That is a super useful feature. I hope it's not too complex to be merged into mainline Pound. Being able to load a new configuration on the fly would be awesome.
On 10/27/2014 11:40 AM, Lubomir Rintel wrote: > 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. > -- To unsubscribe send an email with subject unsubscribe to [email protected]. Please contact [email protected] for questions.
