diff --git a/src/quic_conn.c b/src/quic_conn.c index 00d974146..129780d70 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -1534,7 +1534,33 @@ void qc_idle_timer_do_rearm(struct quic_conn *qc, int arm_ack) task_wakeup(qc->idle_timer_task, TASK_WOKEN_MSG); } else { - expire = QUIC_MAX(3 * quic_pto(qc), qc->max_idle_timeout); + if (qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_DRAINING)) { + /* 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 as defined in [QUIC-RECOVERY]. + */ + + /* Delay is limited to 1s which should cover most of + * network conditions. The process should not be + * impacted by a connection with a high RTT. + */ + expire = MIN(3 * quic_pto(qc), 1000); + } + else { + /* RFC 9000 10.1. Idle Timeout + * + * To avoid excessively small idle timeout periods, endpoints MUST + * increase the idle timeout period to be at least three times the + * current Probe Timeout (PTO). This allows for multiple PTOs to expire, + * and therefore multiple probes to be sent and lost, prior to idle + * timeout. + */ + expire = QUIC_MAX(3 * quic_pto(qc), qc->max_idle_timeout); + } + qc->idle_expire = tick_add(now_ms, MS_TO_TICKS(expire)); if (arm_ack) { /* Arm the ack timer only if not already armed. */