Re: [Pound Mailing List] [PATCH 5/5] Allow to reload configuration on SIGHUP/SIGINT without service outage

Emilio Campos <[email protected]>
Newsgroups gmane.comp.web.pound.general
Message-ID <[email protected]>
Great patch, I'm interested in trying it.  Pound  version for applying it?

Regards

2014-10-24 16:32 GMT+02:00 Lubomir Rintel <[email protected]>:

> From: Miroslav Spousta <miroslav.spousta-Vz9dX3IBr95Wk0Htik3J/[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.
>



-- 
Load balancer distribution - Open Source Project
http://www.zenloadbalancer.com
Distribution list (subscribe): zenloadbalancer-support-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.