From: Amaury Denoyelle Date: Mon, 4 Jul 2022 09:44:53 +0000 (+0200) Subject: MEDIUM: mux-quic: implement STOP_SENDING handling X-Git-Tag: v2.7-dev2~65 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a5b507521130784fa301a0257e0274b5a496ac9d;p=thirdparty%2Fhaproxy.git MEDIUM: mux-quic: implement STOP_SENDING handling Implement support for STOP_SENDING frame parsing. The stream is resetted as specified by RFC 9000. This will automatically interrupt all future send operation in qc_send(). A RESET_STREAM will be sent with the code extracted from the original STOP_SENDING frame. --- diff --git a/include/haproxy/mux_quic.h b/include/haproxy/mux_quic.h index 23a17cb251..dbb6fe6faa 100644 --- a/include/haproxy/mux_quic.h +++ b/include/haproxy/mux_quic.h @@ -27,6 +27,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset, char fin, char *data); int qcc_recv_max_data(struct qcc *qcc, uint64_t max); int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max); +int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err); void qcc_streams_sent_done(struct qcs *qcs, uint64_t data, uint64_t offset); /* Bit shift to get the stream sub ID for internal use which is obtained diff --git a/src/mux_quic.c b/src/mux_quic.c index 44fdf6a7f6..ba62598cad 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -888,6 +888,56 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max) return 0; } +/* Handle a new STOP_SENDING frame for stream ID . The error code should be + * specified in . + * + * Returns 0 on success else non-zero. On error, the received frame should not + * be acknowledged. + */ +int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err) +{ + struct qcs *qcs; + + TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn); + + /* RFC 9000 19.5. STOP_SENDING Frames + * + * Receiving a STOP_SENDING frame for a + * locally initiated stream that has not yet been created MUST be + * treated as a connection error of type STREAM_STATE_ERROR. An + * 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 (!qcs) + goto out; + + /* RFC 9000 3.5. Solicited State Transitions + * + * An endpoint that receives a STOP_SENDING frame + * MUST send a RESET_STREAM frame if the stream is in the "Ready" or + * "Send" state. If the stream is in the "Data Sent" state, the + * endpoint MAY defer sending the RESET_STREAM frame until the packets + * containing outstanding data are acknowledged or declared lost. If + * any outstanding data is declared lost, the endpoint SHOULD send a + * RESET_STREAM frame instead of retransmitting the data. + * + * An endpoint SHOULD copy the error code from the STOP_SENDING frame to + * the RESET_STREAM frame it sends, but it can use any application error + * code. + */ + TRACE_DEVEL("receiving STOP_SENDING on stream", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs); + qcc_reset_stream(qcs, err); + + out: + TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn); + return 0; +} + /* Signal the closing of remote stream with id . Flow-control for new * streams may be allocated for the peer if needed. */ diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 728aaf5c2e..34fc13e73a 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -2412,8 +2412,16 @@ static int qc_parse_pkt_frms(struct quic_rx_packet *pkt, struct ssl_sock_ctx *ct /* TODO: handle this frame at STREAM level */ break; case QUIC_FT_STOP_SENDING: - /* TODO: handle this frame at STREAM level */ + { + struct quic_stop_sending *stop_sending = &frm.stop_sending; + if (qc->mux_state == QC_MUX_READY) { + if (qcc_recv_stop_sending(qc->qcc, stop_sending->id, + stop_sending->app_error_code)) { + goto err; + } + } break; + } case QUIC_FT_CRYPTO: { struct quic_rx_crypto_frm *cf;