]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux_quic: handle conn errors on QMux without crash
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 23 Apr 2026 13:37:34 +0000 (15:37 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 24 Apr 2026 07:33:04 +0000 (09:33 +0200)
Remove BUG_ON() related to connection errors when invoking XPRT
snd_buf/rcv_buf in QMux operations. Such errors are now converted in
QC_CF_ERR_CONN flag, which will disable any I/O operations and close the
connection as soon as possible.

Note that this error management is pretty crude. In particular, it could
lead to truncated data when dealing with unidirectional connection
closure from the remote peer. However, it is considered sufficient for
now to continue interop testing without being disturbed by BUG_ON()
assertion crashes.

src/mux_quic_qstrm.c

index ffa7571ac2ec7ddecfabf726e2ac576dcbab1d00..0551f76b46327983e306acb1799ec7f85dc177f9 100644 (file)
@@ -110,6 +110,9 @@ int qcc_qstrm_recv(struct qcc *qcc)
 
        TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
 
+       if (qcc->flags & QC_CF_ERR_CONN)
+               return 0;
+
        if (!b_size(buf)) {
                if (!b_alloc(buf, DB_MUX_RX)) {
                        TRACE_ERROR("rx qstrm buf alloc failure", QMUX_EV_QCC_RECV);
@@ -137,7 +140,8 @@ int qcc_qstrm_recv(struct qcc *qcc)
                        /* 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);
-                       BUG_ON(conn->flags & CO_FL_ERROR); /* TODO handle errors */
+                       if (qcc->conn->flags & CO_FL_ERROR)
+                               goto out;
                        /* Previous realign operation should ensure send cannot result in data wrapping. */
                        BUG_ON(b_data(buf) != b_contig_data(buf, 0));
                }
@@ -172,7 +176,11 @@ int qcc_qstrm_recv(struct qcc *qcc)
                }
        } while (ret > 0);
 
-       if (!conn_xprt_read0_pending(qcc->conn)) {
+ out:
+       if ((conn->flags & CO_FL_ERROR) || conn_xprt_read0_pending(conn)) {
+               qcc->flags |= QC_CF_ERR_CONN;
+       }
+       else {
                conn->xprt->subscribe(conn, conn->xprt_ctx, SUB_RETRY_RECV,
                                      &qcc->wait_event);
        }
@@ -280,6 +288,8 @@ int qcc_qstrm_send_frames(struct qcc *qcc, struct list *frms)
        /* Purge buffer first if remaining data to send. */
        if (b_data(buf)) {
                sent = conn->xprt->snd_buf(conn, conn->xprt_ctx, buf, b_data(buf), NULL, 0, 0);
+               if (conn->flags & CO_FL_ERROR)
+                       goto out;
                if (!sent) {
                        TRACE_DEVEL("snd_buf interrupted", QMUX_EV_QCC_SEND, qcc->conn);
                        goto out;
@@ -332,6 +342,8 @@ int qcc_qstrm_send_frames(struct qcc *qcc, struct list *frms)
                b_add(buf, pos - old);
 
                sent = conn->xprt->snd_buf(conn, conn->xprt_ctx, buf, b_data(buf), NULL, 0, 0);
+               if (conn->flags & CO_FL_ERROR)
+                       goto out;
                if (!sent) {
                        TRACE_DEVEL("snd_buf interrupted", QMUX_EV_QCC_SEND, qcc->conn);
                        if (split_frm)
@@ -354,8 +366,9 @@ int qcc_qstrm_send_frames(struct qcc *qcc, struct list *frms)
        }
 
  out:
-       if (conn->flags & CO_FL_ERROR) {
-               /* TODO */
+       if ((conn->flags & CO_FL_ERROR)) {
+               qcc->flags |= QC_CF_ERR_CONN;
+               ret = -1;
        }
        else if (!LIST_ISEMPTY(frms)) {
                if (!(qcc->wait_event.events & SUB_RETRY_SEND))