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 23a17cb..dbb6fe6 100644
--- a/include/haproxy/mux_quic.h
+++ b/include/haproxy/mux_quic.h
@@ -27,6 +27,7 @@
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 44fdf6a..ba62598 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -888,6 +888,56 @@
return 0;
}
+/* Handle a new STOP_SENDING frame for stream ID <id>. The error code should be
+ * specified in <err>.
+ *
+ * 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 <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 728aaf5..34fc13e 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -2412,8 +2412,16 @@
/* 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;