]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-quic: interrupt qcc_recv*() operations if CC scheduled
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 9 Mar 2023 14:49:48 +0000 (15:49 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 23 Mar 2023 13:39:47 +0000 (14:39 +0100)
Ensure that external MUX operations are interrupted if a
CONNECTION_CLOSE is scheduled. This was already the cases for some
functions. This is extended to the qcc_recv*() family for
MAX_STREAM_DATA, RESET_STREAM and STOP_SENDING.

Also, qcc_release_remote_stream() is skipped in qcs_destroy() if a
CONNECTION_CLOSE is already scheduled.

All of this will ensure we only proceed to minimal treatment as soon as
a CONNECTION_CLOSE is prepared. Indeed, all sending and receiving is
stopped as soon as a CONNECTION_CLOSE is emitted so only internal
cleanup code should be necessary at this stage.

This should prevent a registered CONNECTION_CLOSE error status to be
overwritten by an error in a follow-up treatment.

This should be backported up to 2.7.

src/mux_quic.c

index 835011a23fcfa62990a591b3053f9b065c526184..945fd6d5f023e60fa7dd89b6176ca6863b64ff67 100644 (file)
@@ -1141,6 +1141,11 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
 
        TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
 
+       if (qcc->flags & QC_CF_CC_EMIT) {
+               TRACE_DATA("connection closed", QMUX_EV_QCC_RECV, qcc->conn);
+               goto err;
+       }
+
        /* RFC 9000 19.10. MAX_STREAM_DATA Frames
         *
         * Receiving a MAX_STREAM_DATA frame for a locally
@@ -1149,10 +1154,8 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
         * receives a MAX_STREAM_DATA frame for a receive-only stream MUST
         * terminate the connection with error STREAM_STATE_ERROR.
         */
-       if (qcc_get_qcs(qcc, id, 0, 1, &qcs)) {
-               TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
-               return 1;
-       }
+       if (qcc_get_qcs(qcc, id, 0, 1, &qcs))
+               goto err;
 
        if (qcs) {
                TRACE_PROTO("receiving MAX_STREAM_DATA", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
@@ -1173,6 +1176,10 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
 
        TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
        return 0;
+
+ err:
+       TRACE_DEVEL("leaving on error", QMUX_EV_QCC_RECV, qcc->conn);
+       return 1;
 }
 
 /* Handle a new RESET_STREAM frame from stream ID <id> with error code <err>
@@ -1187,6 +1194,11 @@ int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t f
 
        TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
 
+       if (qcc->flags & QC_CF_CC_EMIT) {
+               TRACE_DATA("connection closed", QMUX_EV_QCC_RECV, qcc->conn);
+               goto err;
+       }
+
        /* RFC 9000 19.4. RESET_STREAM Frames
         *
         * An endpoint that receives a RESET_STREAM frame for a send-only stream
@@ -1248,6 +1260,11 @@ int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err)
 
        TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
 
+       if (qcc->flags & QC_CF_CC_EMIT) {
+               TRACE_DATA("connection closed", QMUX_EV_QCC_RECV, qcc->conn);
+               goto err;
+       }
+
        /* RFC 9000 19.5. STOP_SENDING Frames
         *
         * Receiving a STOP_SENDING frame for a
@@ -1256,10 +1273,8 @@ int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err)
         * endpoint that receives a STOP_SENDING frame for a receive-only stream
         * MUST terminate the connection with error STREAM_STATE_ERROR.
         */
-       if (qcc_get_qcs(qcc, id, 0, 1, &qcs)) {
-               TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
-               return 1;
-       }
+       if (qcc_get_qcs(qcc, id, 0, 1, &qcs))
+               goto err;
 
        if (!qcs)
                goto out;
@@ -1317,6 +1332,10 @@ int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err)
  out:
        TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
        return 0;
+
+ err:
+       TRACE_DEVEL("leaving on error", QMUX_EV_QCC_RECV, qcc->conn);
+       return 1;
 }
 
 /* Signal the closing of remote stream with id <id>. Flow-control for new
@@ -1360,7 +1379,8 @@ static int qcc_release_remote_stream(struct qcc *qcc, uint64_t id)
 /* detaches the QUIC stream from its QCC and releases it to the QCS pool. */
 static void qcs_destroy(struct qcs *qcs)
 {
-       struct connection *conn = qcs->qcc->conn;
+       struct qcc *qcc = qcs->qcc;
+       struct connection *conn = qcc->conn;
        const uint64_t id = qcs->id;
 
        TRACE_ENTER(QMUX_EV_QCS_END, conn, qcs);
@@ -1370,8 +1390,10 @@ static void qcs_destroy(struct qcs *qcs)
         */
        BUG_ON(qcs->tx.offset < qcs->tx.sent_offset);
 
-       if (quic_stream_is_remote(qcs->qcc, id))
-               qcc_release_remote_stream(qcs->qcc, id);
+       if (!(qcc->flags & QC_CF_CC_EMIT)) {
+               if (quic_stream_is_remote(qcc, id))
+                       qcc_release_remote_stream(qcc, id);
+       }
 
        qcs_free(qcs);