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;