MAJOR: listeners: use dual-linked lists to chain listeners with frontends

Navigating through listeners was very inconvenient and error-prone. Not to
mention that listeners were linked in reverse order and reverted afterwards.
In order to definitely get rid of these issues, we now do the following :
  - frontends have a dual-linked list of bind_conf
  - frontends have a dual-linked list of listeners
  - bind_conf have a dual-linked list of listeners
  - listeners have a pointer to their bind_conf

This way we can now navigate from anywhere to anywhere and always find the
proper bind_conf for a given listener, as well as find the list of listeners
for a current bind_conf.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 79e4d0d..c197245 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1701,55 +1701,41 @@
 
 #ifdef CONFIG_HAP_LINUX_TPROXY
 /* parse the "transparent" bind keyword */
-static int bind_parse_transparent(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_transparent(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 
-	if (px->listen->addr.ss_family != AF_INET && px->listen->addr.ss_family != AF_INET6) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on IPv4 and IPv6 sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_INET || l->addr.ss_family == AF_INET6)
+			l->options |= LI_O_FOREIGN;
 	}
 
-	for (l = px->listen; l != last; l = l->next)
-		l->options |= LI_O_FOREIGN;
-
 	return 0;
 }
 #endif
 
 #ifdef TCP_DEFER_ACCEPT
 /* parse the "defer-accept" bind keyword */
-static int bind_parse_defer_accept(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_defer_accept(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 
-	if (px->listen->addr.ss_family != AF_INET && px->listen->addr.ss_family != AF_INET6) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on IPv4 and IPv6 sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_INET || l->addr.ss_family == AF_INET6)
+			l->options |= LI_O_DEF_ACCEPT;
 	}
 
-	for (l = px->listen; l != last; l = l->next)
-		l->options |= LI_O_DEF_ACCEPT;
-
 	return 0;
 }
 #endif
 
 #ifdef TCP_MAXSEG
 /* parse the "mss" bind keyword */
-static int bind_parse_mss(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_mss(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 	int mss;
 
-	if (px->listen->addr.ss_family != AF_INET && px->listen->addr.ss_family != AF_INET6) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on IPv4 and IPv6 sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing MSS value", args[cur_arg]);
@@ -1763,8 +1749,10 @@
 		return ERR_ALERT | ERR_FATAL;
 	}
 
-	for (l = px->listen; l != last; l = l->next)
-		l->maxseg = mss;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_INET || l->addr.ss_family == AF_INET6)
+			l->maxseg = mss;
+	}
 
 	return 0;
 }
@@ -1772,24 +1760,20 @@
 
 #ifdef SO_BINDTODEVICE
 /* parse the "mss" bind keyword */
-static int bind_parse_interface(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_interface(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 
-	if (px->listen->addr.ss_family != AF_INET && px->listen->addr.ss_family != AF_INET6) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on IPv4 and IPv6 sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing interface name", args[cur_arg]);
 		return ERR_ALERT | ERR_FATAL;
 	}
 
-	for (l = px->listen; l != last; l = l->next)
-		l->interface = strdup(args[cur_arg + 1]);
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_INET || l->addr.ss_family == AF_INET6)
+			l->interface = strdup(args[cur_arg + 1]);
+	}
 
 	global.last_checks |= LSTCHK_NETADM;
 	return 0;