diff options
Diffstat (limited to 'src/child.c')
-rw-r--r-- | src/child.c | 594 |
1 files changed, 280 insertions, 314 deletions
diff --git a/src/child.c b/src/child.c index bb4110c..9e8d515 100644 --- a/src/child.c +++ b/src/child.c @@ -37,13 +37,11 @@ static socklen_t addrlen; /* * Stores the internal data needed for each child (connection) */ -enum child_status_t -{ T_EMPTY, T_WAITING, T_CONNECTED }; -struct child_s -{ - pid_t tid; - unsigned int connects; - enum child_status_t status; +enum child_status_t { T_EMPTY, T_WAITING, T_CONNECTED }; +struct child_s { + pid_t tid; + unsigned int connects; + enum child_status_t status; }; /* @@ -52,10 +50,9 @@ struct child_s */ static struct child_s *child_ptr; -static struct child_config_s -{ - unsigned int maxclients, maxrequestsperchild; - unsigned int maxspareservers, minspareservers, startservers; +static struct child_config_s { + unsigned int maxclients, maxrequestsperchild; + unsigned int maxspareservers, minspareservers, startservers; } child_config; static unsigned int *servers_waiting; /* servers waiting for a connection */ @@ -76,49 +73,45 @@ static unsigned int *servers_waiting; /* servers waiting for a connection */ static struct flock lock_it, unlock_it; static int lock_fd = -1; -static void -_child_lock_init (void) +static void _child_lock_init (void) { - char lock_file[] = "/tmp/tinyproxy.servers.lock.XXXXXX"; + char lock_file[] = "/tmp/tinyproxy.servers.lock.XXXXXX"; - /* Only allow u+rw bits. This may be required for some versions - * of glibc so that mkstemp() doesn't make us vulnerable. - */ - umask (0177); + /* Only allow u+rw bits. This may be required for some versions + * of glibc so that mkstemp() doesn't make us vulnerable. + */ + umask (0177); - lock_fd = mkstemp (lock_file); - unlink (lock_file); + lock_fd = mkstemp (lock_file); + unlink (lock_file); - lock_it.l_type = F_WRLCK; - lock_it.l_whence = SEEK_SET; - lock_it.l_start = 0; - lock_it.l_len = 0; + lock_it.l_type = F_WRLCK; + lock_it.l_whence = SEEK_SET; + lock_it.l_start = 0; + lock_it.l_len = 0; - unlock_it.l_type = F_UNLCK; - unlock_it.l_whence = SEEK_SET; - unlock_it.l_start = 0; - unlock_it.l_len = 0; + unlock_it.l_type = F_UNLCK; + unlock_it.l_whence = SEEK_SET; + unlock_it.l_start = 0; + unlock_it.l_len = 0; } -static void -_child_lock_wait (void) +static void _child_lock_wait (void) { - int rc; - - while ((rc = fcntl (lock_fd, F_SETLKW, &lock_it)) < 0) - { - if (errno == EINTR) - continue; - else - return; - } + int rc; + + while ((rc = fcntl (lock_fd, F_SETLKW, &lock_it)) < 0) { + if (errno == EINTR) + continue; + else + return; + } } -static void -_child_lock_release (void) +static void _child_lock_release (void) { - if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0) - return; + if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0) + return; } /* END OF LOCKING SECTION */ @@ -141,348 +134,321 @@ _child_lock_release (void) /* * Set the configuration values for the various child related settings. */ -short int -child_configure (child_config_t type, unsigned int val) +short int child_configure (child_config_t type, unsigned int val) { - switch (type) - { - case CHILD_MAXCLIENTS: - child_config.maxclients = val; - break; - case CHILD_MAXSPARESERVERS: - child_config.maxspareservers = val; - break; - case CHILD_MINSPARESERVERS: - child_config.minspareservers = val; - break; - case CHILD_STARTSERVERS: - child_config.startservers = val; - break; - case CHILD_MAXREQUESTSPERCHILD: - child_config.maxrequestsperchild = val; - break; - default: - DEBUG2 ("Invalid type (%d)", type); - return -1; - } - - return 0; + switch (type) { + case CHILD_MAXCLIENTS: + child_config.maxclients = val; + break; + case CHILD_MAXSPARESERVERS: + child_config.maxspareservers = val; + break; + case CHILD_MINSPARESERVERS: + child_config.minspareservers = val; + break; + case CHILD_STARTSERVERS: + child_config.startservers = val; + break; + case CHILD_MAXREQUESTSPERCHILD: + child_config.maxrequestsperchild = val; + break; + default: + DEBUG2 ("Invalid type (%d)", type); + return -1; + } + + return 0; } /* * This is the main (per child) loop. */ -static void -child_main (struct child_s *ptr) +static void child_main (struct child_s *ptr) { - 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); - } + 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; + ptr->connects = 0; - while (!config.quit) - { - ptr->status = T_WAITING; + while (!config.quit) { + ptr->status = T_WAITING; - clilen = addrlen; + clilen = addrlen; - connfd = accept (listenfd, cliaddr, &clilen); + 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); - } + /* + * 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; - } + /* + * 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; + ptr->status = T_CONNECTED; - SERVER_DEC (); + SERVER_DEC (); - handle_connection (connfd); - ptr->connects++; + handle_connection (connfd); + ptr->connects++; - if (child_config.maxrequestsperchild != 0) - { - DEBUG2 ("%u connections so far...", 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; - } - } + 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_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 (); - } + SERVER_INC (); + } - ptr->status = T_EMPTY; + ptr->status = T_EMPTY; - safefree (cliaddr); - exit (0); + safefree (cliaddr); + exit (0); } /* * Fork a child "child" (or in our case a process) and then start up the * child_main() function. */ -static pid_t -child_make (struct child_s *ptr) +static pid_t child_make (struct child_s *ptr) { - pid_t pid; + pid_t pid; - if ((pid = fork ()) > 0) - return pid; /* parent */ + if ((pid = fork ()) > 0) + return pid; /* parent */ - /* - * Reset the SIGNALS so that the child can be reaped. - */ - set_signal_handler (SIGCHLD, SIG_DFL); - set_signal_handler (SIGTERM, SIG_DFL); - set_signal_handler (SIGHUP, SIG_DFL); + /* + * Reset the SIGNALS so that the child can be reaped. + */ + set_signal_handler (SIGCHLD, SIG_DFL); + set_signal_handler (SIGTERM, SIG_DFL); + set_signal_handler (SIGHUP, SIG_DFL); - child_main (ptr); /* never returns */ - return -1; + child_main (ptr); /* never returns */ + return -1; } /* * Create a pool of children to handle incoming connections */ -short int -child_pool_create (void) +short int child_pool_create (void) { - unsigned int i; - - /* - * Make sure the number of MaxClients is not zero, since this - * variable determines the size of the array created for children - * later on. - */ - if (child_config.maxclients == 0) - { - log_message (LOG_ERR, - "child_pool_create: \"MaxClients\" must be " - "greater than zero."); - return -1; - } - if (child_config.startservers == 0) - { - log_message (LOG_ERR, - "child_pool_create: \"StartServers\" must be " - "greater than zero."); - return -1; - } - - child_ptr = (struct child_s *)calloc_shared_memory (child_config.maxclients, - sizeof (struct child_s)); - if (!child_ptr) - { - log_message (LOG_ERR, "Could not allocate memory for children."); - return -1; - } - - servers_waiting = (unsigned int *)malloc_shared_memory (sizeof (unsigned int)); - if (servers_waiting == MAP_FAILED) - { - log_message (LOG_ERR, "Could not allocate memory for child counting."); - return -1; - } - *servers_waiting = 0; - - /* - * Create a "locking" file for use around the servers_waiting - * variable. - */ - _child_lock_init (); - - if (child_config.startservers > child_config.maxclients) - { - log_message (LOG_WARNING, - "Can not start more than \"MaxClients\" servers. " - "Starting %u servers instead.", child_config.maxclients); - child_config.startservers = child_config.maxclients; - } - - for (i = 0; i != child_config.maxclients; i++) - { - child_ptr[i].status = T_EMPTY; - child_ptr[i].connects = 0; - } - - for (i = 0; i != child_config.startservers; i++) - { - DEBUG2 ("Trying to create child %d of %d", i + 1, - child_config.startservers); - child_ptr[i].status = T_WAITING; - child_ptr[i].tid = child_make (&child_ptr[i]); - - if (child_ptr[i].tid < 0) - { - log_message (LOG_WARNING, - "Could not create child number %d of %d", - i, child_config.startservers); - return -1; + unsigned int i; + + /* + * Make sure the number of MaxClients is not zero, since this + * variable determines the size of the array created for children + * later on. + */ + if (child_config.maxclients == 0) { + log_message (LOG_ERR, + "child_pool_create: \"MaxClients\" must be " + "greater than zero."); + return -1; + } + if (child_config.startservers == 0) { + log_message (LOG_ERR, + "child_pool_create: \"StartServers\" must be " + "greater than zero."); + return -1; + } + + child_ptr = + (struct child_s *) calloc_shared_memory (child_config.maxclients, + sizeof (struct child_s)); + if (!child_ptr) { + log_message (LOG_ERR, + "Could not allocate memory for children."); + return -1; } - else - { - log_message (LOG_INFO, - "Creating child number %d of %d ...", - i + 1, child_config.startservers); - SERVER_INC (); + servers_waiting = + (unsigned int *) malloc_shared_memory (sizeof (unsigned int)); + if (servers_waiting == MAP_FAILED) { + log_message (LOG_ERR, + "Could not allocate memory for child counting."); + return -1; + } + *servers_waiting = 0; + + /* + * Create a "locking" file for use around the servers_waiting + * variable. + */ + _child_lock_init (); + + if (child_config.startservers > child_config.maxclients) { + log_message (LOG_WARNING, + "Can not start more than \"MaxClients\" servers. " + "Starting %u servers instead.", + child_config.maxclients); + child_config.startservers = child_config.maxclients; } - } - log_message (LOG_INFO, "Finished creating all children."); + for (i = 0; i != child_config.maxclients; i++) { + child_ptr[i].status = T_EMPTY; + child_ptr[i].connects = 0; + } - return 0; + for (i = 0; i != child_config.startservers; i++) { + DEBUG2 ("Trying to create child %d of %d", i + 1, + child_config.startservers); + child_ptr[i].status = T_WAITING; + child_ptr[i].tid = child_make (&child_ptr[i]); + + if (child_ptr[i].tid < 0) { + log_message (LOG_WARNING, + "Could not create child number %d of %d", + i, child_config.startservers); + return -1; + } else { + log_message (LOG_INFO, + "Creating child number %d of %d ...", + i + 1, child_config.startservers); + + SERVER_INC (); + } + } + + log_message (LOG_INFO, "Finished creating all children."); + + return 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) +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; + 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 (); } - } - } - else - { - SERVER_COUNT_UNLOCK (); - } - sleep (5); + sleep (5); - /* Handle log rotation if it was requested */ - if (received_sighup) - { - truncate_log_file (); + /* Handle log rotation if it was requested */ + if (received_sighup) { + truncate_log_file (); #ifdef FILTER_ENABLE - if (config.filter) - { - filter_destroy (); - filter_init (); - } - log_message (LOG_NOTICE, "Re-reading filter file."); + if (config.filter) { + filter_destroy (); + filter_init (); + } + log_message (LOG_NOTICE, "Re-reading filter file."); #endif /* FILTER_ENABLE */ - received_sighup = FALSE; + received_sighup = FALSE; + } } - } } /* * Go through all the non-empty children and cancel them. */ -void -child_kill_children (void) +void child_kill_children (void) { - unsigned int i; + unsigned int i; - for (i = 0; i != child_config.maxclients; i++) - { - if (child_ptr[i].status != T_EMPTY) - kill (child_ptr[i].tid, SIGTERM); - } + for (i = 0; i != child_config.maxclients; i++) { + if (child_ptr[i].status != T_EMPTY) + kill (child_ptr[i].tid, SIGTERM); + } } -int -child_listening_sock (uint16_t port) +int child_listening_sock (uint16_t port) { - listenfd = listen_sock (port, &addrlen); - return listenfd; + listenfd = listen_sock (port, &addrlen); + return listenfd; } -void -child_close_sock (void) +void child_close_sock (void) { - close (listenfd); + close (listenfd); } |