BUG/MEDIUM: mworker: does not close inherited FD

At the end of the master initialisation, a call to protocol_unbind_all()
was made, in order to close all the FDs.

Unfortunately, this function closes the inherited FDs (fd@), upon reload
the master wasn't able to reload a configuration with those FDs.

The create_listeners() function now store a flag to specify if the fd
was inherited or not.

Replace the protocol_unbind_all() by  mworker_cleanlisteners() +
deinit_pollers()
diff --git a/src/cfgparse.c b/src/cfgparse.c
index b42dd54..57f25fa 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -239,6 +239,7 @@
 	next = dupstr = strdup(str);
 
 	while (next && *next) {
+		int inherited = 0;
 		struct sockaddr_storage *ss2;
 		int fd = -1;
 
@@ -277,6 +278,7 @@
 		}
 		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 @@
 		}
 
 		/* 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 00cc25b..5b45dfb 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -541,6 +541,33 @@
 }
 
 /*
+ * 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 @@
 
 		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 c7db79a..7cb4d6a 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -372,11 +372,13 @@
  * range <portl> to <porth>, and possibly attached to fd <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 <inherited> 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 <err>.
  */
 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 @@
 
 		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);