From 2386be64ba3f13f767a5ef0af4912d7361198664 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Sep 2017 19:40:52 +0200 Subject: [PATCH] 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. --- include/proto/connection.h | 68 ++++++++++++++++++++++++++++++++++++++ include/types/connection.h | 16 +++++++++ src/connection.c | 5 +++ 3 files changed, 89 insertions(+) diff --git a/include/proto/connection.h b/include/proto/connection.h index 72f793adf..fbb37904d 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -23,6 +23,7 @@ #define _PROTO_CONNECTION_H #include +#include #include #include #include @@ -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 @@ static inline int conn_get_alpn(const struct connection *conn, const char **str, return conn->xprt->get_alpn(conn, str, len); } +/* registers alpn mux 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 */ +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 and 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 , a proxy in and http mode + * , and installs it on the connection for direction (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 f720601a2..b925f65ff 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -331,6 +332,21 @@ struct connection { } 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 129c74117..43ec32878 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() {