From: Amaury Denoyelle Date: Wed, 14 Oct 2026 13:40:56 +0000 (+0200) Subject: BUG/MINOR: quic: rearm packet on packet received even non ack-eliciting X-Git-Tag: v3.5-dev10~193 X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=bb516ea002db198ff70052c16e3d374fd047e2e0;p=haproxy.git BUG/MINOR: quic: rearm packet on packet received even non ack-eliciting QUIC idle timeout must be refreshed for each valid packet received. Previously, this was only performed for ack-eliciting packets. In case the client only emit non ack-eliciting frames, the connection would be closed despite being still active. Fix idle timeout mechanism by calling qc_idle_timer_rearm() on every packets, outside of QUIC_FL_RX_PACKET_ACK_ELICITING flag. As previously, in case of an ack-eliciting packet, both idle and ack expire are refreshed, but the latter will be queued as it is smaller. This issue was detected with SSE running on top of an HTTP/3 connection, with the server pushing updates and the client emitting only ACKs. This should fix github issue #3534. This must be backported up to 2.6, after a period of observation. --- diff --git a/src/quic_rx.c b/src/quic_rx.c index 1bfe78fbb..c4411c9cd 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -1387,6 +1387,7 @@ int qc_treat_rx_pkts(struct quic_conn *qc) int64_t largest_pn = -1; unsigned int largest_pn_time_received = 0; struct quic_enc_level *qel, *qelbak; + int arm_ack_timer; TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc); @@ -1434,16 +1435,17 @@ int qc_treat_rx_pkts(struct quic_conn *qc) HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); } + arm_ack_timer = 0; + /* Update the list of ranges to acknowledge. */ if (quic_update_ack_ranges_list(qc, &qel->pktns->rx.arngs, &ar)) { if (pkt->flags & QUIC_FL_RX_PACKET_ACK_ELICITING) { - int arm_ack_timer = - qc->state >= QUIC_HS_ST_COMPLETE && - qel->pktns == qc->apktns; + arm_ack_timer = + qc->state >= QUIC_HS_ST_COMPLETE && + qel->pktns == qc->apktns; qel->pktns->flags |= QUIC_FL_PKTNS_ACK_REQUIRED; qel->pktns->rx.nb_aepkts_since_last_ack++; - qc_idle_timer_rearm(qc, 1, arm_ack_timer); } if (pkt->pn > largest_pn) { @@ -1455,6 +1457,13 @@ int qc_treat_rx_pkts(struct quic_conn *qc) TRACE_ERROR("Could not update ack range list", QUIC_EV_CONN_RXPKT, qc); } + + /* RFC 9000 10.1. Idle Timeout + * + * An endpoint restarts its idle timer when a packet from its peer is + * received and processed successfully. + */ + qc_idle_timer_rearm(qc, 1, arm_ack_timer); } } node = eb64_next(node);