MINOR: connection: implement alpn registration of muxes

Selecting a mux based on ALPN and the proxy mode will quickly become a
pain. This commit provides new functions to register/lookup a mux based
on the ALPN string and the proxy mode to make this easier. Given that
we're not supposed to support a wide range of muxes, the lookup should
not have any measurable performance impact.
diff --git a/include/proto/connection.h b/include/proto/connection.h
index 72f793a..fbb3790 100644
--- a/include/proto/connection.h
+++ b/include/proto/connection.h
@@ -23,6 +23,7 @@
 #define _PROTO_CONNECTION_H
 
 #include <common/config.h>
+#include <common/ist.h>
 #include <common/memory.h>
 #include <types/connection.h>
 #include <types/listener.h>
@@ -31,6 +32,7 @@
 
 extern struct pool_head *pool2_connection;
 extern struct xprt_ops *registered_xprt[XPRT_ENTRIES];
+extern struct alpn_mux_list alpn_mux_list;
 
 /* perform minimal intializations, report 0 in case of error, 1 if OK. */
 int init_connection();
@@ -702,6 +704,72 @@
 	return conn->xprt->get_alpn(conn, str, len);
 }
 
+/* registers alpn mux list <list>. Modifies the list element! */
+static inline void alpn_register_mux(struct alpn_mux_list *list)
+{
+	LIST_ADDQ(&alpn_mux_list.list, &list->list);
+}
+
+/* unregisters alpn mux list <list> */
+static inline void alpn_unregister_mux(struct alpn_mux_list *list)
+{
+	LIST_DEL(&list->list);
+	LIST_INIT(&list->list);
+}
+
+/* returns the first mux in the list matching the exact same token and
+ * compatible with the proxy's mode (http or tcp). Mode "health" has to be
+ * considered as TCP here. Ie passing "px->mode == PR_MODE_HTTP" is fine. Will
+ * fall back to the first compatible mux with empty ALPN name. May return null
+ * if the code improperly registered the default mux to use as a fallback.
+ */
+static inline const struct mux_ops *alpn_get_mux(const struct ist token, int http_mode)
+{
+	struct alpn_mux_list *item;
+	const struct mux_ops *fallback = NULL;
+
+	http_mode = 1 << !!http_mode;
+
+	list_for_each_entry(item, &alpn_mux_list.list, list) {
+		if (!(item->mode & http_mode))
+			continue;
+		if (isteq(token, item->token))
+			return item->mux;
+		if (!istlen(item->token))
+			fallback = item->mux;
+	}
+	return fallback;
+}
+
+/* finds the best mux for incoming connection <conn> and mode <http_mode> for
+ * the proxy. Null cannot be returned unless there's a serious bug somewhere
+ * else (no fallback mux registered).
+ */
+static inline const struct mux_ops *conn_find_best_mux(struct connection *conn, int http_mode)
+{
+	const char *alpn_str;
+	int alpn_len;
+
+	if (!conn_get_alpn(conn, &alpn_str, &alpn_len))
+		alpn_len = 0;
+
+	return alpn_get_mux(ist2(alpn_str, alpn_len), http_mode);
+}
+
+/* finds the best mux for incoming connection <conn>, a proxy in and http mode
+ * <mode>, and installs it on the connection for direction <dir> (MUX_INBOUND/
+ * MUX_OUTBOUND). Returns < 0 on error.
+ */
+static inline int conn_install_best_mux(struct connection *conn, int mode, enum mux_dir dir)
+{
+	const struct mux_ops *mux_ops;
+
+	mux_ops = conn_find_best_mux(conn, mode);
+	if (!mux_ops)
+		return -1;
+	return conn_install_mux(conn, mux_ops, dir);
+}
+
 #endif /* _PROTO_CONNECTION_H */
 
 /*
diff --git a/include/types/connection.h b/include/types/connection.h
index f720601..b925f65 100644
--- a/include/types/connection.h
+++ b/include/types/connection.h
@@ -26,6 +26,7 @@
 #include <sys/socket.h>
 
 #include <common/config.h>
+#include <common/ist.h>
 
 #include <types/listener.h>
 #include <types/obj_type.h>
@@ -331,6 +332,21 @@
 	} addr; /* addresses of the remote side, client for producer and server for consumer */
 };
 
+/* ALPN token registration */
+enum alpn_proxy_mode {
+	ALPN_MODE_NONE = 0,
+	ALPN_MODE_TCP  = 1 << 0, // must not be changed!
+	ALPN_MODE_HTTP = 1 << 1, // must not be changed!
+	ALPN_MODE_ANY  = ALPN_MODE_TCP | ALPN_MODE_HTTP,
+};
+
+struct alpn_mux_list {
+	const struct ist token;    /* token name and length. Empty is catch-all */
+	enum alpn_proxy_mode mode;
+	const struct mux_ops *mux;
+	struct list list;
+};
+
 /* proxy protocol v2 definitions */
 #define PP2_SIGNATURE        "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
 #define PP2_SIGNATURE_LEN    12
diff --git a/src/connection.c b/src/connection.c
index 129c741..43ec328 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -30,6 +30,11 @@
 struct pool_head *pool2_connection;
 struct xprt_ops *registered_xprt[XPRT_ENTRIES] = { NULL, };
 
+/* List head of all known muxes for ALPN */
+struct alpn_mux_list alpn_mux_list = {
+        .list = LIST_HEAD_INIT(alpn_mux_list.list)
+};
+
 /* perform minimal intializations, report 0 in case of error, 1 if OK. */
 int init_connection()
 {