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.

Reply via email to