]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: xprt_qstrm: define new xprt module for QMux protocol
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 24 Mar 2026 15:58:48 +0000 (16:58 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 2 Apr 2026 12:02:04 +0000 (14:02 +0200)
Define a new XPRT layer for the new QMux protocol. Its role will be to
perform the initial exchange of transport parameters.

On completion, contrary to XPRT handshake, xprt_qstrm will first init
the MUX and then removes itself. This will be necessary so that the
parameters can be retrieved by the MUX during its initialization.

This patch only declares the new xprt_qstrm along with basic operations.
Future commits will implement the proper reception/emission steps.

Makefile
include/haproxy/connection-t.h
src/xprt_qstrm.c [new file with mode: 0644]

index 44d014784351d4d8671bf1d282092c6344e6af83..41aab3e376888d76e9559b1e57fe1286a5c1449c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -670,7 +670,7 @@ OPTIONS_OBJS += src/mux_quic.o src/h3.o src/quic_rx.o src/quic_tx.o \
                 src/quic_cc_nocc.o src/quic_cc.o src/quic_pacing.o     \
                 src/h3_stats.o src/quic_stats.o src/qpack-enc.o                \
                 src/qpack-tbl.o src/quic_cc_drs.o src/quic_fctl.o      \
-                src/quic_enc.o src/mux_quic_qstrm.o
+                src/quic_enc.o src/mux_quic_qstrm.o src/xprt_qstrm.o
 endif
 
 ifneq ($(USE_QUIC_OPENSSL_COMPAT:0=),)
index 0d7a589fcf28843929b5962233e3992e473b2f2d..2b8927b826b53d58139e2f756f5cd9f431228147 100644 (file)
@@ -345,6 +345,7 @@ enum {
        XPRT_SSL = 1,
        XPRT_HANDSHAKE = 2,
        XPRT_QUIC = 3,
+       XPRT_QSTRM = 4,
        XPRT_ENTRIES /* must be last one */
 };
 
diff --git a/src/xprt_qstrm.c b/src/xprt_qstrm.c
new file mode 100644 (file)
index 0000000..8fccacf
--- /dev/null
@@ -0,0 +1,118 @@
+#include <haproxy/api.h>
+#include <haproxy/buf.h>
+#include <haproxy/connection.h>
+#include <haproxy/fd.h>
+#include <haproxy/global.h>
+#include <haproxy/pool.h>
+#include <haproxy/quic_frame.h>
+#include <haproxy/quic_tp-t.h>
+
+struct xprt_qstrm_ctx {
+       struct connection *conn;
+       struct wait_event *subs;
+       struct wait_event wait_event;
+
+       const struct xprt_ops *ops_lower;
+       void *ctx_lower;
+
+       struct quic_transport_params lparams;
+       struct quic_transport_params rparams;
+};
+
+DECLARE_STATIC_TYPED_POOL(xprt_qstrm_ctx_pool, "xprt_qstrm_ctx", struct xprt_qstrm_ctx);
+
+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;
+
+ out:
+       if (conn->flags & CO_FL_ERROR) {
+               /* MUX will access members from xprt_ctx on init, so create
+                * operation should be called before any members are resetted.
+                */
+               ret = conn_create_mux(conn, NULL);
+               BUG_ON(ret);
+
+               conn->xprt_ctx = ctx->ctx_lower;
+               conn->xprt = ctx->ops_lower;
+               conn->mux->wake(conn);
+
+               tasklet_free(ctx->wait_event.tasklet);
+               pool_free(xprt_qstrm_ctx_pool, ctx);
+               t = NULL;
+       }
+
+       return t;
+}
+
+static int xprt_qstrm_add_xprt(struct connection *conn, void *xprt_ctx,
+                              void *ctx_lower, const struct xprt_ops *ops_lower,
+                              void **ctx_older, const struct xprt_ops **ops_older)
+{
+       struct xprt_qstrm_ctx *ctx = xprt_ctx;
+       BUG_ON(ctx_older || ops_older);
+
+       ctx->ctx_lower = ctx_lower;
+       ctx->ops_lower = ops_lower;
+
+       return 0;
+}
+
+static int xprt_qstrm_init(struct connection *conn, void **xprt_ctx)
+{
+       struct xprt_qstrm_ctx *ctx;
+       BUG_ON(*xprt_ctx);
+
+       ctx = pool_alloc(xprt_qstrm_ctx_pool);
+       if (!ctx) {
+               conn->err_code = CO_ER_SSL_NO_MEM;
+               return -1;
+       }
+
+       ctx->conn = conn;
+       ctx->wait_event.tasklet = tasklet_new();
+       if (!ctx->wait_event.tasklet) {
+               conn->err_code = CO_ER_SSL_NO_MEM;
+               pool_free(xprt_qstrm_ctx_pool, ctx);
+               return -1;
+       }
+       ctx->wait_event.tasklet->process = xprt_qstrm_io_cb;
+       ctx->wait_event.tasklet->context = ctx;
+       ctx->wait_event.events = 0;
+
+       ctx->ctx_lower = NULL;
+       ctx->ops_lower = NULL;
+
+       *xprt_ctx = ctx;
+
+       return 0;
+}
+
+static int xprt_qstrm_start(struct connection *conn, void *xprt_ctx)
+{
+       struct xprt_qstrm_ctx *ctx = xprt_ctx;
+       tasklet_wakeup(ctx->wait_event.tasklet);
+       return 0;
+}
+
+static void xprt_qstrm_close(struct connection *conn, void *xprt_ctx)
+{
+       /* TODO not implemented */
+       ABORT_NOW();
+}
+
+struct xprt_ops xprt_qstrm = {
+       .add_xprt  = xprt_qstrm_add_xprt,
+       .init      = xprt_qstrm_init,
+       .start     = xprt_qstrm_start,
+       .close     = xprt_qstrm_close,
+       .name      = "qstrm",
+};
+
+static void __xprt_qstrm_init(void)
+{
+       xprt_register(XPRT_QSTRM, &xprt_qstrm);
+}
+INITCALL0(STG_REGISTER, __xprt_qstrm_init);