[Pound Mailing List] [PATCH 5/5] Allow to reload configuration on SIGHUP/SIGINT without service outage
Lubomir Rintel <[email protected]>
| Newsgroups | gmane.comp.web.pound.general |
|---|---|
| Message-ID | <[email protected]> |
From: Miroslav Spousta <miroslav.spousta-Vz9dX3IBr95Wk0Htik3J/[email protected]> When SIGHUP/SIGINT is received, signal old child to shut down, reload configuration and fork a new child while reusing opened listeners (if possible). Configuration reload only works when pound is configured with --enable-super option. Supervisor also keeps track of all running children and kill them when signaled with SIGTERM/SIGQUIT. --- config.c | 17 +- pound.8 | 9 + pound.c | 586 ++++++++++++++++++++++++++++++++++++--------------------------- pound.h | 31 ++++ svc.c | 139 +++++++++++++++ 5 files changed, 520 insertions(+), 262 deletions(-) mode change 100644 => 100755 svc.c diff --git a/config.c b/config.c index 30037c9..cb972a8 100755 --- a/config.c +++ b/config.c @@ -734,10 +734,10 @@ parse_HTTP(void) memset(res, 0, sizeof(LISTENER)); res->to = clnt_to; res->rewr_loc = 1; - res->err414 = "Request URI is too long"; - res->err500 = "An internal server error occurred. Please try again later."; - res->err501 = "This method may not be used."; - res->err503 = "The service is not available. Please try again later."; + res->err414 = strdup("Request URI is too long"); + res->err500 = strdup("An internal server error occurred. Please try again later."); + res->err501 = strdup("This method may not be used."); + res->err503 = strdup("The service is not available. Please try again later."); res->log_level = log_level; if(regcomp(&res->verb, xhttp[0], REG_ICASE | REG_NEWLINE | REG_EXTENDED)) conf_err("xHTTP bad default pattern - aborted"); @@ -937,10 +937,10 @@ parse_HTTPS(void) res->to = clnt_to; res->rewr_loc = 1; - res->err414 = "Request URI is too long"; - res->err500 = "An internal server error occurred. Please try again later."; - res->err501 = "This method may not be used."; - res->err503 = "The service is not available. Please try again later."; + res->err414 = strdup("Request URI is too long"); + res->err500 = strdup("An internal server error occurred. Please try again later."); + res->err501 = strdup("This method may not be used."); + res->err503 = strdup("The service is not available. Please try again later."); res->allow_client_reneg = 0; res->log_level = log_level; if(regcomp(&res->verb, xhttp[0], REG_ICASE | REG_NEWLINE | REG_EXTENDED)) @@ -1464,6 +1464,7 @@ config_parse(const int argc, char **const argv) exit(1); } + optind = 1; opterr = 0; check_only = 0; conf_name = F_CONF; diff --git a/pound.8 b/pound.8 index b665ebe..afffd2e 100755 --- a/pound.8 +++ b/pound.8 @@ -945,6 +945,15 @@ server is re-opened as necessary. attempts to resolve the names of the hosts that appear in various requests and/or responses. That means it need a functioning resolver of some kind (be it /etc/hosts, DNS or something else). +.PP +When +.B Pound +is compiled to work in supervised mode (default), it supports configuration +reload without service outage. When SIGHUP/SIGINT is delivered to the +supervisor process, new worker child process is created while keeping old child +for servicing current connections. Listening socket is then passed to the new +child. SIGKILL/SIGQUIT terminates supervisor and all worker processes. + .SH EXAMPLES To translate HTTPS requests to a local HTTP server (assuming your network address is 123.123.123.123): diff --git a/pound.c b/pound.c index 09c5f16..1de7013 100755 --- a/pound.c +++ b/pound.c @@ -47,6 +47,9 @@ int alive_to, /* check interval for resurrection */ SERVICE *services; /* global services (if any) */ LISTENER *listeners; /* all available listeners */ +LISTENER *prev_listeners; /* saved listeners */ + +PID *children; /* pid of workers */ regex_t HEADER, /* Allowed header */ CHUNK_HEAD, /* chunk header line */ @@ -193,34 +196,31 @@ get_thr_qlen(void) static RETSIGTYPE h_term(const int sig) { - logmsg(LOG_NOTICE, "received signal %d - exiting...", sig); if(son > 0) - kill(son, sig); - if(ctrl_name != NULL) - (void)unlink(ctrl_name); + signal_all(children, sig); + else + if(ctrl_name != NULL) + (void)unlink(ctrl_name); exit(0); } /* - * handle SIGHUP/SIGINT - exit after grace period + * handle SIGHUP/SIGINT - shut down worker (and spawn new one, if possible) */ static RETSIGTYPE h_shut(const int sig) { - int status; - LISTENER *lstn; - - logmsg(LOG_NOTICE, "received signal %d - shutting down...", sig); if(son > 0) { - for(lstn = listeners; lstn; lstn = lstn->next) - close(lstn->sock); kill(son, sig); - (void)wait(&status); - if(ctrl_name != NULL) - (void)unlink(ctrl_name); - exit(0); - } else - shut_down = 1; + son = 0; + } + shut_down = 1; +} + +static RETSIGTYPE +h_child(const int sig) +{ + /* just wake-up from sigsuspend() */ } /* @@ -236,6 +236,7 @@ main(const int argc, char **argv) int n_listeners, i, clnt_length, clnt; struct pollfd *polls; LISTENER *lstn; + LISTENER *prev_lstn; pthread_t thr; pthread_attr_t attr; struct sched_param sp; @@ -247,11 +248,11 @@ main(const int argc, char **argv) #ifndef SOL_TCP struct protoent *pe; #endif + int daemon; - print_log = 0; + polls = NULL; + daemon = 0; (void)umask(077); - control_sock = -1; - log_facility = -1; logmsg(LOG_NOTICE, "starting..."); signal(SIGHUP, h_shut); @@ -259,6 +260,7 @@ main(const int argc, char **argv) signal(SIGTERM, h_term); signal(SIGQUIT, h_term); signal(SIGPIPE, SIG_IGN); + signal(SIGCHLD, h_child); srandom(getpid()); @@ -310,274 +312,350 @@ main(const int argc, char **argv) SOL_TCP = pe->p_proto; #endif - /* read config */ - config_parse(argc, argv); - - if(log_facility != -1) - openlog("pound", LOG_CONS | LOG_NDELAY, LOG_DAEMON); - if(ctrl_name != NULL) { - struct sockaddr_un ctrl; - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.sun_family = AF_UNIX; - strncpy(ctrl.sun_path, ctrl_name, sizeof(ctrl.sun_path) - 1); - (void)unlink(ctrl.sun_path); - if((control_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - logmsg(LOG_ERR, "Control \"%s\" create: %s", ctrl.sun_path, strerror(errno)); - exit(1); - } - if(bind(control_sock, (struct sockaddr *)&ctrl, (socklen_t)sizeof(ctrl)) < 0) { - logmsg(LOG_ERR, "Control \"%s\" bind: %s", ctrl.sun_path, strerror(errno)); - exit(1); + for(;;) { + /* free previous values and re-initialize */ + free(user); + free(group); + free(root_jail); + free(ctrl_name); + + print_log = 0; + control_sock = -1; + log_facility = -1; + + /* preserve listeners */ + prev_listeners = listeners; + listeners = NULL; + + /* read config */ + config_parse(argc, argv); + if(shut_down) + print_log = 0; + + if(log_facility != -1) + openlog("pound", LOG_CONS | LOG_NDELAY, LOG_DAEMON); + else + closelog(); + + if(ctrl_name != NULL) { + struct sockaddr_un ctrl; + + if(control_sock >= 0) + close(control_sock); + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.sun_family = AF_UNIX; + strncpy(ctrl.sun_path, ctrl_name, sizeof(ctrl.sun_path) - 1); + (void)unlink(ctrl.sun_path); + if((control_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + logmsg(LOG_ERR, "Control \"%s\" create: %s", ctrl.sun_path, strerror(errno)); + exit(1); + } + if(bind(control_sock, (struct sockaddr *)&ctrl, (socklen_t)sizeof(ctrl)) < 0) { + logmsg(LOG_ERR, "Control \"%s\" bind: %s", ctrl.sun_path, strerror(errno)); + exit(1); + } + listen(control_sock, 512); } - listen(control_sock, 512); - } - - /* open listeners */ - for(lstn = listeners, n_listeners = 0; lstn; lstn = lstn->next, n_listeners++) { - int opt; - - /* prepare the socket */ - if((lstn->sock = socket(lstn->addr.ai_family == AF_INET? PF_INET: PF_INET6, SOCK_STREAM, 0)) < 0) { - addr2str(tmp, MAXBUF - 1, &lstn->addr, 0); - logmsg(LOG_ERR, "HTTP socket %s create: %s - aborted", tmp, strerror(errno)); - exit(1); + + /* open listeners */ + for(lstn = listeners, n_listeners = 0; lstn; lstn = lstn->next, n_listeners++) { + int opt; + + /* try to re-use listener socket */ + for(prev_lstn = prev_listeners; prev_lstn; prev_lstn = prev_lstn->next) { + if(prev_lstn->sock >= 0 && !addrinfo_cmp(&prev_lstn->addr, &lstn->addr)) + break; + } + if(prev_lstn && prev_lstn->sock >= 0) { + char addr[MAXBUF]; + /* reuse listener socket */ + lstn->sock = prev_lstn->sock; + prev_lstn->sock = -1; + addr2str(addr, sizeof(addr), &prev_lstn->addr, 0); + logmsg(LOG_INFO, "reusing listener socket for %s", addr); + } else { + /* prepare the socket */ + if((lstn->sock = socket(lstn->addr.ai_family == AF_INET? PF_INET: PF_INET6, SOCK_STREAM, 0)) < 0) { + addr2str(tmp, MAXBUF - 1, &lstn->addr, 0); + logmsg(LOG_ERR, "HTTP socket %s create: %s - aborted", tmp, strerror(errno)); + exit(1); + } + opt = 1; + setsockopt(lstn->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)); + if(bind(lstn->sock, lstn->addr.ai_addr, (socklen_t)lstn->addr.ai_addrlen) < 0) { + addr2str(tmp, MAXBUF - 1, &lstn->addr, 0); + logmsg(LOG_ERR, "HTTP socket bind %s: %s - aborted", tmp, strerror(errno)); + exit(1); + } + listen(lstn->sock, 512); + } } - opt = 1; - setsockopt(lstn->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)); - if(bind(lstn->sock, lstn->addr.ai_addr, (socklen_t)lstn->addr.ai_addrlen) < 0) { - addr2str(tmp, MAXBUF - 1, &lstn->addr, 0); - logmsg(LOG_ERR, "HTTP socket bind %s: %s - aborted", tmp, strerror(errno)); - exit(1); + /* close remaining old listeners and free structures */ + while(prev_listeners) { + LISTENER *lstn = prev_listeners; + prev_listeners = prev_listeners->next; + if(lstn->sock >= 0) + close(lstn->sock); + free_listener(lstn); } - listen(lstn->sock, 512); - } - - /* alloc the poll structures */ - if((polls = (struct pollfd *)calloc(n_listeners, sizeof(struct pollfd))) == NULL) { - logmsg(LOG_ERR, "Out of memory for poll - aborted"); - exit(1); - } - for(lstn = listeners, i = 0; lstn; lstn = lstn->next, i++) - polls[i].fd = lstn->sock; - - /* set uid if necessary */ - if(user) { - struct passwd *pw; - - if((pw = getpwnam(user)) == NULL) { - logmsg(LOG_ERR, "no such user %s - aborted", user); + + /* alloc the poll structures */ + free(polls); + if((polls = (struct pollfd *)calloc(n_listeners, sizeof(struct pollfd))) == NULL) { + logmsg(LOG_ERR, "Out of memory for poll - aborted"); exit(1); } - user_id = pw->pw_uid; - } - - /* set gid if necessary */ - if(group) { - struct group *gr; - - if((gr = getgrnam(group)) == NULL) { - logmsg(LOG_ERR, "no such group %s - aborted", group); - exit(1); + for(lstn = listeners, i = 0; lstn; lstn = lstn->next, i++) + polls[i].fd = lstn->sock; + + /* set uid if necessary */ + if(user) { + struct passwd *pw; + + if((pw = getpwnam(user)) == NULL) { + logmsg(LOG_ERR, "no such user %s - aborted", user); + exit(1); + } + user_id = pw->pw_uid; } - group_id = gr->gr_gid; - } - - /* Turn off verbose messages (if necessary) */ - print_log = 0; - - if(daemonize) { - /* daemonize - make ourselves a subprocess. */ - switch (fork()) { - case 0: - if(log_facility != -1) { - close(0); - close(1); - close(2); - } - break; - case -1: - logmsg(LOG_ERR, "fork: %s - aborted", strerror(errno)); + + /* set gid if necessary */ + if(group) { + struct group *gr; + + if((gr = getgrnam(group)) == NULL) { + logmsg(LOG_ERR, "no such group %s - aborted", group); exit(1); - default: - exit(0); + } + group_id = gr->gr_gid; } + + /* Turn off verbose messages (if necessary) */ + print_log = 0; + + if(!daemon && daemonize) { + /* daemonize - make ourselves a subprocess. */ + switch (fork()) { + case 0: + if(log_facility != -1) { + close(0); + close(1); + close(2); + } + break; + case -1: + logmsg(LOG_ERR, "fork: %s - aborted", strerror(errno)); + exit(1); + default: + exit(0); + } + daemon = 1; #ifdef HAVE_SETSID - (void) setsid(); + (void) setsid(); #endif - } - - /* record pid in file */ - if((fpid = fopen(pid_name, "wt")) != NULL) { - fprintf(fpid, "%d\n", getpid()); - fclose(fpid); - } else - logmsg(LOG_NOTICE, "Create \"%s\": %s", pid_name, strerror(errno)); - - /* chroot if necessary */ - if(root_jail) { - if(chroot(root_jail)) { - logmsg(LOG_ERR, "chroot: %s - aborted", strerror(errno)); - exit(1); } - if(chdir("/")) { - logmsg(LOG_ERR, "chroot/chdir: %s - aborted", strerror(errno)); - exit(1); + + /* record pid in file */ + if(!fpid) { + if((fpid = fopen(pid_name, "wt")) != NULL) { + fprintf(fpid, "%d\n", getpid()); + fclose(fpid); + } else + logmsg(LOG_NOTICE, "Create \"%s\": %s", pid_name, strerror(errno)); } - } - if(group) - if(setgid(group_id) || setegid(group_id)) { - logmsg(LOG_ERR, "setgid: %s - aborted", strerror(errno)); - exit(1); - } - if(user) - if(setuid(user_id) || seteuid(user_id)) { - logmsg(LOG_ERR, "setuid: %s - aborted", strerror(errno)); - exit(1); - } + shut_down = 0; - /* split off into monitor and working process if necessary */ - for(;;) { + /* split off into monitor and working process if necessary */ + while(!shut_down) { #ifdef UPER - if((son = fork()) > 0) { - int status; - - (void)wait(&status); - if(WIFEXITED(status)) - logmsg(LOG_ERR, "MONITOR: worker exited normally %d, restarting...", WEXITSTATUS(status)); - else if(WIFSIGNALED(status)) - logmsg(LOG_ERR, "MONITOR: worker exited on signal %d, restarting...", WTERMSIG(status)); - else - logmsg(LOG_ERR, "MONITOR: worker exited (stopped?) %d, restarting...", status); - } else if (son == 0) { + if((son = fork()) > 0) { + sigset_t mask, oldmask; + + insert_pid(&children, son); + + sigemptyset(&mask); + sigaddset(&mask, SIGHUP); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGCHLD); + + sigprocmask(SIG_BLOCK, &mask, &oldmask); + while(!shut_down) { + int status, pid; + + while((pid = waitpid(-1, &status, WNOHANG)) > 0) { + /* we only oversee youngest son, older ones are ignored */ + if(pid == son) { + if(WIFEXITED(status)) + logmsg(LOG_ERR, "MONITOR: worker %d exited normally %d, restarting...", pid, WEXITSTATUS(status)); + else if(WIFSIGNALED(status)) + logmsg(LOG_ERR, "MONITOR: worker %d exited on signal %d, restarting...", pid, WTERMSIG(status)); + else + logmsg(LOG_ERR, "MONITOR: worker %d exited (stopped?) %d, restarting...", pid, status); + } else { + logmsg(LOG_INFO, "worker %d exited", pid); + } + remove_pid(&children, pid); + } + + /* wait for children or SIGHUP/INT */ + sigsuspend(&oldmask); + } + /* SIGHUP/INT: reload configuration */ + sigprocmask(SIG_UNBLOCK, &mask, NULL); + logmsg(LOG_NOTICE, "config reload..."); + } else if (son == 0) { #endif + /* chroot if necessary */ + if(root_jail) { + if(chroot(root_jail)) { + logmsg(LOG_ERR, "chroot: %s - aborted", strerror(errno)); + exit(1); + } + if(chdir("/")) { + logmsg(LOG_ERR, "chroot/chdir: %s - aborted", strerror(errno)); + exit(1); + } + } - /* thread stuff */ - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if(group) + if(setgid(group_id) || setegid(group_id)) { + logmsg(LOG_ERR, "setgid: %s - aborted", strerror(errno)); + exit(1); + } + if(user) + if(setuid(user_id) || seteuid(user_id)) { + logmsg(LOG_ERR, "setuid: %s - aborted", strerror(errno)); + exit(1); + } + + /* thread stuff */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #ifdef NEED_STACK - /* set new stack size - necessary for OpenBSD/FreeBSD and Linux NPTL */ - if(pthread_attr_setstacksize(&attr, 1 << 18)) { - logmsg(LOG_ERR, "can't set stack size - aborted"); - exit(1); - } + /* set new stack size - necessary for OpenBSD/FreeBSD and Linux NPTL */ + if(pthread_attr_setstacksize(&attr, 1 << 18)) { + logmsg(LOG_ERR, "can't set stack size - aborted"); + exit(1); + } #endif - /* start timer */ - if(pthread_create(&thr, &attr, thr_timer, NULL)) { - logmsg(LOG_ERR, "create thr_resurect: %s - aborted", strerror(errno)); - exit(1); - } - - /* start the controlling thread (if needed) */ - if(control_sock >= 0 && pthread_create(&thr, &attr, thr_control, NULL)) { - logmsg(LOG_ERR, "create thr_control: %s - aborted", strerror(errno)); - exit(1); - } - - /* pause to make sure the service threads were started */ - sleep(1); + /* start timer */ + if(pthread_create(&thr, &attr, thr_timer, NULL)) { + logmsg(LOG_ERR, "create thr_resurect: %s - aborted", strerror(errno)); + exit(1); + } - /* create the worker threads */ - for(i = 0; i < numthreads; i++) - if(pthread_create(&thr, &attr, thr_http, NULL)) { - logmsg(LOG_ERR, "create thr_http: %s - aborted", strerror(errno)); + /* start the controlling thread (if needed) */ + if(control_sock >= 0 && pthread_create(&thr, &attr, thr_control, NULL)) { + logmsg(LOG_ERR, "create thr_control: %s - aborted", strerror(errno)); exit(1); } - /* pause to make sure at least some of the worker threads were started */ - sleep(1); - - /* and start working */ - for(;;) { - if(shut_down) { - int finished; - - logmsg(LOG_NOTICE, "shutting down (%d)...", getpid()); - for(lstn = listeners; lstn; lstn = lstn->next) - close(lstn->sock); - /* rename control file (append pid) */ - if(ctrl_name != NULL) { - char *ctrl_tmp = malloc(strlen(ctrl_name)+11); - sprintf(ctrl_tmp, "%s.%d", ctrl_name, getpid()); - rename(ctrl_name, ctrl_tmp); - free(ctrl_name); - ctrl_name = ctrl_tmp; + /* pause to make sure the service threads were started */ + sleep(1); + + /* create the worker threads */ + for(i = 0; i < numthreads; i++) + if(pthread_create(&thr, &attr, thr_http, NULL)) { + logmsg(LOG_ERR, "create thr_http: %s - aborted", strerror(errno)); + exit(1); } - /* wait for all threads to be finished */ - finished = 0; - while(!finished) { - int running; - (void)pthread_mutex_lock(&arg_mut); - running = numthreads-waiting; - finished = !first && !running; - (void)pthread_mutex_unlock(&arg_mut); - if(!finished) { - logmsg(LOG_INFO, "%d thread(s) still running...", running); - sleep(RUNNING_CHECK_PERIOD); + + /* pause to make sure at least some of the worker threads were started */ + sleep(1); + + /* and start working */ + for(;;) { + if(shut_down) { + int finished; + + logmsg(LOG_NOTICE, "shutting down (%d)...", getpid()); + for(lstn = listeners; lstn; lstn = lstn->next) + close(lstn->sock); + /* rename control file (append pid) */ + if(ctrl_name != NULL) { + char *ctrl_tmp = malloc(strlen(ctrl_name)+11); + sprintf(ctrl_tmp, "%s.%d", ctrl_name, getpid()); + rename(ctrl_name, ctrl_tmp); + free(ctrl_name); + ctrl_name = ctrl_tmp; } + /* wait for all threads to be finished */ + finished = 0; + while(!finished) { + int running; + (void)pthread_mutex_lock(&arg_mut); + running = numthreads-waiting; + finished = !first && !running; + (void)pthread_mutex_unlock(&arg_mut); + if(!finished) { + logmsg(LOG_INFO, "%d thread(s) still running...", running); + sleep(RUNNING_CHECK_PERIOD); + } + } + logmsg(LOG_NOTICE, "no threads running - exiting..."); + if(ctrl_name != NULL) + (void)unlink(ctrl_name); + exit(0); } - logmsg(LOG_NOTICE, "no threads running - exiting..."); - if(ctrl_name != NULL) - (void)unlink(ctrl_name); - exit(0); - } - for(lstn = listeners, i = 0; i < n_listeners; lstn = lstn->next, i++) { - polls[i].events = POLLIN | POLLPRI; - polls[i].revents = 0; - } - if(poll(polls, n_listeners, -1) < 0) { - logmsg(LOG_WARNING, "poll: %s", strerror(errno)); - } else { - for(lstn = listeners, i = 0; lstn; lstn = lstn->next, i++) { - if(polls[i].revents & (POLLIN | POLLPRI)) { - memset(&clnt_addr, 0, sizeof(clnt_addr)); - clnt_length = sizeof(clnt_addr); - if((clnt = accept(lstn->sock, (struct sockaddr *)&clnt_addr, - (socklen_t *)&clnt_length)) < 0) { - logmsg(LOG_WARNING, "HTTP accept: %s", strerror(errno)); - } else if(((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET - || ((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET6) { - thr_arg arg; - - if(lstn->disabled) { - /* - addr2str(tmp, MAXBUF - 1, &clnt_addr, 1); - logmsg(LOG_WARNING, "HTTP disabled listener from %s", tmp); - */ - close(clnt); - } - arg.sock = clnt; - arg.lstn = lstn; - if((arg.from_host.ai_addr = (struct sockaddr *)malloc(clnt_length)) == NULL) { - logmsg(LOG_WARNING, "HTTP arg address: malloc"); + for(lstn = listeners, i = 0; i < n_listeners; lstn = lstn->next, i++) { + polls[i].events = POLLIN | POLLPRI; + polls[i].revents = 0; + } + if(poll(polls, n_listeners, -1) < 0) { + logmsg(LOG_WARNING, "poll: %s", strerror(errno)); + } else { + for(lstn = listeners, i = 0; lstn; lstn = lstn->next, i++) { + if(polls[i].revents & (POLLIN | POLLPRI)) { + memset(&clnt_addr, 0, sizeof(clnt_addr)); + clnt_length = sizeof(clnt_addr); + if((clnt = accept(lstn->sock, (struct sockaddr *)&clnt_addr, + (socklen_t *)&clnt_length)) < 0) { + logmsg(LOG_WARNING, "HTTP accept: %s", strerror(errno)); + } else if(((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET + || ((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET6) { + thr_arg arg; + + if(lstn->disabled) { + /* + addr2str(tmp, MAXBUF - 1, &clnt_addr, 1); + logmsg(LOG_WARNING, "HTTP disabled listener from %s", tmp); + */ + close(clnt); + } + arg.sock = clnt; + arg.lstn = lstn; + if((arg.from_host.ai_addr = (struct sockaddr *)malloc(clnt_length)) == NULL) { + logmsg(LOG_WARNING, "HTTP arg address: malloc"); + close(clnt); + continue; + } + memcpy(arg.from_host.ai_addr, &clnt_addr, clnt_length); + arg.from_host.ai_addrlen = clnt_length; + if(((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET) + arg.from_host.ai_family = AF_INET; + else + arg.from_host.ai_family = AF_INET6; + if(put_thr_arg(&arg)) + close(clnt); + } else { + /* may happen on FreeBSD, I am told */ + logmsg(LOG_WARNING, "HTTP connection prematurely closed by peer"); close(clnt); - continue; } - memcpy(arg.from_host.ai_addr, &clnt_addr, clnt_length); - arg.from_host.ai_addrlen = clnt_length; - if(((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET) - arg.from_host.ai_family = AF_INET; - else - arg.from_host.ai_family = AF_INET6; - if(put_thr_arg(&arg)) - close(clnt); - } else { - /* may happen on FreeBSD, I am told */ - logmsg(LOG_WARNING, "HTTP connection prematurely closed by peer"); - close(clnt); } } } } - } #ifdef UPER - } else { - /* failed to spawn son */ - logmsg(LOG_ERR, "Can't fork worker (%s) - aborted", strerror(errno)); - exit(1); - } + } else { + /* failed to spawn son */ + logmsg(LOG_ERR, "Can't fork worker (%s) - aborted", strerror(errno)); + exit(1); + } #endif + } } } diff --git a/pound.h b/pound.h index 15ed71c..de5f8b1 100755 --- a/pound.h +++ b/pound.h @@ -416,6 +416,12 @@ typedef struct _listener { extern LISTENER *listeners; /* all available listeners */ #endif /* NO_EXTERNALS */ +/* pid list item definition */ +typedef struct _pid { + pid_t pid; + struct _pid *next; +} PID; + typedef struct _thr_arg { int sock; LISTENER *lstn; @@ -509,6 +515,11 @@ extern int cpURL(char *, char *, int); extern void addr2str(char *, const int, const struct addrinfo *, const int); /* + * Compare two addrinfo strctures, return 0 on match + */ +extern int addrinfo_cmp(const struct addrinfo *a, const struct addrinfo *b); + +/* * Return a string representation for a back-end address */ #define str_be(BUF, LEN, BE) addr2str((BUF), (LEN), &(BE)->addr, 0) @@ -640,3 +651,23 @@ extern void *thr_timer(void *); * listens to client requests and calls the appropriate functions */ extern void *thr_control(void *); + +/* + * free listener structure (and all linked structures) + */ +extern void free_listener(LISTENER *lstn); + +/* + * insert pid into list + */ +void insert_pid(PID **list, pid_t pid); + +/* + * remove pid from the list + */ +void remove_pid(PID **list, pid_t pid); + +/* + * signal all processes in the list + */ +void signal_all(PID *list, int signal); diff --git a/svc.c b/svc.c old mode 100644 new mode 100755 index 0bad4e8..d8f4313 --- a/svc.c +++ b/svc.c @@ -305,6 +305,18 @@ addr2str(char *const res, const int res_len, const struct addrinfo *addr, const } /* + * Compare two addrinfo strctures, return 0 on match + */ +int +addrinfo_cmp(const struct addrinfo *a, const struct addrinfo *b) +{ + return a->ai_flags == b->ai_flags && a->ai_family == b->ai_family + && a->ai_socktype == b->ai_socktype && a->ai_protocol == b->ai_protocol + && a->ai_addrlen == b->ai_addrlen && !memcmp(a->ai_addr, b->ai_addr, a->ai_addrlen) + ? 0 : 1; +} + +/* * Parse a URL, possibly decoding hexadecimal-encoded characters */ int @@ -1838,3 +1850,130 @@ SSLINFO_callback(const SSL *ssl, int where, int rc) *reneg_state = RENEG_REJECT; } } + +/* + * free linked list of matchers + */ +void +free_matchers(MATCHER *matchers) +{ + while (matchers) { + MATCHER *m = matchers; + matchers = matchers->next; + regfree(&m->pat); + free(m); + } +} + +/* + * free linked list of backends + */ +void +free_backends(BACKEND *backends) { + while (backends) { + BACKEND *be = backends; + backends = backends->next; + free(be->url); + SSL_CTX_free(be->ctx); + pthread_mutex_destroy(&be->mut); + free(be); + } +} + +/* + * free linked list of services + */ +void +free_services(SERVICE *services) +{ + while (services) { + SERVICE *svc = services; + services = services->next; + free_matchers(svc->url); + free_matchers(svc->req_head); + free_matchers(svc->deny_head); + free_backends(svc->backends); + free_backends(svc->emergency); + pthread_mutex_destroy(&svc->mut); + regfree(&svc->sess_start); + regfree(&svc->sess_pat); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + LHM_lh_free(TABNODE, svc->sessions); +#else + lh_free(svc->sessions); +#endif + free(svc); + } +} + +/* + * free linked list of pound contexts + */ +void +free_contexts(POUND_CTX *contexts) +{ + while (contexts) { + POUND_CTX *ctx = contexts; + contexts = contexts->next; + free(ctx->server_name); + SSL_CTX_free(ctx->ctx); + free(ctx); + } +} + +/* + * free listener structure (and all linked structures) + */ +void +free_listener(LISTENER *lstn) +{ + free_contexts(lstn->ctx); + free(lstn->add_head); + regfree(&lstn->verb); + regfree(&lstn->url_pat); + free(lstn->err414); + free(lstn->err500); + free(lstn->err501); + free(lstn->err503); + free_matchers(lstn->head_off); + free_services(lstn->services); + free(lstn); +} + +/* + * insert pid into list + */ +void insert_pid(PID **list, pid_t pid) { + PID *item = (PID*)malloc(sizeof(PID)); + item->pid = pid; + item->next = *list; + *list = item; +} + +/* + * remove pid from the list + */ +void remove_pid(PID **list, pid_t pid) { + PID *prev = NULL, *cur = *list; + while (cur) { + if (cur->pid == pid) { + if (prev) + prev->next = cur->next; + else + *list = cur->next; + free(cur); + } + prev = cur; + cur = cur->next; + } +} + +/* + * signal all processes in the list + */ +void signal_all(PID *list, int signal) { + while (list) { + kill(list->pid, signal); + list = list->next; + } +} -- 1.9.3 -- To unsubscribe send an email with subject unsubscribe to [email protected] Please contact [email protected] for questions.