MEDIUM: ssl: allow h3/QMux negotiation without explicit proto

Implements automatic selection of QMux MUX if "h3" ALPN has been
negotiated on top of TCP/SSL.

The first part of this change is to define "alpn" member of
mux_proto_list. This is necessary so that conn_get_best_mux_entry() can
select it when "h3" has been chosen. As a side-effect, this also
automatically sets a default ALPN to "h3" for bind lines with "proto
qmux".

The most important change is to adapt the SSL layer. On handshake
completion, the eligible MUX is retrieved via conn_select_mux_fe/be()
functions. If xprt_qmux is required by it, MUX init is delayed and QMux
handshake is started first.

This last change is necessary as connection flags CO_FL_QMUX_RECV/SEND
are only set if "proto qmux" is explicitely set. In case xprt_qmux is
activated via pure ALPN negotiation, these flags are also set on
xprt_qmux_init(). This is mandatory to ensure emission/reception of QMux
transport parameters will be performed as expected.
This commit is contained in:
Amaury Denoyelle 2026-05-19 17:54:05 +02:00
parent e30bcfe6cd
commit f2b152c95e
3 changed files with 18 additions and 3 deletions

View file

@ -4814,6 +4814,6 @@ static const struct mux_ops qmux_ops = {
static struct mux_proto_list mux_proto_qmux =
{ .mux_proto = IST("qmux"), .mode = PROTO_MODE_HTTP, .side = PROTO_SIDE_BOTH, .mux = &qmux_ops,
.init_xprt = XPRT_QMUX };
.alpn = "\002h3", .init_xprt = XPRT_QMUX };
INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_qmux);

View file

@ -6962,10 +6962,15 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
* woke a tasklet already.
*/
if (ctx->conn->xprt_ctx == ctx) {
const struct mux_proto_list *mux;
int closed_connection = 0;
if (!ctx->conn->mux) {
if (ctx->conn->flags & (CO_FL_QMUX_RECV|CO_FL_QMUX_SEND)) {
mux = !conn_is_back(conn) ?
conn_select_mux_fe(conn) : conn_select_mux_be(conn);
if (ctx->conn->flags & (CO_FL_QMUX_RECV|CO_FL_QMUX_SEND) ||
mux->init_xprt == XPRT_QMUX) {
const struct xprt_ops *ops = xprt_get(XPRT_QMUX);
void *xprt_ctx_hs = NULL;
@ -6983,8 +6988,13 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
ret = conn->xprt->start(conn, xprt_ctx_hs);
BUG_ON(ret);
}
else
else {
/* TODO MUX selection already performs by conn_select_mux_fe/be().
* Implement an alternative to conn_create_mux() to skip this
* part and directly init the connection and its MUX.
*/
ret = conn_create_mux(ctx->conn, &closed_connection);
}
}
if (ret >= 0 && ctx->conn->mux && !woke && ctx->conn->mux && ctx->conn->mux->wake) {

View file

@ -300,6 +300,11 @@ static int xprt_qmux_init(struct connection *conn, void **xprt_ctx)
ctx->lparams.initial_max_stream_data_bidi_remote = qcm_stream_rx_bufsz();
ctx->lparams.initial_max_stream_data_uni = qcm_stream_rx_bufsz();
/* Ensure the connection flags are set. Necessary when current XPRT is
* activated without explicit "proto qmux" configuration.
*/
conn->flags |= (CO_FL_QMUX_RECV|CO_FL_QMUX_SEND);
*xprt_ctx = ctx;
return 0;