]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: mux-quic: implement STOP_SENDING handling
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 4 Jul 2022 09:44:53 +0000 (11:44 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 11 Jul 2022 14:45:04 +0000 (16:45 +0200)
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.

include/haproxy/mux_quic.h
src/mux_quic.c
src/xprt_quic.c

index 23a17cb2515f1dfafff4e2d1196c49f0d466f818..dbb6fe6faa36116a45bef1531f618f1d3446daa9 100644 (file)
@@ -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
index 44fdf6a7f6fc6b4e29d40e17817d2dc75d595c67..ba62598cad7b9182c73493ba5672f9bf0cbc51b2 100644 (file)
@@ -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 <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.
  */
index 728aaf5c2ed5a58a8a1f46b3f78bc4e7c2de6f8b..34fc13e73a8caf41c0de78679ad4590f5b1a8d28 100644 (file)
@@ -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;