On Mon, 2014-10-27 at 13:34 +0100, Emilio Campos wrote: > Great patch, I'm interested in trying it. Pound version for applying it?
2.7d > 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. > > > > > -- To unsubscribe send an email with subject unsubscribe to [email protected]. Please contact [email protected] for questions.
