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 <[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): [email protected]

Reply via email to