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;