diff --git a/include/proto/listener.h b/include/proto/listener.h index 2758a3c7f..a33aeed4a 100644 --- a/include/proto/listener.h +++ b/include/proto/listener.h @@ -83,11 +83,13 @@ int unbind_all_listeners(struct protocol *proto); * range to , and possibly attached to fd (or -1 for auto * allocation). The address family is taken from ss->ss_family. The number of * jobs and listeners is automatically increased by the number of listeners - * created. It returns non-zero on success, zero on error with the error message + * created. If the argument is set to 1, it specifies that the FD + * was obtained from a parent process. + * It returns non-zero on success, zero on error with the error message * set in . */ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss, - int portl, int porth, int fd, char **err); + int portl, int porth, int fd, int inherited, char **err); /* Delete a listener from its protocol's list of listeners. The listener's * state is automatically updated from LI_ASSIGNED to LI_INIT. The protocol's diff --git a/include/types/listener.h b/include/types/listener.h index 545f88c45..b92c35e2d 100644 --- a/include/types/listener.h +++ b/include/types/listener.h @@ -98,6 +98,7 @@ enum li_state { #define LI_O_V6ONLY 0x0400 /* bind to IPv6 only on Linux >= 2.4.21 */ #define LI_O_V4V6 0x0800 /* bind to IPv4/IPv6 on Linux >= 2.4.21 */ #define LI_O_ACC_CIP 0x1000 /* find the proxied address in the NetScaler Client IP header */ +#define LI_O_INHERITED 0x2000 /* inherited FD from the parent process (fd@) */ /* Note: if a listener uses LI_O_UNLIMITED, it is highly recommended that it adds its own * maxconn setting to the global.maxsock value so that its resources are reserved. diff --git a/src/cfgparse.c b/src/cfgparse.c index b42dd5404..57f25fac7 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -239,6 +239,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, next = dupstr = strdup(str); while (next && *next) { + int inherited = 0; struct sockaddr_storage *ss2; int fd = -1; @@ -277,6 +278,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, } else if (ss2->ss_family == AF_UNSPEC) { socklen_t addr_len; + inherited = 1; /* We want to attach to an already bound fd whose number * is in the addr part of ss2 when cast to sockaddr_in. @@ -295,7 +297,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, } /* OK the address looks correct */ - if (!create_listeners(bind_conf, ss2, port, end, fd, err)) { + if (!create_listeners(bind_conf, ss2, port, end, fd, inherited, err)) { memprintf(err, "%s for address '%s'.\n", *err, str); goto fail; } diff --git a/src/haproxy.c b/src/haproxy.c index 00cc25b16..5b45dfbaf 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -540,6 +540,33 @@ static void mworker_kill(int sig) } } +/* + * Upon a reload, the master worker needs to close all listeners FDs but the mworker_pipe + * fd, and the FD provided by fd@ + */ +static void mworker_cleanlisteners() +{ + struct listener *l, *l_next; + struct proxy *curproxy; + + for (curproxy = proxy; curproxy; curproxy = curproxy->next) { + + list_for_each_entry_safe(l, l_next, &curproxy->conf.listeners, by_fe) { + /* does not close if the FD is inherited with fd@ + * from the parent process */ + if (!(l->options & LI_O_INHERITED)) { + close(l->fd); + LIST_DEL(&l->by_fe); + LIST_DEL(&l->by_bind); + free(l->name); + free(l->counters); + free(l); + } + } + } +} + + /* * remove a pid forom the olpid array and decrease nb_oldpids * return 1 pid was found otherwise return 0 @@ -2694,7 +2721,8 @@ int main(int argc, char **argv) if (proc == global.nbproc) { if (global.mode & MODE_MWORKER) { - protocol_unbind_all(); + mworker_cleanlisteners(); + deinit_pollers(); mworker_wait(); /* should never get there */ exit(EXIT_FAILURE); diff --git a/src/listener.c b/src/listener.c index c7db79a89..7cb4d6aa2 100644 --- a/src/listener.c +++ b/src/listener.c @@ -372,11 +372,13 @@ int unbind_all_listeners(struct protocol *proto) * range to , and possibly attached to fd (or -1 for auto * allocation). The address family is taken from ss->ss_family. The number of * jobs and listeners is automatically increased by the number of listeners - * created. It returns non-zero on success, zero on error with the error message + * created. If the argument is set to 1, it specifies that the FD + * was obtained from a parent process. + * It returns non-zero on success, zero on error with the error message * set in . */ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss, - int portl, int porth, int fd, char **err) + int portl, int porth, int fd, int inherited, char **err) { struct protocol *proto = protocol_by_family(ss->ss_family); struct listener *l; @@ -404,6 +406,9 @@ int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss, proto->add(l, port); + if (inherited) + l->options |= LI_O_INHERITED; + HA_SPIN_INIT(&l->lock); HA_ATOMIC_ADD(&jobs, 1); HA_ATOMIC_ADD(&listeners, 1);