MINOR: quic: Add closing connection state

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.
This commit is contained in:
Frédéric Lécaille 2022-03-28 12:13:09 +02:00 committed by Amaury Denoyelle
parent 47756809fb
commit 59bf255806
2 changed files with 48 additions and 3 deletions

View 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;
};

View 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) {