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_uxst.c b/src/proto_uxst.c
index 5f56ad5..58fd06d 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -349,17 +349,11 @@
 }
 
 /* parse the "mode" bind keyword */
-static int bind_parse_mode(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_mode(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 	int val;
 
-	if (px->listen->addr.ss_family != AF_UNIX) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on unix sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing mode (octal integer expected)", args[cur_arg]);
@@ -368,24 +362,20 @@
 
 	val = strtol(args[cur_arg + 1], NULL, 8);
 
-	for (l = px->listen; l != last; l = l->next)
-		l->perm.ux.mode = val;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_UNIX)
+			l->perm.ux.mode = val;
+	}
 
 	return 0;
 }
 
 /* parse the "gid" bind keyword */
-static int bind_parse_gid(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_gid(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 	int val;
 
-	if (px->listen->addr.ss_family != AF_UNIX) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on unix sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing value", args[cur_arg]);
@@ -393,24 +383,20 @@
 	}
 
 	val = atol(args[cur_arg + 1]);
-	for (l = px->listen; l != last; l = l->next)
-		l->perm.ux.gid = val;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_UNIX)
+			l->perm.ux.gid = val;
+	}
 
 	return 0;
 }
 
 /* parse the "group" bind keyword */
-static int bind_parse_group(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_group(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 	struct group *group;
 
-	if (px->listen->addr.ss_family != AF_UNIX) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on unix sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing group name", args[cur_arg]);
@@ -424,24 +410,20 @@
 		return ERR_ALERT | ERR_FATAL;
 	}
 
-	for (l = px->listen; l != last; l = l->next)
-		l->perm.ux.gid = group->gr_gid;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_UNIX)
+			l->perm.ux.gid = group->gr_gid;
+	}
 
 	return 0;
 }
 
 /* parse the "uid" bind keyword */
-static int bind_parse_uid(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_uid(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 	int val;
 
-	if (px->listen->addr.ss_family != AF_UNIX) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on unix sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing value", args[cur_arg]);
@@ -449,24 +431,20 @@
 	}
 
 	val = atol(args[cur_arg + 1]);
-	for (l = px->listen; l != last; l = l->next)
-		l->perm.ux.uid = val;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_UNIX)
+			l->perm.ux.uid = val;
+	}
 
 	return 0;
 }
 
 /* parse the "user" bind keyword */
-static int bind_parse_user(char **args, int cur_arg, struct proxy *px, struct listener *last, char **err)
+static int bind_parse_user(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	struct listener *l;
 	struct passwd *user;
 
-	if (px->listen->addr.ss_family != AF_UNIX) {
-		if (err)
-			memprintf(err, "'%s' option is only supported on unix sockets", args[cur_arg]);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
 	if (!*args[cur_arg + 1]) {
 		if (err)
 			memprintf(err, "'%s' : missing user name", args[cur_arg]);
@@ -480,8 +458,10 @@
 		return ERR_ALERT | ERR_FATAL;
 	}
 
-	for (l = px->listen; l != last; l = l->next)
-		l->perm.ux.uid = user->pw_uid;
+	list_for_each_entry(l, &conf->listeners, by_bind) {
+		if (l->addr.ss_family == AF_UNIX)
+			l->perm.ux.uid = user->pw_uid;
+	}
 
 	return 0;
 }