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.

Reply via email to