From: Amaury Denoyelle Date: Thu, 9 Mar 2023 14:49:48 +0000 (+0100) Subject: MINOR: mux-quic: interrupt qcc_recv*() operations if CC scheduled X-Git-Tag: v2.8-dev6~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b47310d883700eee4ba996a7f035b05a069723cd;p=thirdparty%2Fhaproxy.git MINOR: mux-quic: interrupt qcc_recv*() operations if CC scheduled 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. --- diff --git a/src/mux_quic.c b/src/mux_quic.c index 835011a23f..945fd6d5f0 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -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 with error code @@ -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 . 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);