diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index b9933642f..e4dac7bf3 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -114,6 +114,7 @@ int conn_reverse(struct connection *conn); const char *conn_err_code_name(struct connection *c); const char *conn_err_code_str(struct connection *c); int xprt_add_hs(struct connection *conn); +int xprt_add_l6hs(struct connection *conn, int xprt); void register_mux_proto(struct mux_proto_list *list); static inline void conn_report_term_evt(struct connection *conn, enum term_event_loc loc, unsigned char type); diff --git a/src/connection.c b/src/connection.c index c56049ed2..99ca36c1f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -847,6 +847,43 @@ int xprt_add_hs(struct connection *conn) return 0; } +/* Activates an layer on top of connection. This handshake layer + * should be designed to work on top of the layer 6. If SSL is active and its + * handshake still in progress, this function does nothing. + * + * Returns 0 on success else a negative error code. + */ +int xprt_add_l6hs(struct connection *conn, int xprt) +{ + const struct xprt_ops *ops = xprt_get(xprt); + void *ops_ctx = NULL; + + /* Only QMux is supported as handshake on top of layer6 for now. */ + BUG_ON(xprt != XPRT_QMUX); + + if (conn->flags & CO_FL_ERROR) + return -1; + + /* Do nothing if SSL is in used but handshake still in progress. In + * this case, xprt layer will be added on handshake completion. + */ + if (conn->xprt == xprt_get(XPRT_SSL) && + (conn->flags & CO_FL_WAIT_L6_CONN)) { + return 0; + } + + if (ops->init(conn, &ops_ctx)) + return -1; + + ops->add_xprt(conn, ops_ctx, conn->xprt_ctx, conn->xprt, NULL, NULL); + conn->xprt = ops; + conn->xprt_ctx = ops_ctx; + /* Reset XPRT READY flag before the next conn_xprt_start(). */ + conn->flags &= ~CO_FL_XPRT_READY; + + return 0; +} + /* returns a short name for an error, typically the same as the enum name * without the "CO_ER_" prefix, or an empty string for no error (better eye * catching in logs). This is more compact for some debug cases. diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 3ab33c990..aa167b001 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -6973,11 +6973,8 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state) mux = !conn_is_back(conn) ? conn_select_mux_fe(conn) : conn_select_mux_be(conn); - if (mux->init_xprt == XPRT_QMUX) { - const struct xprt_ops *ops = xprt_get(XPRT_QMUX); - void *xprt_ctx_hs = NULL; - - ret = ops->init(conn, &xprt_ctx_hs); + if (mux->init_xprt) { + ret = xprt_add_l6hs(conn, mux->init_xprt); /* Frontend conn must be freed in case of XPRT init failure. */ if (ret) { if (!conn_is_back(conn)) { @@ -6989,15 +6986,7 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state) goto leave; } - ret = ops->add_xprt(conn, xprt_ctx_hs, - conn->xprt_ctx, conn->xprt, NULL, NULL); - BUG_ON(ret); /* xprt_qmux add_xprt always succeeds */ - - conn->xprt = ops; - conn->xprt_ctx = xprt_ctx_hs; - - ret = conn->xprt->start(conn, xprt_ctx_hs); - BUG_ON(ret); + ret = conn_xprt_start(conn); } else { /* TODO MUX selection already performs by conn_select_mux_fe/be().