From: Amaury Denoyelle Date: Thu, 23 Apr 2026 13:38:06 +0000 (+0200) Subject: MINOR: mux_quic: handle incomplete QMux record read X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=cc395357029ea5227a0c41ca626aa1789cc73050;p=thirdparty%2Fhaproxy.git MINOR: mux_quic: handle incomplete QMux record read QMux implements a record layer which is used to encapsulate QUIC frames. This patch implements reception of an incomplete record in qcc_qstrm_recv(). BUG_ON() failures are removed and now reading will continue until the whole record is received or a fatal error occurs. Several adjustments were made in the logic for read operation. Previously, read syscall was only performed if either data buffer was empty or current record was incomplete. An extra condition is added to perform read if there is data in the buffer but not enough to decode a record header. Another change is that buffer realign is also performed in this latter case and if buffer wrapping position has been reached. --- diff --git a/src/mux_quic_qstrm.c b/src/mux_quic_qstrm.c index 0551f76b4..a83d20369 100644 --- a/src/mux_quic_qstrm.c +++ b/src/mux_quic_qstrm.c @@ -105,7 +105,7 @@ int qcc_qstrm_recv(struct qcc *qcc) struct connection *conn = qcc->conn; struct buffer *buf = &qcc->rx.qstrm_buf; struct buffer buf_rec; - int total = 0, frm_ret; + int total = 0, dec = 1, frm_ret; size_t ret = 1; TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn); @@ -125,8 +125,11 @@ int qcc_qstrm_recv(struct qcc *qcc) /* Wrapping is not supported for QMux reception. */ BUG_ON(b_data(buf) != b_contig_data(buf, 0)); - /* If current record is too big, realign buffer for more room. */ - if (b_head(buf) + qcc->rx.rlen > b_wrap(buf)) { + /* Realign buffer if current record too big or cannot decode + * record header and wrapping position reached. + */ + if (b_head(buf) + qcc->rx.rlen > b_wrap(buf) || + (!dec && b_head(buf) + b_data(buf) == b_wrap(buf))) { BUG_ON(qcc->rx.rlen > b_size(buf)); /* TODO max_record_size */ memmove(b_orig(buf), b_head(buf), b_data(buf)); buf->head = 0; @@ -136,7 +139,12 @@ int qcc_qstrm_recv(struct qcc *qcc) b_realign_if_empty(buf); } - if ((!b_data(buf) && !qcc->rx.rlen) || qcc->rx.rlen > b_data(buf)) { + /* Try read if record header not yet read and no data available + * or hreader cannot be decoded, or either if current record + * is incomplete. + */ + if ((!qcc->rx.rlen && (!b_data(buf) || !dec)) || + qcc->rx.rlen > b_data(buf)) { /* Previous realign operation should ensure send cannot result in data wrapping. */ BUG_ON(b_data(buf) && b_tail(buf) == b_orig(buf)); ret = conn->xprt->rcv_buf(conn, conn->xprt_ctx, buf, b_contig_space(buf), NULL, 0, 0); @@ -147,11 +155,15 @@ int qcc_qstrm_recv(struct qcc *qcc) } if (b_data(buf) && !qcc->rx.rlen) { - int ret2 = b_quic_dec_int(&qcc->rx.rlen, buf, NULL); - BUG_ON(!ret2); /* TODO incomplete record length */ - if (b_head(buf) + qcc->rx.rlen > b_wrap(buf)) + dec = b_quic_dec_int(&qcc->rx.rlen, buf, NULL); + /* Restart read if an incomplete record has been received + * until there is no more new data available. + */ + if (ret && (!dec || + b_head(buf) + qcc->rx.rlen > b_wrap(buf) || + b_data(buf) < qcc->rx.rlen)) { goto recv; - BUG_ON(b_data(buf) < qcc->rx.rlen); /* TODO incomplete record */ + } } /* TODO realign necessary if record boundary at the extreme end of the buffer */