MINOR: listeners: add clone_listener() to duplicate listeners at boot time

This function's purpose will be to duplicate a listener in INIT state.
This will be used to ease declaration of listeners spanning multiple
groups, which will thus require multiple FDs hence multiple receivers.
diff --git a/include/haproxy/listener.h b/include/haproxy/listener.h
index 5bd60c0..39dce4c 100644
--- a/include/haproxy/listener.h
+++ b/include/haproxy/listener.h
@@ -98,6 +98,7 @@
  */
 int create_listeners(struct bind_conf *bc, const struct sockaddr_storage *ss,
                      int portl, int porth, int fd, struct protocol *proto, char **err);
+struct listener *clone_listener(struct listener *src);
 
 /* 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/src/listener.c b/src/listener.c
index 112455a..044d223 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -663,6 +663,55 @@
 	return 1;
 }
 
+/* clones listener <src> and returns the new one. All dynamically allocated
+ * fields are reallocated (name for now). The new listener is inserted before
+ * the original one in the bind_conf and frontend lists. This allows it to be
+ * duplicated while iterating over the current list. The original listener must
+ * only be in the INIT or ASSIGNED states, and the new listener will only be
+ * placed into the INIT state. The counters are always set to NULL. Maxsock is
+ * updated. Returns NULL on allocation error.
+ */
+struct listener *clone_listener(struct listener *src)
+{
+	struct listener *l;
+
+	l = calloc(1, sizeof(*l));
+	if (!l)
+		goto oom1;
+	memcpy(l, src, sizeof(*l));
+
+	if (l->name) {
+		l->name = strdup(l->name);
+		if (!l->name)
+			goto oom2;
+	}
+
+	l->rx.owner = l;
+	l->state = LI_INIT;
+	l->counters = NULL;
+	l->extra_counters = NULL;
+
+	LIST_APPEND(&src->by_fe,   &l->by_fe);
+	LIST_APPEND(&src->by_bind, &l->by_bind);
+
+	MT_LIST_INIT(&l->wait_queue);
+
+	l->rx.proto->add(l->rx.proto, l);
+
+	HA_SPIN_INIT(&l->lock);
+	_HA_ATOMIC_INC(&jobs);
+	_HA_ATOMIC_INC(&listeners);
+	global.maxsock++;
+	return l;
+
+ oom3:
+	free(l->name);
+ oom2:
+	free(l);
+ oom1:
+	return l;
+}
+
 /* 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
  * number of listeners is updated, as well as the global number of listeners