]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: xprt_qstrm: implement reception of transport parameters
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 25 Mar 2026 08:05:21 +0000 (09:05 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 2 Apr 2026 12:02:04 +0000 (14:02 +0200)
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.

include/haproxy/connection-t.h
src/xprt_qstrm.c

index 2b8927b826b53d58139e2f756f5cd9f431228147..f803aaf419578cf4a6acafcf3601ec4d059dfb52 100644 (file)
@@ -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 */
index c9ad39b1b9f210b7192b7f131bb9dfe5654b19ff..104197dab8d1d4551c027334cc839889f54911b4 100644 (file)
@@ -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.
                 */