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.