]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: mux_quic: use separate error code for STOP_SENDING
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 30 Jun 2026 16:29:07 +0000 (18:29 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 6 Jul 2026 08:19:12 +0000 (10:19 +0200)
Prior to this patch, a single error code was registrable at the QCS
level. This code was used both for RESET_STREAM and STOP_SENDING
emission. It was specified via qcc_reset_stream().

This patch extends the API so that now a dedicated error code is
implemented for STOP_SENDING as well. This may be necessary as both
frames can be sent in different context, with a diverging error code.

This patch is required to implement STOP_SENDING emission during shut
callback when read channel is closed.

include/haproxy/mux_quic-t.h
include/haproxy/mux_quic.h
src/h3.c
src/mux_quic.c

index 78cc5041ba27d303415eff5200fe9a8f4a2db239..25bab15d97cffd859073c1efa6c76afb11d2801b 100644 (file)
@@ -198,7 +198,8 @@ struct qcs {
        struct wait_event wait_event;
        struct wait_event *subs;
 
-       uint64_t err; /* error code to transmit via RESET_STREAM */
+       uint64_t rs_err; /* error code to transmit via RESET_STREAM */
+       uint64_t ss_err; /* error code to transmit via STOP_SENDING */
 
        int start; /* base timestamp for http-request timeout */
 
index ae4a58846036180195fb0c4544c233a78bafa8d2..d79e2cc661958b12bba0bf0afa1ef2e558329c26 100644 (file)
@@ -44,7 +44,7 @@ int qcc_release_stream_txbuf(struct qcs *qcs);
 int qcc_stream_can_send(const struct qcs *qcs);
 void qcc_reset_stream(struct qcs *qcs, int err, int term_evt);
 void qcc_send_stream(struct qcs *qcs, int urg, int count);
-void qcc_abort_stream_read(struct qcs *qcs);
+void qcc_abort_stream_read(struct qcs *qcs, int err);
 void qcc_update_shut_id(struct qcc *qcc, uint64_t val);
 int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
              char fin, char *data);
index 6ce7708467ebdb1998222119503df9f256f59c53..3a1eb1124299a1c52fb447c327d8ed4c9d8a3eaa 100644 (file)
--- a/src/h3.c
+++ b/src/h3.c
@@ -283,7 +283,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
                 * streams that have unknown or unsupported types.
                 */
                TRACE_STATE("abort reading on unknown uni stream type", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
-               qcc_abort_stream_read(qcs);
+               qcc_abort_stream_read(qcs, H3_ERR_NO_ERROR);
                goto err;
        }
 
@@ -1908,7 +1908,7 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
 
                /* FIN received, ensure body length is conform to any content-length header. */
                if ((h3s->flags & H3_SF_HAVE_CLEN) && h3_check_body_size(qcs, 1)) {
-                       qcc_abort_stream_read(qcs);
+                       qcc_abort_stream_read(qcs, h3s->err);
                        qcc_reset_stream(qcs, h3s->err, se_tevt_type_proto_err);
                        goto done;
                }
@@ -2133,7 +2133,7 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
                /* TODO Only unimplemented CONNECT reports H3_ERR_REQUEST_REJECTED here. */
                const int tevt =
                  (h3s->err == H3_ERR_REQUEST_REJECTED) ? 0 : se_tevt_type_proto_err;
-               qcc_abort_stream_read(qcs);
+               qcc_abort_stream_read(qcs, h3s->err);
                qcc_reset_stream(qcs, h3s->err, tevt);
                total += b_data(b);
                goto done;
@@ -3141,8 +3141,7 @@ static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count, char
                /* Generate a STOP_SENDING if full response transferred before
                 * receiving the full request.
                 */
-               qcs->err = H3_ERR_NO_ERROR;
-               qcc_abort_stream_read(qcs);
+               qcc_abort_stream_read(qcs, H3_ERR_NO_ERROR);
        }
 #endif
 
@@ -3368,7 +3367,7 @@ static int h3_attach(struct qcs *qcs, void *conn_ctx)
                BUG_ON(quic_stream_is_local(qcs->qcc, qcs->id));
 
                TRACE_STATE("close stream outside of GOAWAY range", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
-               qcc_abort_stream_read(qcs);
+               qcc_abort_stream_read(qcs, H3_ERR_REQUEST_REJECTED);
                qcc_reset_stream(qcs, H3_ERR_REQUEST_REJECTED, 0);
        }
 
index 550a02a8c11795ce4e99d1901fa4d22e5b13d212..ae6c2da0d62e9be168caaa440d01cf43cb11d6a0 100644 (file)
@@ -207,7 +207,7 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type)
        qcs->wait_event.events = 0;
        qcs->subs = NULL;
 
-       qcs->err = 0;
+       qcs->rs_err = qcs->ss_err = 0;
 
        /* Reset all timers and start base one. */
        tot_time_reset(&qcs->timer.base);
@@ -238,7 +238,7 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type)
         * accept or reject the new stream via its attach() operation.
         */
        if (qcc->app_st >= QCC_APP_ST_SHUT && !qcc->app_ops->shutdown) {
-               qcc_abort_stream_read(qcs);
+               qcc_abort_stream_read(qcs, 0);
                qcc_reset_stream(qcs, 0, 0);
                goto out;
        }
@@ -1749,7 +1749,7 @@ void qcc_reset_stream(struct qcs *qcs, int err, int tevt)
 
        TRACE_STATE("reset stream", QMUX_EV_QCS_END, qcc->conn, qcs);
        qcs->flags |= QC_SF_TO_RESET;
-       qcs->err = err;
+       qcs->rs_err = err;
 
        /* On BE side, a QCS may be resetted before any data emission. */
        if (conn_is_back(qcs->qcc->conn))
@@ -1808,7 +1808,7 @@ void qcc_send_stream(struct qcs *qcs, int urg, int count)
 }
 
 /* Prepare for the emission of STOP_SENDING on <qcs>. */
-void qcc_abort_stream_read(struct qcs *qcs)
+void qcc_abort_stream_read(struct qcs *qcs, int err)
 {
        struct qcc *qcc = qcs->qcc;
 
@@ -1819,6 +1819,7 @@ void qcc_abort_stream_read(struct qcs *qcs)
 
        TRACE_STATE("abort stream read", QMUX_EV_QCS_END, qcc->conn, qcs);
        qcs->flags |= (QC_SF_TO_STOP_SENDING|QC_SF_READ_ABORTED);
+       qcs->ss_err = err;
 
        _qcc_send_stream(qcs, 1);
        tasklet_wakeup(qcc->wait_event.tasklet);
@@ -2795,7 +2796,7 @@ static int qcs_send_reset(struct qcs *qcs)
        }
 
        frm->reset_stream.id = qcs->id;
-       frm->reset_stream.app_error_code = qcs->err;
+       frm->reset_stream.app_error_code = qcs->rs_err;
        frm->reset_stream.final_size = qcs->tx.fc.off_real;
 
        LIST_APPEND(&frms, &frm->list);
@@ -2847,7 +2848,7 @@ static int qcs_send_stop_sending(struct qcs *qcs)
        }
 
        frm->stop_sending.id = qcs->id;
-       frm->stop_sending.app_error_code = qcs->err;
+       frm->stop_sending.app_error_code = qcs->ss_err;
 
        LIST_APPEND(&frms, &frm->list);
        if (qcc_send_frames(qcs->qcc, &frms, 0)) {
@@ -4809,8 +4810,9 @@ static int qcm_strm_show_sd(struct buffer *msg, struct sedesc *sd, const char *p
        if (!qcs)
                return ret;
 
-       chunk_appendf(msg, " qcs=%p .flg=%#x .id=%llu .st=%s .ctx=%p, .err=%#llx",
-                     qcs, qcs->flags, (ull)qcs->id, qcs_st_to_str(qcs->st), qcs->ctx, (ull)qcs->err);
+       chunk_appendf(msg, " qcs=%p .flg=%#x .id=%llu .st=%s .ctx=%p, .err=%#llx/%#llx",
+                     qcs, qcs->flags, (ull)qcs->id, qcs_st_to_str(qcs->st), qcs->ctx,
+                     (ull)qcs->rs_err, (ull)qcs->ss_err);
 
        if (pfx)
                chunk_appendf(msg, "\n%s", pfx);