/* * This is the main (per child) loop. */ static void child_main (struct child_s *ptr) { on_exit(asdf); int connfd; struct sockaddr *cliaddr; socklen_t clilen; cliaddr = (struct sockaddr *) safemalloc (addrlen); if (!cliaddr) { log_message (LOG_CRIT, "Could not allocate memory for child address."); exit (0); } ptr->connects = 0; srand(time(NULL)); while (!config.quit) { ptr->status = T_WAITING; clilen = addrlen; connfd = accept (listenfd, cliaddr, &clilen); #ifndef NDEBUG /* * Enable the TINYPROXY_DEBUG environment variable if you * want to use the GDB debugger. */ if (getenv ("TINYPROXY_DEBUG")) { /* Pause for 10 seconds to allow us to connect debugger */ fprintf (stderr, "Process has accepted connection: %ld\n", (long int) ptr->tid); sleep (10); fprintf (stderr, "Continuing process: %ld\n", (long int) ptr->tid); } #endif /* * Make sure no error occurred... */ if (connfd < 0) { log_message (LOG_ERR, "Accept returned an error (%s) ... retrying.", strerror (errno)); continue; } ptr->status = T_CONNECTED; SERVER_DEC (); handle_connection (connfd); ptr->connects++; if (child_config.maxrequestsperchild != 0) { DEBUG2 ("%u connections so far...", ptr->connects); if (ptr->connects == child_config.maxrequestsperchild) { log_message (LOG_NOTICE, "Child has reached MaxRequestsPerChild (%u). " "Killing child.", ptr->connects); break; } } SERVER_COUNT_LOCK (); if (*servers_waiting > child_config.maxspareservers) { /* * There are too many spare children, kill ourself * off. */ log_message (LOG_NOTICE, "Waiting servers (%d) exceeds MaxSpareServers (%d). " "Killing child.", *servers_waiting, child_config.maxspareservers); SERVER_COUNT_UNLOCK (); break; } else { SERVER_COUNT_UNLOCK (); } SERVER_INC (); } ptr->status = T_EMPTY; safefree (cliaddr); exit (0); }
/* * Keep the proper number of servers running. This is the birth of the * servers. It monitors this at least once a second. */ void child_main_loop (void) { unsigned int i; while (1) { if (config.quit) return; /* If there are not enough spare servers, create more */ SERVER_COUNT_LOCK (); if (*servers_waiting < child_config.minspareservers) { log_message (LOG_NOTICE, "Waiting servers (%d) is less than MinSpareServers (%d). " "Creating new child.", *servers_waiting, child_config.minspareservers); SERVER_COUNT_UNLOCK (); for (i = 0; i != child_config.maxclients; i++) { if (child_ptr[i].status == T_EMPTY) { child_ptr[i].status = T_WAITING; child_ptr[i].tid = child_make (&child_ptr[i]); if (child_ptr[i].tid < 0) { log_message (LOG_NOTICE, "Could not create child"); child_ptr[i].status = T_EMPTY; break; } SERVER_INC (); break; } } } else { SERVER_COUNT_UNLOCK (); } sleep (5); /* Handle log rotation if it was requested */ if (received_sighup) { /* * Ignore the return value of reload_config for now. * This should actually be handled somehow... */ reload_config (); #ifdef FILTER_ENABLE filter_reload (); #endif /* FILTER_ENABLE */ /* propagate filter reload to all children */ child_kill_children (SIGHUP); received_sighup = FALSE; } } }
/* * This is the main (per child) loop. */ static void child_main (struct child_s *ptr) { int connfd; struct sockaddr *cliaddr; socklen_t clilen; fd_set rfds; int maxfd = 0; ssize_t i; int ret; cliaddr = (struct sockaddr *) safemalloc (sizeof(struct sockaddr_storage)); if (!cliaddr) { log_message (LOG_CRIT, "Could not allocate memory for child address."); exit (0); } ptr->connects = 0; /* * We have to wait for connections on multiple fds, * so use select. */ FD_ZERO(&rfds); for (i = 0; i < vector_length(listen_fds); i++) { int *fd = (int *) vector_getentry(listen_fds, i, NULL); ret = socket_nonblocking(*fd); if (ret != 0) { log_message(LOG_ERR, "Failed to set the listening " "socket %d to non-blocking: %s", fd, strerror(errno)); exit(1); } FD_SET(*fd, &rfds); maxfd = max(maxfd, *fd); } while (!config.quit) { int listenfd = -1; ptr->status = T_WAITING; clilen = sizeof(struct sockaddr_storage); ret = select(maxfd + 1, &rfds, NULL, NULL, NULL); if (ret == -1) { log_message (LOG_ERR, "error calling select: %s", strerror(errno)); exit(1); } else if (ret == 0) { log_message (LOG_WARNING, "Strange: select returned 0 " "but we did not specify a timeout..."); continue; } for (i = 0; i < vector_length(listen_fds); i++) { int *fd = (int *) vector_getentry(listen_fds, i, NULL); if (FD_ISSET(*fd, &rfds)) { /* * only accept the connection on the first * fd that we find readable. - fair? */ listenfd = *fd; break; } } if (listenfd == -1) { log_message(LOG_WARNING, "Strange: None of our listen " "fds was readable after select"); continue; } ret = socket_blocking(listenfd); if (ret != 0) { log_message(LOG_ERR, "Failed to set listening " "socket %d to blocking for accept: %s", listenfd, strerror(errno)); exit(1); } /* * We have a socket that is readable. * Continue handling this connection. */ connfd = accept (listenfd, cliaddr, &clilen); #ifndef NDEBUG /* * Enable the TINYPROXY_DEBUG environment variable if you * want to use the GDB debugger. */ if (getenv ("TINYPROXY_DEBUG")) { /* Pause for 10 seconds to allow us to connect debugger */ fprintf (stderr, "Process has accepted connection: %ld\n", (long int) ptr->tid); sleep (10); fprintf (stderr, "Continuing process: %ld\n", (long int) ptr->tid); } #endif /* * Make sure no error occurred... */ if (connfd < 0) { log_message (LOG_ERR, "Accept returned an error (%s) ... retrying.", strerror (errno)); continue; } ptr->status = T_CONNECTED; SERVER_DEC (); handle_connection (connfd); ptr->connects++; if (child_config.maxrequestsperchild != 0) { DEBUG2 ("%u connections so far...", ptr->connects); if (ptr->connects == child_config.maxrequestsperchild) { log_message (LOG_NOTICE, "Child has reached MaxRequestsPerChild (%u). " "Killing child.", ptr->connects); break; } } SERVER_COUNT_LOCK (); if (*servers_waiting > child_config.maxspareservers) { /* * There are too many spare children, kill ourself * off. */ log_message (LOG_NOTICE, "Waiting servers (%d) exceeds MaxSpareServers (%d). " "Killing child.", *servers_waiting, child_config.maxspareservers); SERVER_COUNT_UNLOCK (); break; } else { SERVER_COUNT_UNLOCK (); } SERVER_INC (); } ptr->status = T_EMPTY; safefree (cliaddr); exit (0); }