Great patch, I'm interested in trying it. Pound version for applying it? Regards
2014-10-24 16:32 GMT+02:00 Lubomir Rintel <[email protected]>: > From: Miroslav Spousta <[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. > -- Load balancer distribution - Open Source Project http://www.zenloadbalancer.com Distribution list (subscribe): [email protected]
