]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: Add closing connection state
authorFrédéric Lécaille <flecaille@haproxy.com>
Mon, 28 Mar 2022 10:13:09 +0000 (12:13 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 6 Apr 2022 13:52:35 +0000 (15:52 +0200)
New received packets after sending CONNECTION_CLOSE frame trigger a new
CONNECTION_CLOSE frame to be sent. Each time such a frame is sent we
increase the number of packet required to send another CONNECTION_CLOSE
frame.
Rearm only one time the idle timer when sending a CONNECTION_CLOSE frame.

include/haproxy/xprt_quic-t.h
src/xprt_quic.c

index 48128413b00d7fb7775b9c4c76dbcfe7fbbf1d08..fad3722c86cc148c2193eb0434ab94c1902d7deb 100644 (file)
@@ -514,8 +514,10 @@ struct quic_rx_strm_frm {
 #define QUIC_FL_TX_PACKET_PADDING       (1UL << 1)
 /* Flag a sent packet as being in flight. */
 #define QUIC_FL_TX_PACKET_IN_FLIGHT     (QUIC_FL_TX_PACKET_ACK_ELICITING | QUIC_FL_TX_PACKET_PADDING)
+/* Flag a sent packet as containg a CONNECTION_CLOSE frame */
+#define QUIC_FL_TX_PACKET_CC            (1UL << 2)
 /* Flag a sent packet as containg an ACK frame */
-#define QUIC_FL_TX_PACKET_ACK           (1UL << 2)
+#define QUIC_FL_TX_PACKET_ACK           (1UL << 3)
 
 /* Structure to store enough information about TX QUIC packets. */
 struct quic_tx_packet {
@@ -662,6 +664,7 @@ enum qc_mux_state {
 #define QUIC_FL_CONN_LISTENER                    (1U << 3)
 #define QUIC_FL_CONN_ACCEPT_REGISTERED           (1U << 4)
 #define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6)
+#define QUIC_FL_CONN_CLOSING                     (1U << 29)
 #define QUIC_FL_CONN_DRAINING                    (1U << 30)
 #define QUIC_FL_CONN_IMMEDIATE_CLOSE             (1U << 31)
 struct quic_conn {
@@ -754,6 +757,11 @@ struct quic_conn {
        struct task *idle_timer_task;
        unsigned int flags;
 
+       /* When in closing state, number of packet before sending CC */
+       unsigned int nb_pkt_for_cc;
+       /* When in closing state, number of packet since receiving CC */
+       unsigned int nb_pkt_since_cc;
+
        const struct qcc_app_ops *app_ops;
 };
 
index 6fdcae6024ba890b57ff763f22d48a1b844ba5e5..6d4262c16bb2e79762dcfd27571610c320bbdcea 100644 (file)
@@ -3047,6 +3047,24 @@ int qc_send_ppkts(struct qring *qr, struct ssl_sock_ctx *ctx)
                                if (qc->flags & QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ)
                                        qc_idle_timer_rearm(qc, 0);
                        }
+                       if (!(qc->flags & QUIC_FL_CONN_CLOSING) &&
+                           (pkt->flags & QUIC_FL_TX_PACKET_CC)) {
+                               qc->flags |= QUIC_FL_CONN_CLOSING;
+                               /* RFC 9000 10.2. Immediate Close:
+                                * The closing and draining connection states exist to ensure
+                                * that connections close cleanly and that delayed or reordered
+                                * packets are properly discarded. These states SHOULD persist
+                                * for at least three times the current PTO interval...
+                                *
+                                * Rearm the idle timeout only one time when entering closing
+                                * state.
+                                */
+                               qc_idle_timer_do_rearm(qc);
+                               if (qc->timer_task) {
+                                       task_destroy(qc->timer_task);
+                                       qc->timer_task = NULL;
+                               }
+                       }
                        qc->path->in_flight += pkt->in_flight_len;
                        pkt->pktns->tx.in_flight += pkt->in_flight_len;
                        if (pkt->in_flight_len)
@@ -4012,6 +4030,10 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
        /* RX part. */
        qc->rx.bytes = 0;
        qc->rx.buf = b_make(buf_area, QUIC_CONN_RX_BUFSZ, 0, 0);
+
+       qc->nb_pkt_for_cc = 1;
+       qc->nb_pkt_since_cc = 0;
+
        LIST_INIT(&qc->rx.pkt_list);
        if (!quic_tls_ku_init(qc)) {
                TRACE_PROTO("Key update initialization failed", QUIC_EV_CONN_INIT, qc);
@@ -4852,6 +4874,17 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
                pkt->qc = qc;
        }
 
+       if (qc->flags & QUIC_FL_CONN_CLOSING) {
+               if (++qc->nb_pkt_since_cc >= qc->nb_pkt_for_cc) {
+                       qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE;
+                       qc->nb_pkt_for_cc++;
+                       qc->nb_pkt_since_cc = 0;
+               }
+               /* Skip the entire datagram */
+               pkt->len = end - beg;
+               TRACE_PROTO("Closing state connection", QUIC_EV_CONN_LPKT, pkt->qc);
+               goto out;
+       }
 
        /* When multiple QUIC packets are coalesced on the same UDP datagram,
         * they must have the same DCID.
@@ -5457,8 +5490,12 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end,
        }
 
        /* Build a CONNECTION_CLOSE frame if needed. */
-       if (cc && !qc_build_frm(&pos, end, &cc_frm, pkt, qc))
-               goto no_room;
+       if (cc) {
+               if (!qc_build_frm(&pos, end, &cc_frm, pkt, qc))
+                       goto no_room;
+
+               pkt->flags |= QUIC_FL_TX_PACKET_CC;
+       }
 
        /* Build a PADDING frame if needed. */
        if (padding_len) {