From: Amaury Denoyelle Date: Wed, 25 Mar 2026 08:05:21 +0000 (+0100) Subject: MINOR: xprt_qstrm: implement reception of transport parameters X-Git-Tag: v3.4-dev8~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=531a2b9f1ac45a33629b4c80bb343dd3a089a945;p=thirdparty%2Fhaproxy.git MINOR: xprt_qstrm: implement reception of transport parameters Extend xprt_qstrm to implement the reception of QMux transport parameters. This is performed via conn_recv_qstrm() which relies on the lower xprt rcv_buf operation. Once received, parameters are kept in xprt_qstrm context, so that the MUX can retrieve them on init. For the reception of parameters to be active, the connection must first be flagged with CO_FL_QSTRM_RECV. --- diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 2b8927b82..f803aaf41 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -130,7 +130,8 @@ enum { CO_FL_OPT_TOS = 0x00000020, /* connection has a special sockopt tos */ - /* unused : 0x00000040, 0x00000080 */ + /* unused : 0x00000040 */ + CO_FL_QSTRM_RECV = 0x00000080, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */ /* These flags indicate whether the Control and Transport layers are initialized */ CO_FL_CTRL_READY = 0x00000100, /* FD was registered, fd_delete() needed */ diff --git a/src/xprt_qstrm.c b/src/xprt_qstrm.c index c9ad39b1b..104197dab 100644 --- a/src/xprt_qstrm.c +++ b/src/xprt_qstrm.c @@ -21,14 +21,71 @@ struct xprt_qstrm_ctx { DECLARE_STATIC_TYPED_POOL(xprt_qstrm_ctx_pool, "xprt_qstrm_ctx", struct xprt_qstrm_ctx); +int conn_recv_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int flag) +{ + struct quic_frame frm; + const unsigned char *pos, *end; + int ret; + + if (!conn_ctrl_ready(conn)) + goto fail; + + BUG_ON(conn->flags & CO_FL_FDLESS); + + if (!fd_recv_ready(conn->handle.fd)) + goto not_ready; + + while (1) { + ret = ctx->ops_lower->rcv_buf(conn, ctx->ctx_lower, &trash, trash.size, NULL, 0, MSG_PEEK); + BUG_ON(conn->flags & CO_FL_ERROR); /* TODO handle fatal errors */ + trash.data = ret; + break; + } + + if (!trash.data) + goto not_ready; + + pos = (unsigned char *)b_orig(&trash); + end = (unsigned char *)(b_orig(&trash) + b_data(&trash)); + ret = qc_parse_frm_type(&frm, &pos, end, NULL); + BUG_ON(!ret); /* TODO handle a truncated frame, recv must be performed again. */ + + /* TODO close connection with TRANSPORT_PARAMETER_ERROR if frame not present. */ + BUG_ON(frm.type != QUIC_FT_QX_TRANSPORT_PARAMETERS); + + ret = qc_parse_frm_payload(&frm, &pos, end, NULL); + BUG_ON(!ret); /* TODO handle a truncated frame, recv must be performed again. */ + + ctx->rparams = frm.qmux_transport_params.params; + + conn->flags &= ~flag; + return 1; + + not_ready: + return 0; + + fail: + conn->flags |= CO_FL_ERROR; + return 0; +} + struct task *xprt_qstrm_io_cb(struct task *t, void *context, unsigned int state) { struct xprt_qstrm_ctx *ctx = context; struct connection *conn = ctx->conn; int ret; + if (conn->flags & CO_FL_QSTRM_RECV) { + if (!conn_recv_qstrm(conn, ctx, CO_FL_QSTRM_RECV)) { + ctx->ops_lower->subscribe(conn, ctx->ctx_lower, + SUB_RETRY_RECV, &ctx->wait_event); + goto out; + } + } + out: - if (conn->flags & CO_FL_ERROR) { + if ((conn->flags & CO_FL_ERROR) || + !(conn->flags & CO_FL_QSTRM_RECV)) { /* MUX will access members from xprt_ctx on init, so create * operation should be called before any members are resetted. */