]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: xprt_qstrm: implement Tx buffering
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 8 Apr 2026 08:42:44 +0000 (10:42 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 10 Apr 2026 08:20:52 +0000 (10:20 +0200)
This commit adds buffering on transmission for xprt_qstrm layer. This is
necessary in the rare case where send syscall only emits partial data.

A new <txbuf> member is defined in xprt_qstrm context. On first send
invokation, buffer is allocated and then the QMux transport parameters
frame is encoded. Then emission is performed via snd_buf and each time
the send function is invoked.

src/xprt_qstrm.c

index a51222a70e0c42527670b7187dc163274e241179..ce7a50f74a97ba73366998f5b5291961a5e4cc31 100644 (file)
@@ -20,6 +20,7 @@ struct xprt_qstrm_ctx {
        struct quic_transport_params lparams;
        struct quic_transport_params rparams;
 
+       struct buffer txbuf;
        struct buffer rxbuf;
 };
 
@@ -97,7 +98,9 @@ int conn_recv_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int fla
 int conn_send_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int flag)
 {
        struct quic_frame frm;
+       struct buffer *buf = &ctx->txbuf;
        unsigned char *pos, *old, *end;
+       size_t sent;
        int ret;
 
        if (!conn_ctrl_ready(conn))
@@ -106,21 +109,31 @@ int conn_send_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int fla
        frm.type = QUIC_FT_QX_TRANSPORT_PARAMETERS;
        frm.qmux_transport_params.params = ctx->lparams;
 
-       b_reset(&trash);
-       old = pos = (unsigned char *)b_head(&trash);
-       end = (unsigned char *)b_wrap(&trash);
-       ret = qc_build_frm(&frm, &pos, end, NULL);
-       BUG_ON(!ret);
-       b_add(&trash, pos - old);
+       /* Small buf is sufficient for our transport parameters. */
+       if (!b_size(buf) && !b_alloc_small(buf))
+               goto fail;
+
+       if (!b_data(buf)) {
+               old = pos = (unsigned char *)b_orig(buf);
+               end = (unsigned char *)b_wrap(buf);
+               ret = qc_build_frm(&frm, &pos, end, NULL);
+               BUG_ON(!ret);
+               b_add(buf, pos - old);
+       }
 
-       ret = ctx->ops_lower->snd_buf(conn, ctx->ctx_lower, &trash, b_data(&trash),
-                                     NULL, 0, 0);
-       BUG_ON(!ret || ret != b_data(&trash));
+       sent = ctx->ops_lower->snd_buf(conn, ctx->ctx_lower, buf, b_data(buf),
+                                      NULL, 0, 0);
+       b_del(buf, sent);
+       if (b_data(buf))
+               goto retry;
 
        conn->flags &= ~flag;
 
        return 1;
 
+ retry:
+       return 0;
+
  fail:
        conn->flags |= CO_FL_ERROR;
        return 0;
@@ -162,6 +175,7 @@ struct task *xprt_qstrm_io_cb(struct task *t, void *context, unsigned int state)
                conn->mux->wake(conn);
 
                b_free(&ctx->rxbuf);
+               b_free(&ctx->txbuf);
 
                tasklet_free(ctx->wait_event.tasklet);
                pool_free(xprt_qstrm_ctx_pool, ctx);
@@ -210,6 +224,7 @@ static int xprt_qstrm_init(struct connection *conn, void **xprt_ctx)
        ctx->ops_lower = NULL;
 
        ctx->rxbuf = BUF_NULL;
+       ctx->txbuf = BUF_NULL;
 
        memset(&ctx->rparams, 0, sizeof(struct quic_transport_params));