Skip to main content

moq_noq_proto/connection/
mod.rs

1use std::{
2    cmp,
3    collections::{BTreeMap, VecDeque, btree_map},
4    convert::TryFrom,
5    fmt, io, mem,
6    net::SocketAddr,
7    num::{NonZeroU32, NonZeroUsize},
8    sync::Arc,
9};
10
11use bytes::{Bytes, BytesMut};
12use frame::StreamMetaVec;
13
14use rand::{RngExt, SeedableRng, rngs::StdRng};
15use rustc_hash::FxHashMap;
16use thiserror::Error;
17use tracing::{debug, error, trace, trace_span, warn};
18
19use crate::{
20    Dir, Duration, EndpointConfig, FourTuple, Frame, INITIAL_MTU, Instant, MAX_CID_SIZE,
21    MAX_STREAM_COUNT, MIN_INITIAL_SIZE, Side, StreamId, TIMER_GRANULARITY, TokenStore, Transmit,
22    TransportError, TransportErrorCode, VarInt,
23    cid_generator::ConnectionIdGenerator,
24    cid_queue::CidQueue,
25    config::{ServerConfig, TransportConfig},
26    congestion::{Controller, PacketId},
27    connection::{
28        paths::PathRetransmits,
29        qlog::{QlogRecvPacket, QlogSink},
30        spaces::LostPacket,
31        stats::PathStatsMap,
32        timer::{ConnTimer, PathTimer},
33    },
34    crypto::{self, Keys},
35    frame::{
36        self, Close, DataBlocked, Datagram, FrameStruct, NewToken, ObservedAddr, StreamDataBlocked,
37        StreamsBlocked,
38    },
39    n0_nat_traversal,
40    packet::{
41        FixedLengthConnectionIdParser, Header, InitialHeader, InitialPacket, LongType, Packet,
42        PacketNumber, PartialDecode, SpaceId,
43    },
44    range_set::ArrayRangeSet,
45    shared::{
46        ConnectionEvent, ConnectionEventInner, ConnectionId, DatagramConnectionEvent, EcnCodepoint,
47        EndpointEvent, EndpointEventInner,
48    },
49    token::{ResetToken, Token, TokenPayload},
50    transport_parameters::TransportParameters,
51};
52
53mod ack_frequency;
54use ack_frequency::AckFrequencyState;
55
56mod assembler;
57pub use assembler::Chunk;
58
59mod cid_state;
60use cid_state::CidState;
61
62mod datagrams;
63use datagrams::DatagramState;
64pub use datagrams::{Datagrams, SendDatagramError};
65
66mod mtud;
67mod pacing;
68
69mod packet_builder;
70use packet_builder::{PacketBuilder, PadDatagram};
71
72mod packet_crypto;
73use packet_crypto::CryptoState;
74pub(crate) use packet_crypto::EncryptionLevel;
75
76mod paths;
77pub use paths::{
78    ClosedPath, PathAbandonReason, PathEvent, PathId, PathStatus, RttEstimator, SetPathStatusError,
79};
80use paths::{PathData, PathState};
81
82pub(crate) mod qlog;
83pub(crate) mod send_buffer;
84
85pub(crate) mod spaces;
86#[cfg(fuzzing)]
87pub use spaces::Retransmits;
88#[cfg(not(fuzzing))]
89use spaces::Retransmits;
90pub use spaces::SpaceKind;
91use spaces::{OpenStatus, PacketSpace, SendableFrames, SentPacket, ThinRetransmits};
92
93mod stats;
94pub use stats::{ConnectionStats, FrameStats, PathStats, UdpStats};
95
96mod streams;
97#[cfg(fuzzing)]
98pub use streams::StreamsState;
99#[cfg(not(fuzzing))]
100use streams::StreamsState;
101pub use streams::{
102    Chunks, ClosedStream, FinishError, ReadError, ReadableError, RecvStream, SendStream,
103    ShouldTransmit, StreamEvent, Streams, WriteError,
104};
105
106pub(crate) mod timer;
107use timer::{Timer, TimerTable};
108
109mod transmit_buf;
110use transmit_buf::TransmitBuf;
111
112mod state;
113
114#[cfg(not(fuzzing))]
115use state::State;
116#[cfg(fuzzing)]
117pub use state::State;
118use state::StateType;
119
120/// Protocol state and logic for a single QUIC connection
121///
122/// Objects of this type receive [`ConnectionEvent`]s and emit [`EndpointEvent`]s and application
123/// [`Event`]s to make progress. To handle timeouts, a `Connection` returns timer updates and
124/// expects timeouts through various methods. A number of simple getter methods are exposed
125/// to allow callers to inspect some of the connection state.
126///
127/// `Connection` has roughly 4 types of methods:
128///
129/// - A. Simple getters, taking `&self`
130/// - B. Handlers for incoming events from the network or system, named `handle_*`.
131/// - C. State machine mutators, for incoming commands from the application. For convenience we
132///   refer to this as "performing I/O" below, however as per the design of this library none of the
133///   functions actually perform system-level I/O. For example, [`read`](RecvStream::read) and
134///   [`write`](SendStream::write), but also things like [`reset`](SendStream::reset).
135/// - D. Polling functions for outgoing events or actions for the caller to take, named `poll_*`.
136///
137/// The simplest way to use this API correctly is to call (B) and (C) whenever
138/// appropriate, then after each of those calls, as soon as feasible call all
139/// polling methods (D) and deal with their outputs appropriately, e.g. by
140/// passing it to the application or by making a system-level I/O call. You
141/// should call the polling functions in this order:
142///
143/// 1. [`poll_transmit`](Self::poll_transmit)
144/// 2. [`poll_timeout`](Self::poll_timeout)
145/// 3. [`poll_endpoint_events`](Self::poll_endpoint_events)
146/// 4. [`poll`](Self::poll)
147///
148/// Currently the only actual dependency is from (2) to (1), however additional
149/// dependencies may be added in future, so the above order is recommended.
150///
151/// (A) may be called whenever desired.
152///
153/// Care should be made to ensure that the input events represent monotonically
154/// increasing time. Specifically, calling [`handle_timeout`](Self::handle_timeout)
155/// with events of the same [`Instant`] may be interleaved in any order with a
156/// call to [`handle_event`](Self::handle_event) at that same instant; however
157/// events or timeouts with different instants must not be interleaved.
158pub struct Connection {
159    endpoint_config: Arc<EndpointConfig>,
160    config: Arc<TransportConfig>,
161    rng: StdRng,
162    /// Consolidated cryptographic state
163    crypto_state: CryptoState,
164    /// The CID we initially chose, for use during the handshake
165    handshake_cid: ConnectionId,
166    /// The CID the peer initially chose, for use during the handshake
167    remote_handshake_cid: ConnectionId,
168    /// The [`PathData`] for each path
169    ///
170    /// This needs to be ordered because [`Connection::poll_transmit`] needs to
171    /// deterministically select the next PathId to send on.
172    // TODO(flub): well does it really? But deterministic is nice for now.
173    paths: BTreeMap<PathId, PathState>,
174    /// Counter to uniquely identify every [`PathData`] created in this connection.
175    ///
176    /// Each [`PathData`] gets a [`PathData::generation`] that is unique among all
177    /// [`PathData`]s created in the lifetime of this connection. This helps identify the
178    /// correct path when RFC9000-style migrations happen, even when they are
179    /// aborted.
180    ///
181    /// Multipath does not change this, each path can also undergo RFC9000-style
182    /// migrations. So a single multipath path ID could see several [`PathData`]s each with
183    /// their unique [`PathData::generation].
184    path_generation_counter: u64,
185    /// Whether MTU detection is supported in this environment
186    allow_mtud: bool,
187    state: State,
188    side: ConnectionSide,
189    /// Transport parameters set by the peer
190    peer_params: TransportParameters,
191    /// Source ConnectionId of the first packet received from the peer
192    original_remote_cid: ConnectionId,
193    /// Destination ConnectionId sent by the client on the first Initial
194    initial_dst_cid: ConnectionId,
195    /// The value that the server included in the Source Connection ID field of a Retry packet, if
196    /// one was received
197    retry_src_cid: Option<ConnectionId>,
198    /// Events returned by [`Connection::poll`]
199    events: VecDeque<Event>,
200    endpoint_events: VecDeque<EndpointEventInner>,
201    /// Whether the spin bit is in use for this connection
202    spin_enabled: bool,
203    /// Outgoing spin bit state
204    spin: bool,
205    /// Packet number spaces: initial, handshake, 1-RTT
206    spaces: [PacketSpace; 3],
207    /// Highest usable packet space.
208    highest_space: SpaceKind,
209    /// Negotiated idle timeout
210    idle_timeout: Option<Duration>,
211    timers: TimerTable,
212    /// Number of packets received which could not be authenticated
213    authentication_failures: u64,
214
215    //
216    // Queued non-retransmittable 1-RTT data
217    /// If the CONNECTION_CLOSE frame needs to be sent
218    connection_close_pending: bool,
219
220    //
221    // ACK frequency
222    ack_frequency: AckFrequencyState,
223
224    //
225    // Congestion Control
226    /// Whether the most recently received packet had an ECN codepoint set
227    receiving_ecn: bool,
228    /// Number of packets authenticated
229    total_authed_packets: u64,
230
231    //
232    // ObservedAddr
233    /// Sequence number for the next observed address frame sent to the peer.
234    next_observed_addr_seq_no: VarInt,
235
236    streams: StreamsState,
237    /// Active and surplus CIDs issued by the remote, for future use on new paths.
238    ///
239    /// These are given out before multiple paths exist, also for paths that will never
240    /// exist.  So if multipath is supported the number of paths here will be higher than
241    /// the actual number of paths in use.
242    remote_cids: FxHashMap<PathId, CidQueue>,
243    /// Attributes of CIDs generated by local endpoint
244    ///
245    /// Any path that is allowed to be opened is present in this map, as well as the already
246    /// opened paths. However since CIDs are issued async by the endpoint driver via
247    /// connection events it can not be used to know if CIDs have been issued for a path or
248    /// not. See [`Connection::max_path_id_with_cids`] for this.
249    local_cid_state: FxHashMap<PathId, CidState>,
250    /// State of the unreliable datagram extension
251    datagrams: DatagramState,
252    /// Path level statistics.
253    path_stats: PathStatsMap,
254    /// Accumulated stats of all discarded paths.
255    ///
256    /// The connection-level stats returned by [`Self::stats`] are the sum of the stats of
257    /// all the paths. However once a path is discarded it gets added to this field instead
258    /// so we do not have to keep an ever growing number of paths stats in memory.
259    partial_stats: ConnectionStats,
260    /// QUIC version used for the connection.
261    version: u32,
262
263    //
264    // Multipath
265    /// Maximum number of concurrent paths
266    ///
267    /// Initially set from the [`TransportConfig::max_concurrent_multipath_paths`]. Even
268    /// when multipath is disabled this will be set to 1, it is not used in that case
269    /// though.
270    max_concurrent_paths: NonZeroU32,
271    /// Local maximum [`PathId`] to be used
272    ///
273    /// This is initially set to [`TransportConfig::get_initial_max_path_id`] when multipath
274    /// is negotiated, or to [`PathId::ZERO`] otherwise. This is essentially the value of
275    /// the highest MAX_PATH_ID frame sent.
276    ///
277    /// Any path with an ID equal or below this [`PathId`] is either:
278    ///
279    /// - Abandoned, if it is also in [`Connection::abandoned_paths`].
280    /// - Open, in this case it is present in [`Connection::paths`]
281    /// - Not yet opened, if it is in neither of these two places.
282    ///
283    /// Note that for not-yet-open there may or may not be any CIDs issued. See
284    /// [`Connection::max_path_id_with_cids`].
285    local_max_path_id: PathId,
286    /// Remote's maximum [`PathId`] to be used
287    ///
288    /// This is initially set to the peer's [`TransportParameters::initial_max_path_id`] when
289    /// multipath is negotiated, or to [`PathId::ZERO`] otherwise. A peer may increase this limit
290    /// by sending [`Frame::MaxPathId`] frames.
291    remote_max_path_id: PathId,
292    /// The greatest [`PathId`] we have issued CIDs for
293    ///
294    /// CIDs are only issued for `min(local_max_path_id, remote_max_path_id)`. It is not
295    /// possible to use [`Connection::local_cid_state`] to know if CIDs have been issued
296    /// since they are issued asynchronously by the endpoint driver.
297    max_path_id_with_cids: PathId,
298    /// The paths already abandoned
299    ///
300    /// They may still have some state left in [`Connection::paths`] or
301    /// [`Connection::local_cid_state`] since some of this has to be kept around for some
302    /// time after a path is abandoned.
303    abandoned_paths: AbandonedPaths,
304
305    /// State for n0's (<https://n0.computer>) nat traversal protocol.
306    n0_nat_traversal: n0_nat_traversal::State,
307    qlog: QlogSink,
308}
309
310impl Connection {
311    pub(crate) fn new(
312        endpoint_config: Arc<EndpointConfig>,
313        config: Arc<TransportConfig>,
314        init_cid: ConnectionId,
315        local_cid: ConnectionId,
316        remote_cid: ConnectionId,
317        network_path: FourTuple,
318        crypto: Box<dyn crypto::Session>,
319        cid_gen: &dyn ConnectionIdGenerator,
320        now: Instant,
321        version: u32,
322        allow_mtud: bool,
323        rng_seed: [u8; 32],
324        side_args: SideArgs,
325        qlog: QlogSink,
326    ) -> Self {
327        let pref_addr_cid = side_args.pref_addr_cid();
328        let path_validated = side_args.path_validated();
329        let connection_side = ConnectionSide::from(side_args);
330        let side = connection_side.side();
331        let mut rng = StdRng::from_seed(rng_seed);
332        let mut initial_space = PacketSpace::new(now, SpaceId::Initial, &mut rng);
333        let mut handshake_space = PacketSpace::new(now, SpaceId::Handshake, &mut rng);
334        #[cfg(test)]
335        let mut data_space = match config.deterministic_packet_numbers {
336            true => PacketSpace::new_deterministic(now, SpaceId::Data),
337            false => PacketSpace::new(now, SpaceId::Data, &mut rng),
338        };
339        #[cfg(not(test))]
340        let mut data_space = PacketSpace::new(now, SpaceId::Data, &mut rng);
341
342        // The spaces for PathId::ZERO do not need the PathEvent::Established event.
343        initial_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
344        handshake_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
345        data_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
346
347        let state = State::handshake(state::Handshake {
348            remote_cid_set: side.is_server(),
349            expected_token: Bytes::new(),
350            client_hello: None,
351            allow_server_migration: side.is_client() && config.server_handshake_migration,
352        });
353        let local_cid_state = FxHashMap::from_iter([(
354            PathId::ZERO,
355            CidState::new(
356                cid_gen.cid_len(),
357                cid_gen.cid_lifetime(),
358                now,
359                if pref_addr_cid.is_some() { 2 } else { 1 },
360            ),
361        )]);
362
363        let mut this = Self {
364            endpoint_config,
365            crypto_state: CryptoState::new(crypto, init_cid, side, &mut rng),
366            handshake_cid: local_cid,
367            remote_handshake_cid: remote_cid,
368            local_cid_state,
369            paths: BTreeMap::from_iter([(
370                PathId::ZERO,
371                PathState {
372                    data: PathData::new(network_path, allow_mtud, None, 0, now, &config),
373                    prev: None,
374                },
375            )]),
376            path_generation_counter: 0,
377            allow_mtud,
378            state,
379            side: connection_side,
380            peer_params: TransportParameters::default(),
381            original_remote_cid: remote_cid,
382            initial_dst_cid: init_cid,
383            retry_src_cid: None,
384            events: VecDeque::new(),
385            endpoint_events: VecDeque::new(),
386            spin_enabled: config.allow_spin && rng.random_ratio(7, 8),
387            spin: false,
388            spaces: [initial_space, handshake_space, data_space],
389            highest_space: SpaceKind::Initial,
390            idle_timeout: match config.max_idle_timeout {
391                None | Some(VarInt(0)) => None,
392                Some(dur) => Some(Duration::from_millis(dur.0)),
393            },
394            timers: TimerTable::default(),
395            authentication_failures: 0,
396            connection_close_pending: false,
397
398            ack_frequency: AckFrequencyState::new(get_max_ack_delay(
399                &TransportParameters::default(),
400            )),
401
402            receiving_ecn: false,
403            total_authed_packets: 0,
404
405            next_observed_addr_seq_no: 0u32.into(),
406
407            streams: StreamsState::new(
408                side,
409                config.max_concurrent_uni_streams,
410                config.max_concurrent_bidi_streams,
411                config.send_window,
412                config.receive_window,
413                config.stream_receive_window,
414            ),
415            datagrams: DatagramState::default(),
416            config,
417            remote_cids: FxHashMap::from_iter([(PathId::ZERO, CidQueue::new(remote_cid))]),
418            rng,
419            path_stats: Default::default(),
420            partial_stats: ConnectionStats::default(),
421            version,
422
423            // peer params are not yet known, so multipath is not enabled
424            max_concurrent_paths: NonZeroU32::MIN,
425            local_max_path_id: PathId::ZERO,
426            remote_max_path_id: PathId::ZERO,
427            max_path_id_with_cids: PathId::ZERO,
428            abandoned_paths: Default::default(),
429
430            n0_nat_traversal: Default::default(),
431            qlog,
432        };
433        if path_validated {
434            this.on_path_validated(PathId::ZERO);
435        }
436        if side.is_client() {
437            // Kick off the connection
438            this.write_crypto();
439            this.init_0rtt(now);
440        }
441        this.qlog
442            .emit_tuple_assigned(PathId::ZERO, network_path, now);
443        this
444    }
445
446    /// Returns the next time at which `handle_timeout` should be called
447    ///
448    /// The value returned may change after:
449    /// - the application performed some I/O on the connection
450    /// - a call was made to `handle_event`
451    /// - a call to `poll_transmit` returned `Some`
452    /// - a call was made to `handle_timeout`
453    #[must_use]
454    pub fn poll_timeout(&self) -> Option<Instant> {
455        self.timers.peek()
456    }
457
458    /// Returns the instant at which `timer` is armed to fire, or `None` if it is not.
459    ///
460    /// `None` covers the timer never having been armed, having fired, and having been
461    /// cancelled.
462    #[cfg(test)]
463    pub(crate) fn timer_pending(&self, timer: Timer) -> Option<Instant> {
464        self.timers.get(timer)
465    }
466
467    /// Returns application-facing events
468    ///
469    /// Connections should be polled for events after:
470    /// - a call was made to `handle_event`
471    /// - a call was made to `handle_timeout`
472    #[must_use]
473    pub fn poll(&mut self) -> Option<Event> {
474        if let Some(x) = self.events.pop_front() {
475            return Some(x);
476        }
477
478        if let Some(event) = self.streams.poll() {
479            return Some(Event::Stream(event));
480        }
481
482        if let Some(reason) = self.state.take_error() {
483            return Some(Event::ConnectionLost { reason });
484        }
485
486        None
487    }
488
489    /// Return endpoint-facing events
490    #[must_use]
491    pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent> {
492        self.endpoint_events.pop_front().map(EndpointEvent)
493    }
494
495    /// Provide control over streams
496    #[must_use]
497    pub fn streams(&mut self) -> Streams<'_> {
498        Streams {
499            state: &mut self.streams,
500            conn_state: &self.state,
501        }
502    }
503
504    /// Provide control over streams
505    #[must_use]
506    pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_> {
507        assert!(id.dir() == Dir::Bi || id.initiator() != self.side.side());
508        RecvStream {
509            id,
510            state: &mut self.streams,
511            pending: &mut self.spaces[SpaceId::Data].pending,
512        }
513    }
514
515    /// Provide control over streams
516    #[must_use]
517    pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_> {
518        assert!(id.dir() == Dir::Bi || id.initiator() == self.side.side());
519        SendStream {
520            id,
521            state: &mut self.streams,
522            pending: &mut self.spaces[SpaceId::Data].pending,
523            conn_state: &self.state,
524        }
525    }
526
527    /// Opens a new path only if no path on the same network path currently exists.
528    ///
529    /// Returns `(path_id, true)` if the path already existed, or `(path_id, false)`
530    /// if was opened.
531    ///
532    /// If `network_path` has no local IP set, then this will open a new path
533    /// if no path exists for this remote address, independent of the existing
534    /// path's local IP. If a local IP is set, it will match against the full
535    /// four-tuple of existing paths. Not setting the local IP avoids having to
536    /// guess which local interface will be used to communicate with the remote,
537    /// should it not be known yet. We assume that if we already have a path to
538    /// the remote, the OS is likely to use the same interface to talk to said remote.
539    ///
540    /// See also [`open_path`].
541    ///
542    /// [`open_path`]: Connection::open_path
543    pub fn open_path_ensure(
544        &mut self,
545        network_path: FourTuple,
546        initial_status: PathStatus,
547        now: Instant,
548    ) -> Result<(PathId, bool), PathError> {
549        let existing_open_path = self.paths.iter().find(|(id, path)| {
550            network_path.is_probably_same_path(&path.data.network_path)
551                && !self.abandoned_paths.contains(id)
552        });
553        match existing_open_path {
554            Some((path_id, _state)) => Ok((*path_id, true)),
555            None => Ok((self.open_path(network_path, initial_status, now)?, false)),
556        }
557    }
558
559    /// Opens a new path.
560    ///
561    /// Further errors might occur and they will be emitted in [`PathEvent::Abandoned`]
562    /// events with this path id.  Once the path is opened and can carry application data it
563    /// will be reported using a [`PathEvent::Established`] event.
564    pub fn open_path(
565        &mut self,
566        network_path: FourTuple,
567        initial_status: PathStatus,
568        now: Instant,
569    ) -> Result<PathId, PathError> {
570        let Some(max_path_id) = self.max_path_id() else {
571            return Err(PathError::MultipathNotNegotiated);
572        };
573        if self.side().is_server() {
574            return Err(PathError::ServerSideNotAllowed);
575        }
576
577        let max_abandoned = self.abandoned_paths.max();
578        let max_used = self.paths.keys().last().copied();
579        let path_id = max_abandoned
580            .max(max_used)
581            .unwrap_or(PathId::ZERO)
582            .saturating_add(1u8);
583
584        if path_id > max_path_id {
585            self.spaces[SpaceId::Data].pending.paths_blocked = Some(self.remote_max_path_id);
586            return Err(PathError::MaxPathIdReached);
587        }
588        if !self.remote_cids.contains_key(&path_id) {
589            self.spaces[SpaceId::Data]
590                .pending
591                .path_cids_blocked
592                .insert(path_id, VarInt(0));
593            return Err(PathError::RemoteCidsExhausted);
594        }
595
596        let path = self.create_path(path_id, network_path, now, None);
597        path.status.local_update(initial_status);
598
599        Ok(path_id)
600    }
601
602    /// Closes a path and sends a PATH_ABANDON frame with the passed error code.
603    ///
604    /// Returns [`ClosePathError::LastOpenPath`] if this is the last open path.
605    /// It does allow closing paths which have not yet been opened, as e.g. is the case
606    /// when receiving a PATH_ABANDON from the peer for a path that was never opened locally.
607    pub fn close_path(
608        &mut self,
609        now: Instant,
610        path_id: PathId,
611        error_code: VarInt,
612    ) -> Result<(), ClosePathError> {
613        self.close_path_inner(
614            now,
615            path_id,
616            PathAbandonReason::ApplicationClosed { error_code },
617        )
618    }
619
620    /// Closes a path and sends a PATH_ABANDON frame.
621    ///
622    /// Other than [`Self::close_path`] this allows to specify the reason for the path being closed.
623    /// Internally, this should be used over [`Self::close_path`].
624    pub(crate) fn close_path_inner(
625        &mut self,
626        now: Instant,
627        path_id: PathId,
628        reason: PathAbandonReason,
629    ) -> Result<(), ClosePathError> {
630        if self.state.is_drained() {
631            return Ok(());
632        }
633
634        if !self.is_multipath_negotiated() {
635            return Err(ClosePathError::MultipathNotNegotiated);
636        }
637        if self.abandoned_paths.contains(&path_id)
638            || Some(path_id) > self.max_path_id()
639            || !self.paths.contains_key(&path_id)
640        {
641            return Err(ClosePathError::ClosedPath);
642        }
643
644        let is_last_path = !self
645            .paths
646            .keys()
647            .any(|id| *id != path_id && !self.abandoned_paths.contains(id));
648
649        if is_last_path && !reason.is_remote() {
650            return Err(ClosePathError::LastOpenPath);
651        }
652
653        self.abandon_path(now, path_id, reason);
654
655        // When the remote abandons our last path, start a grace timer to allow
656        // the application to open a replacement path.
657        // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4-8
658        if is_last_path {
659            // The spec suggests 1 PTO, but we use 3 * PTO to account for
660            // packet loss when opening a replacement path. Uses initial RTT
661            // since the abandoned path's RTT estimate is no longer valid.
662            let rtt = RttEstimator::new(self.config.initial_rtt);
663            let pto = rtt.pto_base() + self.ack_frequency.max_ack_delay_for_pto();
664            let grace = pto * 3;
665            self.timers.set(
666                Timer::Conn(ConnTimer::NoAvailablePath),
667                now + grace,
668                self.qlog.with_time(now),
669            );
670        }
671
672        Ok(())
673    }
674
675    /// Unconditionally abandon a path.
676    ///
677    /// Only to be called once sure this path should be abandoned, all checks
678    /// should have happened before calling this.
679    fn abandon_path(&mut self, now: Instant, path_id: PathId, reason: PathAbandonReason) {
680        trace!(%path_id, ?reason, "abandoning path");
681
682        let pending_space = &mut self.spaces[SpaceId::Data].pending;
683        // Send PATH_ABANDON
684        pending_space
685            .path_abandon
686            .insert(path_id, reason.error_code());
687
688        // Remove pending NEW CIDs for this path
689        pending_space.new_cids.retain(|cid| cid.path_id != path_id);
690        pending_space.path_status.retain(|&id| id != path_id);
691
692        // Cleanup retransmits across ALL paths (CIDs for path_id may have been transmitted on other
693        // paths)
694        for space in self.spaces[SpaceId::Data].iter_paths_mut() {
695            for sent_packet in space.sent_packets.values_mut() {
696                if let Some(retransmits) = sent_packet.retransmits.get_mut() {
697                    retransmits.new_cids.retain(|cid| cid.path_id != path_id);
698                    retransmits.path_status.retain(|&id| id != path_id);
699                }
700            }
701        }
702
703        // We can't send anything on abandoned paths, so we set
704        // tail-loss probes to zero.
705        // This likely doesn't do much, as the path won't even be tried for sending
706        // in poll_transmit after the path is abandoned.
707        self.spaces[SpaceId::Data].for_path(path_id).loss_probes = 0;
708
709        // Note: remote CIDs are NOT removed here. They are removed when the PATH_ABANDON
710        // frame is actually written to a packet (in populate_packet). This allows sending
711        // PATH_ABANDON on the abandoned path itself when no other path exists (#509).
712        debug_assert!(!self.state.is_drained()); // requirement for endpoint_events, checked in `close_path_inner`
713        self.endpoint_events
714            .push_back(EndpointEventInner::RetireResetToken(path_id));
715
716        self.abandoned_paths.insert(path_id);
717
718        for timer in PathTimer::VALUES {
719            // match for completeness
720            let keep_timer = match timer {
721                // These timers deal with sending and receiving PATH_CHALLENGE and
722                // PATH_RESPONSE, but now that the path is abandoned, we no longer care about
723                // these frames or their timing
724                PathTimer::PathValidationFailed | PathTimer::PathChallengeLost => false,
725                // These timers deal with the lifetime of the path. Now that the path is abandoned,
726                // these are not relevant.
727                PathTimer::PathKeepAlive | PathTimer::PathIdle => false,
728                // The path has already been informed that outstanding acks should be sent
729                // immediately
730                PathTimer::MaxAckDelay => false,
731                // This timer should not be set, for completeness it's not kept as it's set when
732                // the PATH_ABANDON frame is sent.
733                PathTimer::PathDrained => false,
734                // Sent packets still need to be identified as lost to trigger timely
735                // retransmission.
736                PathTimer::LossDetection => true,
737                // This path should not be used for sending after the PATH_ABANDON frame is sent.
738                // However, any outstanding data that should be sent before PATH_ABANDON, should
739                // still respect pacing.
740                PathTimer::Pacing => true,
741            };
742
743            if !keep_timer {
744                let qlog = self.qlog.with_time(now);
745                self.timers.stop(Timer::PerPath(path_id, timer), qlog);
746            }
747        }
748
749        // Set the loss detection timer again, as now it should only be set
750        // for time-based loss detection, not tail-loss probes, but currently it
751        // could still be set to a tail-loss probe.
752        // This will reset it to the next time-based loss time, if applicable.
753        self.set_loss_detection_timer(now, path_id);
754
755        // Emit event to the application.
756        self.events.push_back(Event::Path(PathEvent::Abandoned {
757            id: path_id,
758            reason,
759        }));
760    }
761
762    /// Gets the [`PathData`] for a known [`PathId`].
763    ///
764    /// Will panic if the path_id does not reference any known path.
765    #[track_caller]
766    fn path_data(&self, path_id: PathId) -> &PathData {
767        if let Some(data) = self.paths.get(&path_id) {
768            &data.data
769        } else {
770            panic!(
771                "unknown path: {path_id}, currently known paths: {:?}",
772                self.paths.keys().collect::<Vec<_>>()
773            );
774        }
775    }
776
777    /// Gets the [`PathData`] for a known [`PathId`].
778    ///
779    /// Will panic if the path_id does not reference any known path.
780    #[track_caller]
781    fn path_data_mut(&mut self, path_id: PathId) -> &mut PathData {
782        &mut self.paths.get_mut(&path_id).expect("known path").data
783    }
784
785    /// Gets a reference to the [`PathData`] for a [`PathId`]
786    fn path(&self, path_id: PathId) -> Option<&PathData> {
787        self.paths.get(&path_id).map(|path_state| &path_state.data)
788    }
789
790    /// Gets a mutable reference to the [`PathData`] for a [`PathId`]
791    fn path_mut(&mut self, path_id: PathId) -> Option<&mut PathData> {
792        self.paths
793            .get_mut(&path_id)
794            .map(|path_state| &mut path_state.data)
795    }
796
797    /// Returns all known paths.
798    ///
799    /// There is no guarantee any of these paths are open or usable.
800    pub fn paths(&self) -> Vec<PathId> {
801        self.paths.keys().copied().collect()
802    }
803
804    /// Gets the local [`PathStatus`] for a known [`PathId`]
805    pub fn path_status(&self, path_id: PathId) -> Result<PathStatus, ClosedPath> {
806        self.path(path_id)
807            .map(PathData::local_status)
808            .ok_or(ClosedPath { _private: () })
809    }
810
811    /// Returns the path's network path represented as a 4-tuple.
812    pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath> {
813        self.path(path_id)
814            .map(|path| path.network_path)
815            .ok_or(ClosedPath { _private: () })
816    }
817
818    /// Sets the [`PathStatus`] for a known [`PathId`]
819    ///
820    /// Returns the previous path status on success.
821    pub fn set_path_status(
822        &mut self,
823        path_id: PathId,
824        status: PathStatus,
825    ) -> Result<PathStatus, SetPathStatusError> {
826        if !self.is_multipath_negotiated() {
827            return Err(SetPathStatusError::MultipathNotNegotiated);
828        }
829        let path = self
830            .path_mut(path_id)
831            .ok_or(SetPathStatusError::ClosedPath)?;
832        let prev = match path.status.local_update(status) {
833            Some(prev) => {
834                self.spaces[SpaceId::Data]
835                    .pending
836                    .path_status
837                    .insert(path_id);
838                prev
839            }
840            None => path.local_status(),
841        };
842        Ok(prev)
843    }
844
845    /// Returns the remote path status
846    // TODO(flub): Probably should also be some kind of path event?  Not even sure if I like
847    //    this as an API, but for now it allows me to write a test easily.
848    // TODO(flub): Technically this should be a Result<Option<PathSTatus>>?
849    pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus> {
850        self.path(path_id).and_then(|path| path.remote_status())
851    }
852
853    /// Sets the max_idle_timeout for a specific path.
854    ///
855    /// If `Some`, the path idle timer is immediately re-armed. Setting `None` disables the timeout
856    /// and stops the timer.
857    ///
858    /// See [`TransportConfig::default_path_max_idle_timeout`] for details.
859    ///
860    /// Returns the previous value of the setting.
861    pub fn set_path_max_idle_timeout(
862        &mut self,
863        now: Instant,
864        path_id: PathId,
865        timeout: Option<Duration>,
866    ) -> Result<Option<Duration>, ClosedPath> {
867        let path = self
868            .paths
869            .get_mut(&path_id)
870            .ok_or(ClosedPath { _private: () })?;
871        let prev_timeout = mem::replace(&mut path.data.idle_timeout, timeout);
872
873        // The expiration instant of the timer should generally be computed from the last time the
874        // path was active. This reference instance is, however, not possible to be recovered.
875        // Previous attempts used the expiration instant and previous setting to get a "last
876        // activity" instant. Since the timer is extended to 3*PTO to prevent very small timeouts,
877        // it's likely that the computed value was in the future, and instead of accounting for
878        // elapsed idle time, it further extended the timer. Then, for consistency, we simply choose
879        // to compute the timer expiration in the same way as if the path had been immediately used.
880        self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
881
882        Ok(prev_timeout)
883    }
884
885    /// Rearms or stops the state of the [`PathTimer::PathIdle`] based on the configured value in
886    /// [`PathData::idle_timeout`].
887    ///
888    /// The timer is extended to 3*PTO if such value is greater than the configured timeout,
889    /// applying the guidance of RFC9000 §10.1 to multipaths.
890    ///
891    /// The timer only applies for non-closed, multiplath-negotiated connections.
892    fn rearm_path_max_idle_timer(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
893        let timer = Timer::PerPath(path_id, PathTimer::PathIdle);
894
895        if self.state.is_closed() || !self.is_multipath_negotiated() {
896            return self.timers.stop(timer, self.qlog.with_time(now));
897        }
898
899        if let Some(timeout) = self.path_data(path_id).idle_timeout {
900            let dt = cmp::max(timeout, 3 * self.pto(space, path_id));
901            self.timers.set(timer, now + dt, self.qlog.with_time(now));
902        } else {
903            self.timers.stop(timer, self.qlog.with_time(now));
904        }
905    }
906
907    /// Sets the keep_alive_interval for a specific path
908    ///
909    /// See [`TransportConfig::default_path_keep_alive_interval`] for details.
910    ///
911    /// Returns the previous value of the setting.
912    pub fn set_path_keep_alive_interval(
913        &mut self,
914        path_id: PathId,
915        interval: Option<Duration>,
916    ) -> Result<Option<Duration>, ClosedPath> {
917        let path = self
918            .paths
919            .get_mut(&path_id)
920            .ok_or(ClosedPath { _private: () })?;
921        Ok(mem::replace(&mut path.data.keep_alive, interval))
922    }
923
924    /// Find an open, validated path that's on the same network path as the given network path.
925    ///
926    /// Returns the first path matching, even if there's multiple.
927    fn find_validated_path_on_network_path(
928        &self,
929        network_path: FourTuple,
930    ) -> Option<(&PathId, &PathState)> {
931        self.paths.iter().find(|(path_id, path_state)| {
932            path_state.data.validated
933                // Would this use the same network path, if network_path were used to send right now?
934                && network_path.is_probably_same_path(&path_state.data.network_path)
935                && !self.abandoned_paths.contains(path_id)
936        })
937        // TODO(@divma): we might want to ensure the path has been recently active to consider the
938        // address validated
939        // matheus23: Perhaps looking at !self.abandoned_paths.contains(path_id) is enough, given
940        // keep-alives?
941    }
942
943    /// Creates the [`PathData`] for a new [`PathId`].
944    ///
945    /// Called for incoming packets as well as when opening a new path locally.
946    fn create_path(
947        &mut self,
948        path_id: PathId,
949        network_path: FourTuple,
950        now: Instant,
951        pn: Option<u64>,
952    ) -> &mut PathData {
953        let valid_path = self.find_validated_path_on_network_path(network_path);
954        let validated = valid_path.is_some();
955        let initial_rtt = valid_path.map(|(_, path)| path.data.rtt.conservative());
956        let vacant_entry = match self.paths.entry(path_id) {
957            btree_map::Entry::Vacant(vacant_entry) => vacant_entry,
958            btree_map::Entry::Occupied(occupied_entry) => {
959                return &mut occupied_entry.into_mut().data;
960            }
961        };
962
963        debug!(%validated, %path_id, %network_path, "path added");
964
965        // A new path was added. Cancel any pending NoAvailablePath grace timer.
966        self.timers.stop(
967            Timer::Conn(ConnTimer::NoAvailablePath),
968            self.qlog.with_time(now),
969        );
970        let peer_max_udp_payload_size =
971            u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
972        self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
973        let mut data = PathData::new(
974            network_path,
975            self.allow_mtud,
976            Some(peer_max_udp_payload_size),
977            self.path_generation_counter,
978            now,
979            &self.config,
980        );
981
982        data.validated = validated;
983        if let Some(initial_rtt) = initial_rtt {
984            data.rtt.reset_initial_rtt(initial_rtt);
985        }
986
987        // To open a path locally we need to send a packet on the path. Sending a challenge
988        // guarantees this.
989        data.pending_challenge = true;
990        data.pending.observed_address = self
991            .config
992            .address_discovery_role
993            .should_report(&self.peer_params.address_discovery_role);
994
995        let path = vacant_entry.insert(PathState { data, prev: None });
996
997        #[cfg(test)]
998        let mut pn_space = match self.config.deterministic_packet_numbers {
999            true => spaces::PacketNumberSpace::new_deterministic(now, SpaceId::Data),
1000            false => spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng),
1001        };
1002        #[cfg(not(test))]
1003        let mut pn_space = spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng);
1004        if let Some(pn) = pn {
1005            pn_space.dedup.insert(pn);
1006        }
1007        self.spaces[SpaceId::Data]
1008            .number_spaces
1009            .insert(path_id, pn_space);
1010        self.qlog.emit_tuple_assigned(path_id, network_path, now);
1011
1012        // If the remote opened this path we may not have CIDs for it. For locally opened
1013        // paths the caller should have already made sure we have CIDs and refused to open
1014        // it if there were none.
1015        if !self.remote_cids.contains_key(&path_id) {
1016            debug!(%path_id, "Remote opened path without issuing CIDs");
1017            self.spaces[SpaceId::Data]
1018                .pending
1019                .path_cids_blocked
1020                .insert(path_id, VarInt(0));
1021            // Do not abandon this path right away. CIDs might be in-flight still and arrive
1022            // soon. It is up to the remote to handle this situation.
1023        }
1024
1025        &mut path.data
1026    }
1027
1028    /// Returns packets to transmit
1029    ///
1030    /// Connections should be polled for transmit after:
1031    /// - the application performed some I/O on the connection
1032    /// - a call was made to `handle_event`
1033    /// - a call was made to `handle_timeout`
1034    ///
1035    /// `max_datagrams` specifies how many datagrams can be returned inside a
1036    /// single Transmit using GSO. This must be at least 1.
1037    #[must_use]
1038    pub fn poll_transmit(
1039        &mut self,
1040        now: Instant,
1041        max_datagrams: NonZeroUsize,
1042        buf: &mut Vec<u8>,
1043    ) -> Option<Transmit> {
1044        let max_datagrams = match self.config.enable_segmentation_offload {
1045            false => NonZeroUsize::MIN,
1046            true => max_datagrams,
1047        };
1048
1049        // Each call to poll_transmit can only send datagrams to one destination, because
1050        // all datagrams in a GSO batch are for the same destination.  Therefore only
1051        // datagrams for one destination address are produced for each poll_transmit call.
1052
1053        // Check whether we need to send a close message
1054        let connection_close_pending = match self.state.as_type() {
1055            StateType::Drained => {
1056                for path in self.paths.values_mut() {
1057                    path.data.app_limited = true;
1058                }
1059                return None;
1060            }
1061            StateType::Draining | StateType::Closed => {
1062                // self.connection_close_pending is only reset once the associated packet
1063                // had been encoded successfully
1064                if !self.connection_close_pending {
1065                    for path in self.paths.values_mut() {
1066                        path.data.app_limited = true;
1067                    }
1068                    return None;
1069                }
1070                true
1071            }
1072            _ => false,
1073        };
1074
1075        // Schedule an ACK_FREQUENCY frame if a new one needs to be sent.
1076        if let Some(config) = &self.config.ack_frequency_config {
1077            let rtt = self
1078                .paths
1079                .values()
1080                .map(|p| p.data.rtt.get())
1081                .min()
1082                .expect("one path exists");
1083            self.spaces[SpaceId::Data].pending.ack_frequency = self
1084                .ack_frequency
1085                .should_send_ack_frequency(rtt, config, &self.peer_params)
1086                && self.highest_space == SpaceKind::Data
1087                && self.peer_supports_ack_frequency();
1088        }
1089
1090        let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1091        while let Some(path_id) = next_path_id {
1092            if !connection_close_pending
1093                && let Some(transmit) = self.poll_transmit_off_path(now, buf, path_id)
1094            {
1095                #[cfg(test)]
1096                {
1097                    self.partial_stats.transmits_tx += 1;
1098                }
1099                return Some(transmit);
1100            }
1101
1102            let info = self.scheduling_info(path_id);
1103            if let Some(transmit) = self.poll_transmit_on_path(
1104                now,
1105                buf,
1106                path_id,
1107                max_datagrams,
1108                &info,
1109                connection_close_pending,
1110            ) {
1111                #[cfg(test)]
1112                {
1113                    self.partial_stats.transmits_tx += 1;
1114                }
1115                return Some(transmit);
1116            }
1117
1118            // Continue checking other paths, tail-loss probes may need to be sent
1119            // in all spaces.
1120            debug_assert!(
1121                buf.is_empty(),
1122                "nothing to send on path but buffer not empty"
1123            );
1124
1125            next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1126        }
1127
1128        // We didn't produce any application data packet
1129        debug_assert!(
1130            buf.is_empty(),
1131            "there was data in the buffer, but it was not sent"
1132        );
1133
1134        if self.state.is_established() {
1135            // Try MTU probing now
1136            let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1137            while let Some(path_id) = next_path_id {
1138                if let Some(transmit) = self.poll_transmit_mtu_probe(now, buf, path_id) {
1139                    #[cfg(test)]
1140                    {
1141                        self.partial_stats.transmits_tx += 1;
1142                    }
1143                    return Some(transmit);
1144                }
1145                next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1146            }
1147        }
1148
1149        None
1150    }
1151
1152    /// Computes the packet scheduling information for this path.
1153    ///
1154    /// While this information is only returned for a single path, it is important to know
1155    /// that this information remains static for the entire span of a single
1156    /// [`Connection::poll_transmit`] call. In other words, the return value is purely
1157    /// functional and only depends on the [`PathId`] **during a single** `poll_transmit`
1158    /// call. It can be computed up-front for all paths but we don't do that because it
1159    /// involves an allocation.
1160    ///
1161    /// See the inline comments for how the  packet scheduling works.
1162    ///
1163    /// # Panics
1164    ///
1165    /// This will panic if called for a path for which we do not have any [`PathData`], like
1166    /// so many other functions we have. But this is the only one to document this in its
1167    /// doc comment. Maybe that should change. Eventually we'll refactor things for this
1168    /// panic to go away.
1169    fn scheduling_info(&self, path_id: PathId) -> PathSchedulingInfo {
1170        // Such a space is preferred for SpaceKind::Data frames.
1171        let have_validated_status_available_space = self.paths.iter().any(|(path_id, path)| {
1172            self.remote_cids.contains_key(path_id)
1173                && !self.abandoned_paths.contains(path_id)
1174                && path.data.validated
1175                && path.data.local_status() == PathStatus::Available
1176        });
1177
1178        // Such a space is able to send SpaceKind::Data frames.
1179        let have_validated_space = self.paths.iter().any(|(path_id, path)| {
1180            self.remote_cids.contains_key(path_id)
1181                && !self.abandoned_paths.contains(path_id)
1182                && path.data.validated
1183        });
1184
1185        let is_handshaking = self.is_handshaking();
1186        let has_cids = self.remote_cids.contains_key(&path_id);
1187        let is_abandoned = self.abandoned_paths.contains(&path_id);
1188        let path_data = self.path_data(path_id);
1189        let validated = path_data.validated;
1190        let status = path_data.local_status();
1191
1192        // This is the core packet scheduling, whether this space ID may send
1193        // SpaceKind::Data frames.
1194        let may_send_data = has_cids
1195            && !is_abandoned
1196            && if is_handshaking {
1197                // There is only one path during the handshake. We want to
1198                // already send 0-RTT and 0.5-RTT (permitting anti-amplification
1199                // limit) data.
1200                true
1201            } else if !validated {
1202                // TODO(flub): When we have a network change we might end up
1203                //    having to abandon all paths and re-open new ones to the
1204                //    same remotes. This leaves us without any validated
1205                //    path. Perhaps we should have a way to figure out if the
1206                //    path is to a previously-validated remote address and allow
1207                //    sending data to such remotes immediately.
1208                false
1209            } else {
1210                match status {
1211                    PathStatus::Available => {
1212                        // Best possible space to send data on.
1213                        true
1214                    }
1215                    PathStatus::Backup => {
1216                        // If there is a status-available path we prefer that.
1217                        !have_validated_status_available_space
1218                    }
1219                }
1220            };
1221
1222        // CONNECTION_CLOSE is allowed to be sent on a non-validated
1223        // path. Particularly during the handshake we want to send it before the
1224        // path is validated. Later if there is no validated path available we
1225        // will also accept sending it on an un-validated path.
1226        let may_send_close = has_cids
1227            && !is_abandoned
1228            && if !validated && have_validated_status_available_space {
1229                // We have a better space to send on.
1230                false
1231            } else {
1232                // No other validated space, this is as good as it gets.
1233                true
1234            };
1235
1236        // PATH_ABANDON is normally sent together with other SpaceKind::Data frames. But if
1237        // there is no other validated space to send it on, it can be sent on the path to be
1238        // abandoned itself if that was validated.
1239        let may_self_abandon = has_cids && validated && !have_validated_space;
1240
1241        PathSchedulingInfo {
1242            is_abandoned,
1243            may_send_data,
1244            may_send_close,
1245            may_self_abandon,
1246        }
1247    }
1248
1249    fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit {
1250        debug_assert!(
1251            !transmit.is_empty(),
1252            "must not be called with an empty transmit buffer"
1253        );
1254
1255        let network_path = self.path_data(path_id).network_path;
1256        trace!(
1257            segment_size = transmit.segment_size(),
1258            last_datagram_len = transmit.len() % transmit.segment_size(),
1259            %network_path,
1260            "sending {} bytes in {} datagrams",
1261            transmit.len(),
1262            transmit.num_datagrams()
1263        );
1264        self.path_data_mut(path_id)
1265            .inc_total_sent(transmit.len() as u64);
1266
1267        self.path_stats
1268            .get_mut(path_id)
1269            .udp_tx
1270            .on_sent(transmit.num_datagrams() as u64, transmit.len());
1271
1272        Transmit {
1273            destination: network_path.remote,
1274            size: transmit.len(),
1275            ecn: if self.path_data(path_id).sending_ecn {
1276                Some(EcnCodepoint::Ect0)
1277            } else {
1278                None
1279            },
1280            segment_size: match transmit.num_datagrams() {
1281                1 => None,
1282                _ => Some(transmit.segment_size()),
1283            },
1284            src_ip: network_path.local_ip,
1285        }
1286    }
1287
1288    /// poll_transmit logic for off-path data.
1289    fn poll_transmit_off_path(
1290        &mut self,
1291        now: Instant,
1292        buf: &mut Vec<u8>,
1293        path_id: PathId,
1294    ) -> Option<Transmit> {
1295        if let Some(challenge) = self.send_prev_path_challenge(now, buf, path_id) {
1296            return Some(challenge);
1297        }
1298        if let Some(response) = self.send_off_path_path_response(now, buf, path_id) {
1299            return Some(response);
1300        }
1301        if let Some(challenge) = self.send_nat_traversal_path_challenge(now, buf, path_id) {
1302            return Some(challenge);
1303        }
1304        None
1305    }
1306
1307    /// poll_transmit logic for on-path data.
1308    ///
1309    /// This is not quite the same as for a multipath packet space, since [`PathId::ZERO`]
1310    /// has 3 packet spaces, which this handles.
1311    ///
1312    /// See [`Self::poll_transmit_off_path`] for off-path data.
1313    #[must_use]
1314    fn poll_transmit_on_path(
1315        &mut self,
1316        now: Instant,
1317        buf: &mut Vec<u8>,
1318        path_id: PathId,
1319        max_datagrams: NonZeroUsize,
1320        scheduling_info: &PathSchedulingInfo,
1321        connection_close_pending: bool,
1322    ) -> Option<Transmit> {
1323        // Check if there is at least one active CID to use for sending
1324        let Some(remote_cid) = self.remote_cids.get(&path_id).map(CidQueue::active) else {
1325            if !self.abandoned_paths.contains(&path_id) {
1326                debug!(%path_id, "no remote CIDs for path");
1327            }
1328            return None;
1329        };
1330
1331        // Whether the last packet in the datagram must be padded so the datagram takes up
1332        // an exact size. An earlier space can decide to not fill an entire datagram and
1333        // require the next space to fill it further. But may need a specific size of the
1334        // datagram containing the packet. The final packet built in the datagram must pad
1335        // to this size.
1336        let mut pad_datagram = PadDatagram::No;
1337
1338        // The packet number of the last built packet. This is kept kept across spaces.
1339        // QUIC is supposed to have a single congestion controller for the Initial,
1340        // Handshake and Data(PathId::ZERO) spaces.
1341        let mut last_packet_number = None;
1342
1343        // Set when either the congestion window or the pacer held a send back; drives
1344        // `app_limited`, since neither case means the application ran dry.
1345        let mut send_blocked = false;
1346        // Set only when the congestion window itself was full. This is the spec's
1347        // `C.is_cwnd_limited`, which a pacing delay must not stand in for.
1348        let mut cwnd_blocked = false;
1349
1350        let path = self.path_data(path_id);
1351
1352        // `C.send_quantum` bounds one aggregate scheduled and transmitted together as a unit,
1353        // which for a GSO batch is its datagram count. Controllers that don't compute one leave
1354        // the batch bounded only by what the caller offered.
1355        // <https://www.ietf.org/archive/id/draft-ietf-ccwg-bbr-06.html#section-5.6.3>
1356        // Nothing `poll_transmit_on_path` does alters these, so one snapshot serves the whole call.
1357        let controller_metrics = path.congestion.metrics();
1358        let max_datagrams = match controller_metrics.send_quantum {
1359            Some(send_quantum) => {
1360                let datagrams = send_quantum / u64::from(path.current_mtu());
1361                let datagrams = usize::try_from(datagrams).unwrap_or(usize::MAX);
1362                max_datagrams.min(NonZeroUsize::new(datagrams).unwrap_or(NonZeroUsize::MIN))
1363            }
1364            None => max_datagrams,
1365        };
1366
1367        // Set the segment size to this path's MTU for on-path data.
1368        let pmtu = path.current_mtu().into();
1369        let mut transmit = TransmitBuf::new(buf, max_datagrams, pmtu);
1370
1371        // Iterate over the available spaces.
1372        for space_id in SpaceId::iter() {
1373            // Only PathId::ZERO uses non Data space ids.
1374            if path_id != PathId::ZERO && space_id != SpaceId::Data {
1375                continue;
1376            }
1377            match self.poll_transmit_path_space(
1378                now,
1379                &mut transmit,
1380                path_id,
1381                space_id,
1382                remote_cid,
1383                scheduling_info,
1384                connection_close_pending,
1385                pad_datagram,
1386            ) {
1387                PollPathSpaceStatus::NothingToSend { path_blocked } => {
1388                    // Continue checking other spaces, tail-loss probes may need to be sent
1389                    // in all spaces.
1390                    match path_blocked {
1391                        PathBlocked::No => {}
1392                        PathBlocked::AntiAmplification => {
1393                            send_blocked = true;
1394                        }
1395                        PathBlocked::Congestion => {
1396                            cwnd_blocked = true;
1397                            send_blocked = true;
1398                        }
1399                        PathBlocked::Pacing => send_blocked = true,
1400                    }
1401                }
1402                PollPathSpaceStatus::WrotePacket {
1403                    last_packet_number: pn,
1404                    pad_datagram: pad,
1405                } => {
1406                    debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1407                    last_packet_number = Some(pn);
1408                    pad_datagram = pad;
1409                    // Always check higher spaces. If the transmit is full or they have
1410                    // nothing to send they will not write packets. But if they can, they
1411                    // must always be allowed to add to this transmit because coalescing may
1412                    // be required.
1413                    continue;
1414                }
1415                PollPathSpaceStatus::Send {
1416                    last_packet_number: pn,
1417                } => {
1418                    debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1419                    last_packet_number = Some(pn);
1420                    break;
1421                }
1422            }
1423        }
1424
1425        if last_packet_number.is_some() || send_blocked {
1426            self.qlog.emit_recovery_metrics(
1427                path_id,
1428                &mut self
1429                    .paths
1430                    .get_mut(&path_id)
1431                    .expect("path_id was iterated from self.paths above")
1432                    .data,
1433                now,
1434            );
1435        }
1436
1437        let path = self.path_data_mut(path_id);
1438
1439        path.app_limited = last_packet_number.is_none() && !send_blocked;
1440
1441        if path.app_limited {
1442            // Tell the controller now: once nothing is in flight, no ACK arrives to carry the
1443            // flag before the next send.
1444            let in_flight = path.in_flight.bytes;
1445            path.congestion.on_app_limited(in_flight);
1446        }
1447        if cwnd_blocked {
1448            path.congestion.on_cwnd_limited();
1449        }
1450
1451        match last_packet_number {
1452            Some(last_packet_number) => {
1453                // Note that when sending in multiple spaces the last packet number will be
1454                // the one from the highest space.
1455                self.path_data_mut(path_id).congestion.on_sent(
1456                    now,
1457                    transmit.len() as u64,
1458                    last_packet_number,
1459                );
1460                Some(self.build_transmit(path_id, transmit))
1461            }
1462            None => None,
1463        }
1464    }
1465
1466    /// poll_transmit logic for a QUIC-MULTIPATH packet number space (PathID + SpaceId).
1467    #[must_use]
1468    fn poll_transmit_path_space(
1469        &mut self,
1470        now: Instant,
1471        transmit: &mut TransmitBuf<'_>,
1472        path_id: PathId,
1473        space_id: SpaceId,
1474        remote_cid: ConnectionId,
1475        scheduling_info: &PathSchedulingInfo,
1476        // If we need to send a CONNECTION_CLOSE frame.
1477        connection_close_pending: bool,
1478        // Whether the current datagram needs to be padded to a certain size.
1479        mut pad_datagram: PadDatagram,
1480    ) -> PollPathSpaceStatus {
1481        // Keep track of the last packet number we wrote. If None we did not write any
1482        // packets.
1483        let mut last_packet_number = None;
1484
1485        // Each loop of this may build one packet. It works logically as follows:
1486        //
1487        // - Check if something *needs* to be sent in this space and *can* be sent.
1488        //   - If not, return to the caller who will call us again for the next space.
1489        // - Start a new datagram.
1490        //   - Unless coalescing the packet into an existing datagram.
1491        // - Write the packet header and payload.
1492        // - Check if coalescing a next packet into the datagram is possible.
1493        // - If coalescing, finish packet without padding to leave space in the datagram.
1494        // - If not coalescing, complete the datagram:
1495        //   - Finish packet with padding.
1496        //   - Set the transmit segment size if this is the first datagram.
1497        // - Loop: next iteration will exit the loop if nothing more to send in this space. The
1498        //   TransmitBuf will contain a started datagram with space if coalescing, or completely
1499        //   filled datagram if not coalescing.
1500        loop {
1501            // Determine if anything can be sent in this packet number space.
1502            let max_packet_size = if transmit.datagram_remaining_mut() > 0 {
1503                // A datagram is started already, we are coalescing another packet into it.
1504                transmit.datagram_remaining_mut()
1505            } else {
1506                // A new datagram needs to be started.
1507                transmit.segment_size()
1508            };
1509            let can_send =
1510                self.space_can_send(space_id, path_id, max_packet_size, connection_close_pending);
1511            let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1512            let space_will_send = {
1513                if scheduling_info.is_abandoned {
1514                    // If this path is abandoned then we might still have to send
1515                    // PATH_ABANDON itself on it if there was no better space
1516                    // available. Otherwise we want to send the PATH_ABANDON as permitted by
1517                    // may_send_data however.
1518                    scheduling_info.may_self_abandon
1519                        && self.spaces[space_id]
1520                            .pending
1521                            .path_abandon
1522                            .contains_key(&path_id)
1523                } else if can_send.close && scheduling_info.may_send_close {
1524                    // This is the best path to send a CONNECTION_CLOSE on.
1525                    true
1526                } else if needs_loss_probe || can_send.space_specific {
1527                    // We always send a loss probe or space-specific frames if the path is
1528                    // not abandoned.
1529                    true
1530                } else {
1531                    // Anything else we only send if we're the best path for SpaceKind::Data
1532                    // frames.
1533                    !can_send.is_empty() && scheduling_info.may_send_data
1534                }
1535            };
1536
1537            if !space_will_send {
1538                // Nothing more to send. Previous iterations of this loop may have built
1539                // packets already.
1540                return match last_packet_number {
1541                    Some(pn) => PollPathSpaceStatus::WrotePacket {
1542                        last_packet_number: pn,
1543                        pad_datagram,
1544                    },
1545                    None => {
1546                        // Only log for spaces which have crypto.
1547                        if self.crypto_state.has_keys(space_id.encryption_level())
1548                            || (space_id == SpaceId::Data
1549                                && self.crypto_state.has_keys(EncryptionLevel::ZeroRtt))
1550                        {
1551                            trace!(?space_id, %path_id, "nothing to send in space");
1552                        }
1553                        PollPathSpaceStatus::NothingToSend {
1554                            path_blocked: PathBlocked::No,
1555                        }
1556                    }
1557                };
1558            }
1559
1560            // We want to send on this space, check congestion control if we can. But only
1561            // if we will need to start a new datagram. If we are coalescing into an already
1562            // started datagram we do not need to check congestion control again.
1563            if transmit.datagram_remaining_mut() == 0 {
1564                let path_blocked =
1565                    self.path_congestion_check(space_id, path_id, transmit, &can_send, now);
1566                if path_blocked != PathBlocked::No {
1567                    // Previous iterations of this loop may have built packets already.
1568                    return match last_packet_number {
1569                        Some(pn) => PollPathSpaceStatus::WrotePacket {
1570                            last_packet_number: pn,
1571                            pad_datagram,
1572                        },
1573                        None => PollPathSpaceStatus::NothingToSend { path_blocked },
1574                    };
1575                }
1576
1577                // If the datagram is full (or there never was one started), we need to start a
1578                // new one.
1579                if transmit.num_datagrams() >= transmit.max_datagrams().get() {
1580                    // No more datagrams allowed.
1581                    // Previous iterations of this loop may have built packets already.
1582                    return match last_packet_number {
1583                        Some(pn) => PollPathSpaceStatus::WrotePacket {
1584                            last_packet_number: pn,
1585                            pad_datagram,
1586                        },
1587                        None => PollPathSpaceStatus::NothingToSend { path_blocked },
1588                    };
1589                }
1590
1591                if needs_loss_probe {
1592                    // Ensure we have something to send for a tail-loss probe.
1593                    let request_immediate_ack =
1594                        space_id == SpaceId::Data && self.peer_supports_ack_frequency();
1595                    self.spaces[space_id].queue_tail_loss_probe(
1596                        path_id,
1597                        request_immediate_ack,
1598                        &self.streams,
1599                    );
1600
1601                    self.spaces[space_id].for_path(path_id).loss_probes -= 1; // needs_loss_probe ensures loss_probes > 0
1602
1603                    // Clamp the datagram to at most the minimum MTU to ensure that loss
1604                    // probes can get through and enable recovery even if the path MTU
1605                    // has shrank unexpectedly.
1606                    transmit.start_new_datagram_with_size(cmp::min(
1607                        usize::from(INITIAL_MTU),
1608                        transmit.segment_size(),
1609                    ));
1610                } else {
1611                    transmit.start_new_datagram();
1612                }
1613                trace!(count = transmit.num_datagrams(), "new datagram started");
1614
1615                // We started a new datagram, we decide later if it needs padding.
1616                pad_datagram = PadDatagram::No;
1617            }
1618
1619            // If coalescing another packet into the existing datagram, there should
1620            // still be enough space for a whole packet.
1621            if transmit.datagram_start_offset() < transmit.len() {
1622                debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE);
1623            }
1624
1625            //
1626            // From here on, we've determined that a packet will definitely be sent.
1627            //
1628
1629            if self.crypto_state.has_keys(EncryptionLevel::Initial)
1630                && space_id == SpaceId::Handshake
1631                && self.side.is_client()
1632            {
1633                // A client stops both sending and processing Initial packets when it
1634                // sends its first Handshake packet.
1635                self.discard_space(now, SpaceKind::Initial);
1636            }
1637            if let Some(ref mut prev) = self.crypto_state.prev_crypto {
1638                prev.update_unacked = false;
1639            }
1640
1641            let Some(mut builder) =
1642                PacketBuilder::new(now, space_id, path_id, remote_cid, transmit, self)
1643            else {
1644                // Confidentiality limit is exceeded and the connection has been killed. We
1645                // should not send any other packets. This works in a roundabout way: We
1646                // have started a datagram but not written anything into it. So even if we
1647                // get called again for another space we will see an already started
1648                // datagram and try and start another packet here. Then be stopped by the
1649                // same confidentiality limit.
1650                return PollPathSpaceStatus::NothingToSend {
1651                    path_blocked: PathBlocked::No,
1652                };
1653            };
1654            last_packet_number = Some(builder.packet_number);
1655
1656            if space_id == SpaceId::Initial
1657                && (self.side.is_client() || can_send.is_ack_eliciting() || needs_loss_probe)
1658            {
1659                // https://www.rfc-editor.org/rfc/rfc9000.html#section-14.1
1660                pad_datagram |= PadDatagram::ToMinMtu;
1661            }
1662            if space_id == SpaceId::Data && self.config.pad_to_mtu {
1663                pad_datagram |= PadDatagram::ToSegmentSize;
1664            }
1665
1666            if scheduling_info.may_send_close && can_send.close {
1667                trace!("sending CONNECTION_CLOSE");
1668                // Encode ACKs before the ConnectionClose message, to give the receiver
1669                // a better approximate on what data has been processed. This is
1670                // especially important with ack delay, since the peer might not
1671                // have gotten any other ACK for the data earlier on.
1672                let is_multipath_negotiated = self.is_multipath_negotiated();
1673                for path_id in self.spaces[space_id]
1674                    .number_spaces
1675                    .iter()
1676                    .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty())
1677                    .map(|(&path_id, _)| path_id)
1678                    .collect::<Vec<_>>()
1679                {
1680                    Self::populate_acks(
1681                        now,
1682                        self.receiving_ecn,
1683                        path_id,
1684                        space_id,
1685                        &mut self.spaces[space_id],
1686                        is_multipath_negotiated,
1687                        &mut builder,
1688                        &mut self.path_stats.get_mut(path_id).frame_tx,
1689                        self.crypto_state.has_keys(space_id.encryption_level()),
1690                    );
1691                }
1692
1693                // Since there only 64 ACK frames there will always be enough space
1694                // to encode the ConnectionClose frame too. However we still have the
1695                // check here to prevent crashes if something changes.
1696
1697                // TODO(flub): This needs fixing for multipath, to ensure we can always
1698                //    write the CONNECTION_CLOSE even if we have many PATH_ACKs to send:
1699                //    https://github.com/n0-computer/noq/issues/367.
1700                debug_assert!(
1701                    builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND,
1702                    "ACKs should leave space for ConnectionClose"
1703                );
1704                let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
1705                if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() {
1706                    let max_frame_size = builder.frame_space_remaining();
1707                    let close: Close = match self.state.as_type() {
1708                        StateType::Closed => {
1709                            let reason: Close =
1710                                self.state.as_closed().expect("checked").clone().into();
1711                            if space_id == SpaceId::Data || reason.is_transport_layer() {
1712                                reason
1713                            } else {
1714                                TransportError::APPLICATION_ERROR("").into()
1715                            }
1716                        }
1717                        StateType::Draining => TransportError::NO_ERROR("").into(),
1718                        _ => unreachable!(
1719                            "tried to make a close packet when the connection wasn't closed"
1720                        ),
1721                    };
1722                    builder.write_frame(close.encoder(max_frame_size), stats);
1723                }
1724                let last_pn = builder.packet_number;
1725                builder.finish_and_track(now, self, path_id, pad_datagram);
1726                if space_id.kind() == self.highest_space {
1727                    // Don't send another close packet. Even with multipath we only send
1728                    // CONNECTION_CLOSE on a single path since we expect our paths to work.
1729                    self.connection_close_pending = false;
1730                }
1731                // Send a close frame in every possible space for robustness, per
1732                // RFC9000 "Immediate Close during the Handshake". Don't bother trying
1733                // to send anything else.
1734                // TODO(flub): This breaks during the handshake if we can not coalesce
1735                //    packets due to space reasons: the next space would either fail a
1736                //    debug_assert checking for enough packet space or produce an invalid
1737                //    packet. We need to keep track of per-space pending CONNECTION_CLOSE to
1738                //    be able to send these across multiple calls to poll_transmit. Then
1739                //    check for coalescing space here because initial packets need to be in
1740                //    padded datagrams. And also add space checks for CONNECTION_CLOSE in
1741                //    space_can_send so it would stop a GSO batch if the datagram is too
1742                //    small for another CONNECTION_CLOSE packet.
1743                return PollPathSpaceStatus::WrotePacket {
1744                    last_packet_number: last_pn,
1745                    pad_datagram,
1746                };
1747            }
1748
1749            self.populate_packet(now, space_id, path_id, scheduling_info, &mut builder);
1750
1751            // ACK-only packets should only be sent when explicitly allowed. If we write them due to
1752            // any other reason, there is a bug which leads to one component announcing write
1753            // readiness while not writing any data. This degrades performance. The condition is
1754            // only checked if the full MTU is available and when potentially large fixed-size
1755            // frames aren't queued, so that lack of space in the datagram isn't the reason for just
1756            // writing ACKs.
1757            debug_assert!(
1758                !(builder.sent_frames().is_ack_only(&self.streams)
1759                    && !can_send.acks
1760                    && (can_send.other || can_send.space_specific)
1761                    && builder.buf.segment_size()
1762                        == self.path_data(path_id).current_mtu() as usize
1763                    && self.datagrams.outgoing.is_empty()),
1764                "SendableFrames was {can_send:?}, but only ACKs have been written"
1765            );
1766            if builder.sent_frames().requires_padding {
1767                pad_datagram |= PadDatagram::ToMinMtu;
1768            }
1769
1770            for path_id in builder.sent_frames().largest_acked.keys() {
1771                self.spaces[space_id]
1772                    .for_path(*path_id)
1773                    .pending_acks
1774                    .acks_sent();
1775                self.timers.stop(
1776                    Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
1777                    self.qlog.with_time(now),
1778                );
1779            }
1780
1781            // Now we need to finish the packet.  Before we do so we need to know if we will
1782            // be coalescing the next packet into this one, or will be ending the datagram
1783            // as well.  Because if this is the last packet in the datagram more padding
1784            // might be needed because of the packet type, or to fill the GSO segment size.
1785
1786            let max_packet_size = builder
1787                .buf
1788                .datagram_remaining_mut()
1789                .saturating_sub(builder.predict_packet_end());
1790            // Are we allowed to coalesce AND is there enough space for another *packet* in
1791            // this datagram AND will we definitely send another packet?
1792            if builder.can_coalesce
1793                && path_id == PathId::ZERO
1794                && let Some(next_space_id) = space_id.next()
1795                && max_packet_size > MIN_PACKET_SPACE
1796                && self
1797                    .space_can_send(space_id, path_id, max_packet_size, connection_close_pending)
1798                    .is_empty()
1799                && self.has_pending_packet(next_space_id, max_packet_size, connection_close_pending)
1800            {
1801                // We can append/coalesce the next packet into the current
1802                // datagram. Finish the current packet without adding extra padding.
1803                trace!("will coalesce with next packet");
1804                let last_pn = builder.packet_number;
1805                builder.finish_and_track(now, self, path_id, PadDatagram::No);
1806                // We need to return - this loop would re-try the same SpaceId, which we don't want.
1807                // We want to coalesce with the next space_id.
1808                return PollPathSpaceStatus::WrotePacket {
1809                    last_packet_number: last_pn,
1810                    pad_datagram,
1811                };
1812            } else {
1813                // We need a new datagram for the next packet.  Finish the current
1814                // packet with padding.
1815                // TODO(flub): if there isn't any more data to be sent, this will still pad
1816                //    to the segment size and only discover there is nothing to send before
1817                //    starting the next packet. That is wasting up to 32 bytes.
1818                if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) {
1819                    // If too many padding bytes would be required to continue the
1820                    // GSO batch after this packet, end the GSO batch here. Ensures
1821                    // that fixed-size frames with heterogeneous sizes
1822                    // (e.g. application datagrams) won't inadvertently waste large
1823                    // amounts of bandwidth. The exact threshold is a bit arbitrary
1824                    // and might benefit from further tuning, though there's no
1825                    // universally optimal value.
1826                    const MAX_PADDING: usize = 32;
1827                    if builder.buf.datagram_remaining_mut()
1828                        > builder.predict_packet_end() + MAX_PADDING
1829                    {
1830                        trace!(
1831                            "GSO truncated by demand for {} padding bytes",
1832                            builder.buf.datagram_remaining_mut() - builder.predict_packet_end()
1833                        );
1834                        let last_pn = builder.packet_number;
1835                        builder.finish_and_track(now, self, path_id, PadDatagram::No);
1836                        return PollPathSpaceStatus::Send {
1837                            last_packet_number: last_pn,
1838                        };
1839                    }
1840
1841                    // Pad the current datagram to GSO segment size so it can be
1842                    // included in the GSO batch.
1843                    builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize);
1844                } else {
1845                    builder.finish_and_track(now, self, path_id, pad_datagram);
1846                }
1847
1848                // If this is the first datagram we set the segment size to the size of the
1849                // first datagram.
1850                if transmit.num_datagrams() == 1 {
1851                    transmit.clip_segment_size();
1852                }
1853            }
1854        }
1855    }
1856
1857    fn poll_transmit_mtu_probe(
1858        &mut self,
1859        now: Instant,
1860        buf: &mut Vec<u8>,
1861        path_id: PathId,
1862    ) -> Option<Transmit> {
1863        let (active_cid, probe_size) = self.get_mtu_probe_data(now, path_id)?;
1864
1865        // We are definitely sending a DPLPMTUD probe.
1866        let mut transmit = TransmitBuf::new(buf, NonZeroUsize::MIN, probe_size as usize);
1867        transmit.start_new_datagram_with_size(probe_size as usize);
1868
1869        let mut builder =
1870            PacketBuilder::new(now, SpaceId::Data, path_id, active_cid, &mut transmit, self)?;
1871
1872        // We implement MTU probes as ping packets padded up to the probe size
1873        trace!(?probe_size, "writing MTUD probe");
1874        builder.write_frame(frame::Ping, &mut self.path_stats.get_mut(path_id).frame_tx);
1875
1876        // If supported by the peer, we want no delays to the probe's ACK
1877        if self.peer_supports_ack_frequency() {
1878            builder.write_frame(
1879                frame::ImmediateAck,
1880                &mut self.path_stats.get_mut(path_id).frame_tx,
1881            );
1882        }
1883
1884        builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size));
1885
1886        self.path_stats.get_mut(path_id).sent_plpmtud_probes += 1;
1887
1888        Some(self.build_transmit(path_id, transmit))
1889    }
1890
1891    /// Returns the CID and probe size if a DPLPMTUD probe is needed.
1892    ///
1893    /// We MTU probe all paths for which all of the following is true:
1894    /// - We have an active destination CID for the path.
1895    /// - The remote address *and* path are validated.
1896    /// - The path is not abandoned.
1897    /// - The MTU Discovery subsystem wants to probe the path.
1898    fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> {
1899        let active_cid = self.remote_cids.get(&path_id).map(CidQueue::active)?;
1900        let is_eligible = self.path_data(path_id).validated
1901            && !self.path_data(path_id).is_validating_path()
1902            && !self.abandoned_paths.contains(&path_id);
1903
1904        if !is_eligible {
1905            return None;
1906        }
1907        let next_pn = self.spaces[SpaceId::Data]
1908            .for_path(path_id)
1909            .peek_tx_number();
1910        let probe_size = self
1911            .path_data_mut(path_id)
1912            .mtud
1913            .poll_transmit(now, next_pn)?;
1914
1915        Some((active_cid, probe_size))
1916    }
1917
1918    /// Returns true if there is a further packet to send on [`PathId::ZERO`].
1919    ///
1920    /// In other words this is predicting whether the next call to
1921    /// [`Connection::space_can_send`] issued will return some frames to be sent. Including
1922    /// having to predict which packet number space it will be invoked with. This depends on
1923    /// how both [`Connection::poll_transmit_on_path`] and
1924    /// [`Connection::poll_transmit_path_space`] behave.
1925    ///
1926    /// This is needed to determine if packet coalescing can happen. Because the last packet
1927    /// in a datagram may need to be padded and thus we must know if another packet will
1928    /// follow or not.
1929    ///
1930    /// The next packet can be either in the same space, or in one of the following spaces
1931    /// on the same path. Because a 0-RTT packet can be coalesced with a 1-RTT packet and
1932    /// both are in the Data(PathId::ZERO) space. Previous spaces are not checked, because
1933    /// packets are built from Initial to Handshake to Data spaces.
1934    fn has_pending_packet(
1935        &mut self,
1936        current_space_id: SpaceId,
1937        max_packet_size: usize,
1938        connection_close_pending: bool,
1939    ) -> bool {
1940        let mut space_id = current_space_id;
1941        loop {
1942            let can_send = self.space_can_send(
1943                space_id,
1944                PathId::ZERO,
1945                max_packet_size,
1946                connection_close_pending,
1947            );
1948            if !can_send.is_empty() {
1949                return true;
1950            }
1951            match space_id.next() {
1952                Some(next_space_id) => space_id = next_space_id,
1953                None => break,
1954            }
1955        }
1956        false
1957    }
1958
1959    /// Checks if creating a new datagram would be blocked by congestion control
1960    fn path_congestion_check(
1961        &mut self,
1962        space_id: SpaceId,
1963        path_id: PathId,
1964        transmit: &TransmitBuf<'_>,
1965        can_send: &SendableFrames,
1966        now: Instant,
1967    ) -> PathBlocked {
1968        // Anti-amplification is only based on `total_sent`, which gets updated after
1969        // the transmit is sent. Therefore we pass the amount of bytes for datagrams
1970        // that are already created, as well as 1 byte for starting another datagram. If
1971        // there is any anti-amplification budget left, we always allow a full MTU to be
1972        // sent (see https://github.com/quinn-rs/quinn/issues/1082).
1973        if self.side().is_server()
1974            && self
1975                .path_data(path_id)
1976                .anti_amplification_blocked(transmit.len() as u64 + 1)
1977        {
1978            trace!(?space_id, %path_id, "blocked by anti-amplification");
1979            return PathBlocked::AntiAmplification;
1980        }
1981
1982        // Congestion control check.
1983        // Tail loss probes must not be blocked by congestion, or a deadlock could arise.
1984        let bytes_to_send = transmit.segment_size() as u64;
1985        let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1986
1987        if can_send.other && !need_loss_probe && !can_send.close {
1988            let path = self.path_data(path_id);
1989            if path.in_flight.bytes + bytes_to_send >= path.congestion.window() {
1990                trace!(
1991                    ?space_id,
1992                    %path_id,
1993                    in_flight=%path.in_flight.bytes,
1994                    congestion_window=%path.congestion.window(),
1995                    "blocked by congestion control",
1996                );
1997                return PathBlocked::Congestion;
1998            }
1999        }
2000
2001        // Pacing check.
2002        if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) {
2003            let resume_time = now + delay;
2004            self.timers.set(
2005                Timer::PerPath(path_id, PathTimer::Pacing),
2006                resume_time,
2007                self.qlog.with_time(now),
2008            );
2009            // Loss probes and CONNECTION_CLOSE should be subject to pacing, even though
2010            // they are not congestion controlled.
2011            trace!(?space_id, %path_id, ?delay, "blocked by pacing");
2012            return PathBlocked::Pacing;
2013        }
2014
2015        PathBlocked::No
2016    }
2017
2018    /// Send PATH_CHALLENGE for a previous path if necessary
2019    ///
2020    /// QUIC-TRANSPORT section 9.3.3
2021    /// <https://www.rfc-editor.org/rfc/rfc9000.html#name-off-path-packet-forwarding>
2022    fn send_prev_path_challenge(
2023        &mut self,
2024        now: Instant,
2025        buf: &mut Vec<u8>,
2026        path_id: PathId,
2027    ) -> Option<Transmit> {
2028        let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?;
2029        if !prev_path.pending_challenge {
2030            return None;
2031        };
2032        prev_path.pending_challenge = false;
2033        let token = self.rng.random();
2034        let network_path = prev_path.network_path;
2035        prev_path.record_path_challenge_sent(now, token, network_path);
2036
2037        debug_assert_eq!(
2038            self.highest_space,
2039            SpaceKind::Data,
2040            "PATH_CHALLENGE queued without 1-RTT keys"
2041        );
2042        let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2043        buf.start_new_datagram();
2044
2045        // Use the previous CID to avoid linking the new path with the previous path. We
2046        // don't bother accounting for possible retirement of that prev_cid because this is
2047        // sent once, immediately after migration, when the CID is known to be valid. Even
2048        // if a post-migration packet caused the CID to be retired, it's fair to pretend
2049        // this is sent first.
2050        let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, self)?;
2051        let challenge = frame::PathChallenge(token);
2052        let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2053        builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path"));
2054
2055        // An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame
2056        // to at least the smallest allowed maximum datagram size of 1200 bytes,
2057        // unless the anti-amplification limit for the path does not permit
2058        // sending a datagram of this size
2059        builder.pad_to(MIN_INITIAL_SIZE);
2060
2061        builder.finish(self, now);
2062        self.path_stats
2063            .get_mut(path_id)
2064            .udp_tx
2065            .on_sent(1, buf.len());
2066
2067        trace!(
2068            dst = ?network_path.remote,
2069            src = ?network_path.local_ip,
2070            len = buf.len(),
2071            "sending prev_path off-path challenge",
2072        );
2073        Some(Transmit {
2074            destination: network_path.remote,
2075            size: buf.len(),
2076            ecn: None,
2077            segment_size: None,
2078            src_ip: network_path.local_ip,
2079        })
2080    }
2081
2082    fn send_off_path_path_response(
2083        &mut self,
2084        now: Instant,
2085        buf: &mut Vec<u8>,
2086        path_id: PathId,
2087    ) -> Option<Transmit> {
2088        let network_path = self
2089            .paths
2090            .get_mut(&path_id)
2091            .map(|state| state.data.network_path)?;
2092        let cid_queue = self.remote_cids.get_mut(&path_id)?;
2093        let pns = self.spaces[SpaceKind::Data].for_path(path_id);
2094        let (token, network_path) = pns.pending_path_responses.pop_off_path(network_path)?;
2095
2096        // TODO: make off-path probes unlinkable.
2097        let cid = cid_queue.active();
2098
2099        // PATH_RESPONSE (off-path)
2100        let frame = frame::PathResponse(token);
2101
2102        let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2103        buf.start_new_datagram();
2104
2105        let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, buf, self)?;
2106        let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2107        builder.write_frame_with_log_msg(frame, stats, Some("(off-path)"));
2108
2109        // PATH_CHALLENGE (off-path)
2110        //
2111        // If we are a client doing NAT traversal, always include a PATH_CHALLENGE with any
2112        // off-path PATH_RESPONSE. No need to schedule any retries for this, if NAT
2113        // traversal is taking place then this remote already is being probed with
2114        // retries, this only speeds up a successful traversal.
2115        if self
2116            .find_validated_path_on_network_path(network_path)
2117            .is_none()
2118            && self.n0_nat_traversal.client_side().is_ok()
2119        {
2120            let token = self.rng.random();
2121            let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2122            builder.write_frame(frame::PathChallenge(token), stats);
2123            let ip_port = (network_path.remote.ip(), network_path.remote.port());
2124            self.n0_nat_traversal.mark_probe_sent(ip_port, token);
2125        }
2126
2127        // Off-path: not tracked in congestion control. The packet is sent to a
2128        // different destination than path_id's network path.
2129        builder.pad_to(MIN_INITIAL_SIZE);
2130        builder.finish(self, now);
2131
2132        let size = buf.len();
2133        self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2134
2135        trace!(
2136            dst = ?network_path.remote,
2137            src = ?network_path.local_ip,
2138            len = buf.len(),
2139            "sending off-path PATH_RESPONSE",
2140        );
2141        Some(Transmit {
2142            destination: network_path.remote,
2143            size,
2144            ecn: None,
2145            segment_size: None,
2146            src_ip: network_path.local_ip,
2147        })
2148    }
2149
2150    /// Send a nat traversal challenge (off-path) on this path if possible.
2151    fn send_nat_traversal_path_challenge(
2152        &mut self,
2153        now: Instant,
2154        buf: &mut Vec<u8>,
2155        path_id: PathId,
2156    ) -> Option<Transmit> {
2157        let remote = self.n0_nat_traversal.next_probe_addr()?;
2158
2159        if !self.paths.get(&path_id)?.data.validated {
2160            // Path is not usable for probing
2161            return None;
2162        }
2163
2164        // TODO: Using the active CID here makes the paths linkable. This is a violation of
2165        //    RFC9000 but something we want to accept in the short term. Eventually we aim
2166        //    to fix up the supply of CIDs sufficiently so that we can keep paths unlinkable
2167        //    again.
2168        let Some(cid) = self
2169            .remote_cids
2170            .get(&path_id)
2171            .map(|cid_queue| cid_queue.active())
2172        else {
2173            trace!(%path_id, "Not sending NAT traversal probe for path with no CIDs");
2174            return None;
2175        };
2176        let token = self.rng.random();
2177
2178        // PATH_CHALLENGE (NAT probe)
2179        let frame = frame::PathChallenge(token);
2180
2181        let mut buf = TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2182        buf.start_new_datagram();
2183
2184        let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, &mut buf, self)?;
2185        let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2186        builder.write_frame_with_log_msg(frame, stats, Some("(nat-traversal)"));
2187        // Off-path: not tracked in congestion control. The packet is sent to a
2188        // different destination than path_id's network path.
2189        builder.finish(self, now);
2190
2191        // Mark as sent after packet build succeeds.
2192        self.n0_nat_traversal.mark_probe_sent(remote, token);
2193
2194        let size = buf.len();
2195        self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2196
2197        trace!(dst = ?remote, len = buf.len(), "sending off-path NAT probe");
2198        Some(Transmit {
2199            destination: remote.into(),
2200            size,
2201            ecn: None,
2202            segment_size: None,
2203            src_ip: None,
2204        })
2205    }
2206
2207    /// Indicate what types of frames are ready to send for the given packet number space.
2208    ///
2209    /// Only for on-path data.
2210    ///
2211    /// *packet_size* is the number of bytes available to build the next packet.
2212    /// *connection_close_pending* indicates whether a CONNECTION_CLOSE frame needs to be
2213    /// sent.
2214    fn space_can_send(
2215        &mut self,
2216        space_id: SpaceId,
2217        path_id: PathId,
2218        packet_size: usize,
2219        connection_close_pending: bool,
2220    ) -> SendableFrames {
2221        let space = &mut self.spaces[space_id];
2222        let space_has_crypto = self.crypto_state.has_keys(space_id.encryption_level());
2223
2224        if !space_has_crypto
2225            && (space_id != SpaceId::Data
2226                || !self.crypto_state.has_keys(EncryptionLevel::ZeroRtt)
2227                || self.side.is_server())
2228        {
2229            // Nothing to send in this space
2230            return SendableFrames::empty();
2231        }
2232
2233        let mut can_send = space.can_send(path_id, &self.streams);
2234
2235        // Check for 1RTT space.
2236        if space_id == SpaceId::Data {
2237            let pn = space.for_path(path_id).peek_tx_number();
2238            // Number of bytes available for frames if this is a 1-RTT packet. We're
2239            // guaranteed to be able to send an individual frame at least this large in the
2240            // next 1-RTT packet. This could be generalized to support every space, but it's
2241            // only needed to handle large fixed-size frames, which only exist in 1-RTT
2242            // (application datagrams).
2243            let frame_space_1rtt =
2244                packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id));
2245            can_send |= self.can_send_1rtt(path_id, frame_space_1rtt);
2246        }
2247
2248        can_send.close = connection_close_pending && space_has_crypto;
2249
2250        can_send
2251    }
2252
2253    /// Process `ConnectionEvent`s generated by the associated `Endpoint`
2254    ///
2255    /// Will execute protocol logic upon receipt of a connection event, in turn preparing signals
2256    /// (including application `Event`s, `EndpointEvent`s and outgoing datagrams) that should be
2257    /// extracted through the relevant methods.
2258    pub fn handle_event(&mut self, event: ConnectionEvent) {
2259        use ConnectionEventInner::*;
2260        match event.0 {
2261            Datagram(DatagramConnectionEvent {
2262                now,
2263                network_path,
2264                path_id,
2265                ecn,
2266                first_decode,
2267                remaining,
2268            }) => {
2269                let span = trace_span!("pkt", %path_id);
2270                let _guard = span.enter();
2271
2272                if self.early_discard_packet(network_path, path_id) {
2273                    // A return value of true indicates we should discard this packet.
2274                    return;
2275                }
2276
2277                let was_anti_amplification_blocked = self
2278                    .path(path_id)
2279                    .map(|path| path.anti_amplification_blocked(1))
2280                    // We never tried to send on an non-existing (new) path so have not been
2281                    // anti-amplification blocked for it previously.
2282                    .unwrap_or(false);
2283
2284                let rx = &mut self.path_stats.get_mut(path_id).udp_rx;
2285                rx.datagrams += 1;
2286                rx.bytes += first_decode.len() as u64;
2287                let data_len = first_decode.len();
2288
2289                self.handle_decode(now, network_path, path_id, ecn, first_decode);
2290                // The current `path` might have changed inside `handle_decode` since the packet
2291                // could have triggered a migration. The packet might also belong to an unknown
2292                // path and have been rejected. Make sure the data received is accounted for the
2293                // most recent path by accessing `path` after `handle_decode`.
2294                if let Some(path) = self.path_mut(path_id) {
2295                    path.inc_total_recvd(data_len as u64);
2296                }
2297
2298                if let Some(data) = remaining {
2299                    self.path_stats.get_mut(path_id).udp_rx.bytes += data.len() as u64;
2300                    self.handle_coalesced(now, network_path, path_id, ecn, data);
2301                }
2302
2303                if let Some(path) = self.paths.get_mut(&path_id) {
2304                    self.qlog
2305                        .emit_recovery_metrics(path_id, &mut path.data, now);
2306                }
2307
2308                if was_anti_amplification_blocked {
2309                    // A prior attempt to set the loss detection timer may have failed due to
2310                    // anti-amplification, so ensure it's set now. Prevents a handshake deadlock if
2311                    // the server's first flight is lost.
2312                    self.set_loss_detection_timer(now, path_id);
2313                }
2314            }
2315            NewIdentifiers(ids, now, cid_len, cid_lifetime) => {
2316                let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default();
2317                debug_assert!(ids.iter().all(|issued| issued.path_id == path_id));
2318
2319                // Path may have been abandoned while this reply was in flight,
2320                // retire the CIDs instead of queuing them.
2321                if self.abandoned_paths.contains(&path_id) {
2322                    if !self.state.is_drained() {
2323                        for issued in &ids {
2324                            self.endpoint_events
2325                                .push_back(EndpointEventInner::RetireConnectionId(
2326                                    now,
2327                                    path_id,
2328                                    issued.sequence,
2329                                    false,
2330                                ));
2331                        }
2332                    }
2333                    return;
2334                }
2335
2336                let cid_state = self
2337                    .local_cid_state
2338                    .entry(path_id)
2339                    .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0));
2340                cid_state.new_cids(&ids, now);
2341
2342                ids.into_iter().rev().for_each(|frame| {
2343                    self.spaces[SpaceId::Data].pending.new_cids.push(frame);
2344                });
2345                // Always update Timer::PushNewCid
2346                self.reset_cid_retirement(now);
2347            }
2348        }
2349    }
2350
2351    /// Returns whether a packet can be discarded early.
2352    ///
2353    /// Packets sent on the wrong network path can be entirely ignored, saving further
2354    /// processing.
2355    ///
2356    /// Returns true if a packet coming in for this `path_id` over given `network_path`
2357    /// should be discarded.
2358    fn early_discard_packet(&mut self, network_path: FourTuple, path_id: PathId) -> bool {
2359        if self.is_handshaking() && path_id != PathId::ZERO {
2360            debug!(%network_path, %path_id, "discarding multipath packet during handshake");
2361            return true;
2362        }
2363
2364        if !self.paths.contains_key(&path_id) && self.abandoned_paths.contains(&path_id) {
2365            trace!(%path_id, "discarding packet for discarded path");
2366            return true;
2367        }
2368
2369        let peer_may_probe = self.peer_may_probe();
2370        let local_ip_may_migrate = self.local_ip_may_migrate();
2371
2372        // If this packet could initiate a migration and we're a client or a server that
2373        // forbids migration, drop the datagram. This could be relaxed to heuristically
2374        // permit NAT-rebinding-like migration.
2375        if let Some(known_path) = self.path_mut(path_id) {
2376            if network_path.remote != known_path.network_path.remote && !peer_may_probe {
2377                trace!(
2378                    %path_id,
2379                    %network_path,
2380                    %known_path.network_path,
2381                    "discarding packet from unrecognized peer"
2382                );
2383                return true;
2384            }
2385
2386            if known_path.network_path.local_ip.is_some()
2387                && network_path.local_ip.is_some()
2388                && known_path.network_path.local_ip != network_path.local_ip
2389                && !local_ip_may_migrate
2390            {
2391                trace!(
2392                    %path_id,
2393                    %network_path,
2394                    %known_path.network_path,
2395                    "discarding packet sent to incorrect interface"
2396                );
2397                return true;
2398            }
2399        }
2400        false
2401    }
2402
2403    /// Whether the peer may probe new paths.
2404    ///
2405    /// RFC9000 §9 and QNT both have probing packets which may arrive from new paths. This
2406    /// indicates whether these are allowed or not. This is a strict superset from
2407    /// [`Self::peer_may_migrate`]: every network path that may be migrated to, may also
2408    /// be probed. But e.g. servers may not migrate, but can be allowed to probe.
2409    // TODO(flub): In RFC9000 the server is allowed to send off-path probing packets
2410    //    once the client has been probing such a 4-tuple. These probes are currently
2411    //    not yet recognised and will end up being discarded because of this.
2412    //    See https://github.com/n0-computer/noq/issues/607.
2413    fn peer_may_probe(&self) -> bool {
2414        match &self.side {
2415            ConnectionSide::Client { .. } => {
2416                if let Some(hs) = self.state.as_handshake() {
2417                    hs.allow_server_migration
2418                } else {
2419                    self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed()
2420                }
2421            }
2422            ConnectionSide::Server { server_config } => {
2423                self.is_handshake_confirmed()
2424                    && (server_config.migration || self.n0_nat_traversal.is_negotiated())
2425            }
2426        }
2427    }
2428
2429    /// Whether the peer's remote address may migrate.
2430    ///
2431    /// In RFC9000 only the client may migrate.
2432    ///
2433    /// QUIC relies on stable endpoints during the handshake. So other than the server's
2434    /// preferred_address transport parameter no side may migrate before the handshake is
2435    /// completed.
2436    ///
2437    /// It is noteworthy that for iroh we allow server migrations during the handshake when
2438    /// [`state::Handshake::allow_server_migration`] is enabled, but that is handled earlier
2439    /// in [`Self::handle_packet`] and without probing the current and previous paths.
2440    fn peer_may_migrate(&self) -> bool {
2441        match &self.side {
2442            ConnectionSide::Server { server_config } => {
2443                server_config.migration && self.is_handshake_confirmed()
2444            }
2445            ConnectionSide::Client { .. } => false,
2446        }
2447    }
2448
2449    /// Whether our local IP address is allowed to change with new incoming packets.
2450    ///
2451    /// Incoming packets show us the local IP address we received a packet on, which could
2452    /// be different from what we thought due to e.g. NAT rebinding or moving from mobile
2453    /// data to WiFi without being notified of the network change.
2454    ///
2455    /// This is only allowed to happen after the handshake is confirmed and when we are the
2456    /// client. Unless QNT is negotiated in which case the server is also allowed to
2457    /// migrate.
2458    ///
2459    /// Be aware that probing packets, which do not exist in Multipath without QNT, are
2460    /// exempt from this.
2461    fn local_ip_may_migrate(&self) -> bool {
2462        (self.side.is_client() || self.n0_nat_traversal.is_negotiated())
2463            && self.is_handshake_confirmed()
2464    }
2465    /// Process timer expirations
2466    ///
2467    /// Executes protocol logic, potentially preparing signals (including application `Event`s,
2468    /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant
2469    /// methods.
2470    ///
2471    /// It is most efficient to call this immediately after the system clock reaches the latest
2472    /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply
2473    /// no-op and therefore are safe.
2474    pub fn handle_timeout(&mut self, now: Instant) {
2475        while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) {
2476            let span = match timer {
2477                Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer),
2478                Timer::PerPath(path_id, timer) => {
2479                    trace_span!("timer_fired", scope="path", %path_id, ?timer)
2480                }
2481            };
2482            let _guard = span.enter();
2483            trace!("timeout");
2484            match timer {
2485                Timer::Conn(timer) => match timer {
2486                    ConnTimer::Close => {
2487                        self.state.move_to_drained(None, &mut self.endpoint_events);
2488                    }
2489                    ConnTimer::Idle => {
2490                        self.kill(ConnectionError::TimedOut);
2491                    }
2492                    ConnTimer::KeepAlive => {
2493                        self.ping();
2494                    }
2495                    ConnTimer::KeyDiscard => {
2496                        self.crypto_state.discard_temporary_keys();
2497                    }
2498                    ConnTimer::PushNewCid => {
2499                        while let Some((path_id, when)) = self.next_cid_retirement() {
2500                            if when > now {
2501                                break;
2502                            }
2503                            match self.local_cid_state.get_mut(&path_id) {
2504                                None => error!(%path_id, "No local CID state for path"),
2505                                Some(cid_state) => {
2506                                    // Update `retire_prior_to` field in NEW_CONNECTION_ID frame
2507                                    let num_new_cid = cid_state.on_cid_timeout().into();
2508                                    if !self.state.is_closed() {
2509                                        trace!(
2510                                            "push a new CID to peer RETIRE_PRIOR_TO field {}",
2511                                            cid_state.retire_prior_to()
2512                                        );
2513                                        self.endpoint_events.push_back(
2514                                            EndpointEventInner::NeedIdentifiers(
2515                                                path_id,
2516                                                now,
2517                                                num_new_cid,
2518                                            ),
2519                                        );
2520                                    }
2521                                }
2522                            }
2523                        }
2524                    }
2525                    ConnTimer::NoAvailablePath => {
2526                        // Grace period expired: all paths were abandoned and no new path
2527                        // was opened. Close the connection. There are no paths left to
2528                        // send CONNECTION_CLOSE on, so this is a silent close.
2529                        // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4-8
2530                        if self.state.is_closed() || self.state.is_drained() {
2531                            // Connection already closing/drained (e.g. application called
2532                            // close() before the grace timer fired). Nothing to do.
2533                            error!("no viable path timer fired, but connection already closing");
2534                        } else {
2535                            trace!("no viable path grace period expired, closing connection");
2536                            let err = TransportError::NO_VIABLE_PATH(
2537                                "last path abandoned, no new path opened",
2538                            );
2539                            self.close_common();
2540                            self.set_close_timer(now);
2541                            self.connection_close_pending = true;
2542                            self.state.move_to_closed(err);
2543                        }
2544                    }
2545                    ConnTimer::NatTraversalProbeRetry => {
2546                        self.n0_nat_traversal.queue_retries(self.is_ipv6());
2547                        if let Some(delay) =
2548                            self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
2549                        {
2550                            self.timers.set(
2551                                Timer::Conn(ConnTimer::NatTraversalProbeRetry),
2552                                now + delay,
2553                                self.qlog.with_time(now),
2554                            );
2555                            trace!("re-queued NAT probes");
2556                        } else {
2557                            trace!("no more NAT probes remaining");
2558                        }
2559                    }
2560                },
2561                Timer::PerPath(path_id, timer) => {
2562                    match timer {
2563                        PathTimer::PathIdle => {
2564                            if let Err(err) =
2565                                self.close_path_inner(now, path_id, PathAbandonReason::TimedOut)
2566                            {
2567                                warn!(?err, "failed closing path");
2568                            }
2569                        }
2570
2571                        PathTimer::PathKeepAlive => {
2572                            self.ping_path(path_id).ok();
2573                        }
2574                        PathTimer::LossDetection => {
2575                            self.on_loss_detection_timeout(now, path_id);
2576                            if let Some(path) = self.paths.get_mut(&path_id) {
2577                                self.qlog
2578                                    .emit_recovery_metrics(path_id, &mut path.data, now);
2579                            } else {
2580                                error!("LossDetection fired for unknown path");
2581                            }
2582                        }
2583                        PathTimer::PathValidationFailed => {
2584                            let Some(path) = self.paths.get_mut(&path_id) else {
2585                                continue;
2586                            };
2587                            self.timers.stop(
2588                                Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2589                                self.qlog.with_time(now),
2590                            );
2591                            debug!("path migration validation failed");
2592                            path.data.reset_on_path_challenges();
2593                            if let Some((_, prev)) = path.prev.take() {
2594                                path.data = prev;
2595                                self.set_loss_detection_timer(now, path_id);
2596                            }
2597                        }
2598                        PathTimer::PathChallengeLost => {
2599                            let Some(path) = self.paths.get_mut(&path_id) else {
2600                                continue;
2601                            };
2602                            trace!(?path.data.lost_challenge_count, "path challenge deemed lost");
2603                            path.data.pending_challenge = true;
2604                            path.data.lost_challenge_count += 1;
2605                            self.timers.set(
2606                                Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2607                                now + path.data.on_path_challenge_pto(),
2608                                self.qlog.with_time(now),
2609                            );
2610                        }
2611                        PathTimer::Pacing => {}
2612                        PathTimer::MaxAckDelay => {
2613                            // This timer is only armed in the Data space
2614                            self.spaces[SpaceId::Data]
2615                                .for_path(path_id)
2616                                .pending_acks
2617                                .on_max_ack_delay_timeout()
2618                        }
2619                        PathTimer::PathDrained => {
2620                            // The path was abandoned and 3*PTO has expired since.  Clean up all
2621                            // remaining state and install stateless reset token.
2622                            self.timers.stop_per_path(path_id, self.qlog.with_time(now));
2623                            if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) {
2624                                debug_assert!(!self.state.is_drained()); // requirement for endpoint_events. All timers should be cleared in drained connections.
2625                                let (min_seq, max_seq) = local_cid_state.active_seq();
2626                                for seq in min_seq..=max_seq {
2627                                    self.endpoint_events.push_back(
2628                                        EndpointEventInner::RetireConnectionId(
2629                                            now, path_id, seq, false,
2630                                        ),
2631                                    );
2632                                }
2633                            }
2634                            self.discard_path(path_id, now);
2635                        }
2636                    }
2637                }
2638            }
2639        }
2640    }
2641
2642    /// Close a connection immediately
2643    ///
2644    /// This does not ensure delivery of outstanding data. It is the application's responsibility to
2645    /// call this only when all important communications have been completed, e.g. by calling
2646    /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding
2647    /// [`StreamEvent::Finished`] event.
2648    ///
2649    /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been
2650    /// delivered. There may still be data from the peer that has not been received.
2651    ///
2652    /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished
2653    pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) {
2654        self.close_inner(
2655            now,
2656            Close::Application(frame::ApplicationClose { error_code, reason }),
2657        )
2658    }
2659
2660    /// Close the connection immediately, initiated by an API call.
2661    ///
2662    /// This will not produce a [`ConnectionLost`] event propagated by the
2663    /// [`Connection::poll`] call, because the API call already propagated the error to the
2664    /// user.
2665    ///
2666    /// Not to be used when entering immediate close due to an internal state change based
2667    /// on an event. See [`State::move_to_closed_local`] for details.
2668    ///
2669    /// This initiates immediate close from
2670    /// <https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2>, moving to the closed
2671    /// state.
2672    ///
2673    /// [`ConnectionLost`]: crate::Event::ConnectionLost
2674    /// [`Connection::poll`]: super::Connection::poll
2675    fn close_inner(&mut self, now: Instant, reason: Close) {
2676        let was_closed = self.state.is_closed();
2677        if !was_closed {
2678            self.close_common();
2679            self.set_close_timer(now);
2680            self.connection_close_pending = true;
2681            self.state.move_to_closed_local(reason);
2682        }
2683    }
2684
2685    /// Control datagrams
2686    pub fn datagrams(&mut self) -> Datagrams<'_> {
2687        Datagrams { conn: self }
2688    }
2689
2690    /// Returns connection statistics
2691    pub fn stats(&mut self) -> ConnectionStats {
2692        let mut stats = self.partial_stats.clone();
2693
2694        for path_stats in self.path_stats.iter_stats() {
2695            // Self::path_stats() computes the path rtt, cwnd and current_mtu on access
2696            // because they are not simple counters. When computing the connection stats we
2697            // can skip that effort since those fields are not used in the `impl
2698            // Add<PathStats> for ConnectionStats`.
2699            stats += *path_stats;
2700        }
2701
2702        stats
2703    }
2704
2705    /// Returns path statistics
2706    pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> {
2707        let path = self.paths.get(&path_id)?;
2708        let mut stats = self.path_stats.get(path_id).unwrap_or_default();
2709        stats.rtt = path.data.rtt.get();
2710        stats.cwnd = path.data.congestion.window();
2711        stats.current_mtu = path.data.mtud.current_mtu();
2712        Some(stats)
2713    }
2714
2715    /// Ping the remote endpoint
2716    ///
2717    /// Causes an ACK-eliciting packet to be transmitted on the connection.
2718    pub fn ping(&mut self) {
2719        // TODO(flub): This is very brute-force: it pings *all* the paths.  Instead it would
2720        //    be nice if we could only send a single packet for this.
2721        for path_data in self.spaces[self.highest_space].number_spaces.values_mut() {
2722            path_data.pending_ping = true;
2723        }
2724    }
2725
2726    /// Ping the remote endpoint over a specific path
2727    ///
2728    /// Causes an ACK-eliciting packet to be transmitted on the path.
2729    pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> {
2730        let path_data = self.spaces[self.highest_space]
2731            .number_spaces
2732            .get_mut(&path)
2733            .ok_or(ClosedPath { _private: () })?;
2734        path_data.pending_ping = true;
2735        Ok(())
2736    }
2737
2738    /// Update traffic keys spontaneously
2739    ///
2740    /// This can be useful for testing key updates, as they otherwise only happen infrequently.
2741    pub fn force_key_update(&mut self) {
2742        if !self.state.is_established() {
2743            debug!("ignoring forced key update in illegal state");
2744            return;
2745        }
2746        if self.crypto_state.prev_crypto.is_some() {
2747            // We already just updated, or are currently updating, the keys. Concurrent key updates
2748            // are illegal.
2749            debug!("ignoring redundant forced key update");
2750            return;
2751        }
2752        self.crypto_state.update_keys(None, false);
2753    }
2754
2755    /// Get a session reference
2756    pub fn crypto_session(&self) -> &dyn crypto::Session {
2757        self.crypto_state.session.as_ref()
2758    }
2759
2760    /// Whether the connection is in the process of being established
2761    ///
2762    /// If this returns `false`, the connection may be either established or closed, signaled by the
2763    /// emission of a [`Connected`](Event::Connected) or [`ConnectionLost`](Event::ConnectionLost)
2764    /// event respectively. Note that locally-initiated closes via [`close()`](Self::close) do not
2765    /// emit a `ConnectionLost` event.
2766    ///
2767    /// For an established connection this essentially means the handshake is **completed**,
2768    /// but not necessarily yet confirmed.
2769    pub fn is_handshaking(&self) -> bool {
2770        self.state.is_handshake()
2771    }
2772
2773    /// Whether the connection is closed
2774    ///
2775    /// Closed connections cannot transport any further data. A connection becomes closed when
2776    /// either peer application intentionally closes it, or when either transport layer detects an
2777    /// error such as a time-out or certificate validation failure.
2778    ///
2779    /// A [`ConnectionLost`](Event::ConnectionLost) event is emitted with details when the
2780    /// connection is closed by the peer or due to an error. When the local application closes
2781    /// the connection via [`close()`](Self::close), no `ConnectionLost` event is emitted;
2782    /// instead, pending operations fail with [`ConnectionError::LocallyClosed`].
2783    pub fn is_closed(&self) -> bool {
2784        self.state.is_closed()
2785    }
2786
2787    /// Whether there is no longer any need to keep the connection around
2788    ///
2789    /// Closed connections become drained after a brief timeout to absorb any remaining in-flight
2790    /// packets from the peer. All drained connections have been closed.
2791    pub fn is_drained(&self) -> bool {
2792        self.state.is_drained()
2793    }
2794
2795    /// For clients, if the peer accepted the 0-RTT data packets
2796    ///
2797    /// The value is meaningless until after the handshake completes.
2798    pub fn accepted_0rtt(&self) -> bool {
2799        self.crypto_state.accepted_0rtt
2800    }
2801
2802    /// Whether 0-RTT is/was possible during the handshake
2803    pub fn has_0rtt(&self) -> bool {
2804        self.crypto_state.zero_rtt_enabled
2805    }
2806
2807    /// Whether there are any pending retransmits
2808    pub fn has_pending_retransmits(&self) -> bool {
2809        !self.spaces[SpaceId::Data].pending.is_empty(&self.streams)
2810    }
2811
2812    /// Look up whether we're the client or server of this Connection
2813    pub fn side(&self) -> Side {
2814        self.side.side()
2815    }
2816
2817    /// Get the address observed by the remote over the given path
2818    pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> {
2819        self.path(path_id)
2820            .map(|path_data| {
2821                path_data
2822                    .last_observed_addr_report
2823                    .as_ref()
2824                    .map(|observed| observed.socket_addr())
2825            })
2826            .ok_or(ClosedPath { _private: () })
2827    }
2828
2829    /// Current best estimate of this connection's latency (round-trip-time)
2830    pub fn rtt(&self, path_id: PathId) -> Option<Duration> {
2831        self.path(path_id).map(|d| d.rtt.get())
2832    }
2833
2834    /// Current state of this connection's congestion controller, for debugging purposes
2835    pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> {
2836        self.path(path_id).map(|d| d.congestion.as_ref())
2837    }
2838
2839    /// Modify the number of remotely initiated streams that may be concurrently open
2840    ///
2841    /// No streams may be opened by the peer unless fewer than `count` are already open. Large
2842    /// `count`s increase both minimum and worst-case memory consumption.
2843    pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) {
2844        self.streams.set_max_concurrent(dir, count);
2845        // If the limit was reduced, then a flow control update previously deemed insignificant may
2846        // now be significant.
2847        let pending = &mut self.spaces[SpaceId::Data].pending;
2848        self.streams.queue_max_stream_id(pending);
2849    }
2850
2851    /// Modify the number of open paths allowed when multipath is enabled
2852    ///
2853    /// When reducing the number of concurrent paths this will only affect delaying sending
2854    /// new MAX_PATH_ID frames until fewer than this number of paths are possible.  To
2855    /// actively reduce paths they must be closed using [`Connection::close_path`], which
2856    /// can also be used to close not-yet-opened paths.
2857    ///
2858    /// If multipath is not negotiated (see the [`TransportConfig`]) this can not enable
2859    /// multipath and will fail.
2860    pub fn set_max_concurrent_paths(
2861        &mut self,
2862        now: Instant,
2863        count: NonZeroU32,
2864    ) -> Result<(), MultipathNotNegotiated> {
2865        if !self.is_multipath_negotiated() {
2866            return Err(MultipathNotNegotiated { _private: () });
2867        }
2868        self.max_concurrent_paths = count;
2869
2870        let in_use_count = self
2871            .local_max_path_id
2872            .next()
2873            .saturating_sub(self.abandoned_paths.len())
2874            .as_u32();
2875        let extra_needed = count.get().saturating_sub(in_use_count);
2876        let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed);
2877
2878        self.set_max_path_id(now, new_max_path_id);
2879
2880        Ok(())
2881    }
2882
2883    /// If needed, issues a new MAX_PATH_ID frame and new CIDs for any newly allowed paths
2884    fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) {
2885        if max_path_id <= self.local_max_path_id {
2886            return;
2887        }
2888
2889        self.local_max_path_id = max_path_id;
2890        self.spaces[SpaceId::Data].pending.max_path_id = true;
2891
2892        self.issue_first_path_cids(now);
2893    }
2894
2895    /// Current number of remotely initiated streams that may be concurrently open
2896    ///
2897    /// If the target for this limit is reduced using
2898    /// [`set_max_concurrent_streams`](Self::set_max_concurrent_streams), it will not change
2899    /// immediately, even if fewer streams are open. Instead, it will decrement by one for each
2900    /// time a remotely initiated stream of matching directionality is closed.
2901    pub fn max_concurrent_streams(&self, dir: Dir) -> u64 {
2902        self.streams.max_concurrent(dir)
2903    }
2904
2905    /// See [`TransportConfig::send_window()`]
2906    pub fn set_send_window(&mut self, send_window: u64) {
2907        self.streams.set_send_window(send_window);
2908    }
2909
2910    /// See [`TransportConfig::receive_window()`]
2911    pub fn set_receive_window(&mut self, receive_window: VarInt) {
2912        if self.streams.set_receive_window(receive_window) {
2913            self.spaces[SpaceId::Data].pending.max_data = true;
2914        }
2915    }
2916
2917    /// Whether the Multipath for QUIC extension is enabled.
2918    ///
2919    /// Multipath is only enabled after the handshake is completed and if it was enabled by both
2920    /// peers.
2921    pub fn is_multipath_negotiated(&self) -> bool {
2922        !self.is_handshaking()
2923            && self.config.max_concurrent_multipath_paths.is_some()
2924            && self.peer_params.initial_max_path_id.is_some()
2925    }
2926
2927    fn on_ack_received(
2928        &mut self,
2929        now: Instant,
2930        space: SpaceId,
2931        ack: frame::Ack,
2932    ) -> Result<(), TransportError> {
2933        // All ACKs are referencing path 0
2934        let path = PathId::ZERO;
2935        self.inner_on_ack_received(now, space, path, ack)
2936    }
2937
2938    fn on_path_ack_received(
2939        &mut self,
2940        now: Instant,
2941        space: SpaceId,
2942        path_ack: frame::PathAck,
2943    ) -> Result<(), TransportError> {
2944        let (ack, path) = path_ack.into_ack();
2945        self.inner_on_ack_received(now, space, path, ack)
2946    }
2947
2948    /// Handles an ACK frame acknowledging packets sent on *path*.
2949    fn inner_on_ack_received(
2950        &mut self,
2951        now: Instant,
2952        space: SpaceId,
2953        path: PathId,
2954        ack: frame::Ack,
2955    ) -> Result<(), TransportError> {
2956        if !self.spaces[space].number_spaces.contains_key(&path) {
2957            if self.abandoned_paths.contains(&path) {
2958                // See also
2959                // https://www.ietf.org/archive/id/draft-ietf-quic-multipath-21.html#section-3.4.3-3
2960                // > When an endpoint finally deletes all state associated with the path [...]
2961                // > PATH_ACK frames received with an abandoned path ID are silently ignored,
2962                // > as specified in Section 4.
2963                trace!("silently ignoring PATH_ACK on discarded path");
2964                return Ok(());
2965            } else {
2966                return Err(TransportError::PROTOCOL_VIOLATION(
2967                    "received PATH_ACK with path ID never used",
2968                ));
2969            }
2970        }
2971        if ack.largest >= self.spaces[space].for_path(path).next_packet_number {
2972            return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked"));
2973        }
2974        // `Some(pn)` if this ACK raised `largest_acked_packet_pn`.
2975        let new_largest_pn = {
2976            let space = &mut self.spaces[space].for_path(path);
2977            if space
2978                .largest_acked_packet_pn
2979                .is_none_or(|pn| ack.largest > pn)
2980            {
2981                space.largest_acked_packet_pn = Some(ack.largest);
2982                if let Some(info) = space.sent_packets.get(ack.largest) {
2983                    // This should always succeed, but a misbehaving peer might ACK a packet we
2984                    // haven't sent. At worst, that will result in us spuriously reducing the
2985                    // congestion window.
2986                    space.largest_acked_packet_send_time = info.time_sent;
2987                }
2988                Some(ack.largest)
2989            } else {
2990                None
2991            }
2992        };
2993
2994        if self.detect_spurious_loss(&ack, space, path) {
2995            self.path_stats.get_mut(path).spurious_congestion_events += 1;
2996            self.path_data_mut(path)
2997                .congestion
2998                .on_spurious_congestion_event();
2999        }
3000
3001        // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks.
3002        let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new();
3003        for range in ack.iter() {
3004            self.spaces[space].for_path(path).check_ack(range.clone())?;
3005            for (pn, _) in self.spaces[space]
3006                .for_path(path)
3007                .sent_packets
3008                .iter_range(range)
3009            {
3010                newly_acked.insert_one(pn);
3011            }
3012        }
3013
3014        if newly_acked.is_empty() {
3015            return Ok(());
3016        }
3017
3018        let mut ack_eliciting_acked = false;
3019        for packet in newly_acked.elts() {
3020            if let Some(info) = self.spaces[space].for_path(path).take(packet) {
3021                for (acked_path_id, acked_pn) in info.largest_acked.iter() {
3022                    // Assume ACKs for all packets below the largest acknowledged in
3023                    // `packet` have been received. This can cause the peer to spuriously
3024                    // retransmit if some of our earlier ACKs were lost, but allows for
3025                    // simpler state tracking. See discussion at
3026                    // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking
3027                    if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) {
3028                        pns.pending_acks.subtract_below(*acked_pn);
3029                    }
3030                }
3031                ack_eliciting_acked |= info.ack_eliciting;
3032
3033                // Notify MTU discovery that a packet was acked, because it might be an MTU probe
3034                let path_data = self.path_data_mut(path);
3035                let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size);
3036                if mtu_updated {
3037                    path_data
3038                        .congestion
3039                        .on_mtu_update(path_data.mtud.current_mtu());
3040                }
3041
3042                // Notify ack frequency that a packet was acked, because it might contain an
3043                // ACK_FREQUENCY frame
3044                self.ack_frequency.on_acked(path, packet);
3045
3046                self.on_packet_acked(now, path, space.kind(), packet, info);
3047            }
3048        }
3049
3050        let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn;
3051        let path_data = self.path_data_mut(path);
3052        let app_limited = path_data.app_limited;
3053        let in_flight = path_data.in_flight.bytes;
3054
3055        path_data
3056            .congestion
3057            .on_end_acks(now, in_flight, app_limited, largest_ackd);
3058
3059        if new_largest_pn.is_some() && ack_eliciting_acked {
3060            let ack_delay = if space != SpaceId::Data {
3061                Duration::from_micros(0)
3062            } else {
3063                cmp::min(
3064                    self.ack_frequency.peer_max_ack_delay,
3065                    Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0),
3066                )
3067            };
3068            let rtt = now.saturating_duration_since(
3069                self.spaces[space]
3070                    .for_path(path)
3071                    .largest_acked_packet_send_time,
3072            );
3073
3074            let next_pn = self.spaces[space].for_path(path).next_packet_number;
3075            let path_data = self.path_data_mut(path);
3076            // TODO(@divma): should be a method of path, should be contained in a single place
3077            path_data.rtt.update(ack_delay, rtt);
3078            if path_data.first_packet_after_rtt_sample.is_none() {
3079                path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn));
3080            }
3081        }
3082
3083        // Must be called before crypto/pto_count are clobbered
3084        self.detect_lost_packets(now, space, path, true);
3085
3086        // If the peer did not complete the handshake address validation the ACK could be
3087        // spoofed, e.g. in the Initial space. Setting the pto_count back to 0 removes the
3088        // exponential backoff from the PTO timer and would result in too many tail-loss
3089        // probes being sent.
3090        if self.peer_completed_handshake_address_validation() {
3091            self.path_data_mut(path).pto_count = 0;
3092        }
3093
3094        // Explicit congestion notification
3095        // TODO(@divma): this code is a good example of logic that should be contained in a single
3096        // place but it's split between the path data and the packet number space data, we should
3097        // find a way to make this work without two lookups
3098        if self.path_data(path).sending_ecn {
3099            if let Some(ecn) = ack.ecn {
3100                // We only examine ECN counters from ACKs that we are certain we received in
3101                // transmit order, allowing us to compute an increase in ECN counts
3102                // to compare against the number of newly acked packets that remains
3103                // well-defined in the presence of arbitrary packet reordering.
3104                if let Some(largest_sent_pn) = new_largest_pn {
3105                    let sent = self.spaces[space]
3106                        .for_path(path)
3107                        .largest_acked_packet_send_time;
3108                    self.process_ecn(
3109                        now,
3110                        space,
3111                        path,
3112                        newly_acked.range_count() as u64,
3113                        ecn,
3114                        sent,
3115                        largest_sent_pn,
3116                    );
3117                }
3118            } else {
3119                // We always start out sending ECN, so any ack that doesn't acknowledge it disables
3120                // it.
3121                debug!("ECN not acknowledged by peer");
3122                self.path_data_mut(path).sending_ecn = false;
3123            }
3124        }
3125
3126        self.set_loss_detection_timer(now, path);
3127        Ok(())
3128    }
3129
3130    fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool {
3131        let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3132
3133        if lost_packets.is_empty() {
3134            return false;
3135        }
3136
3137        for range in ack.iter() {
3138            let spurious_losses: Vec<u64> = lost_packets
3139                .iter_range(range.clone())
3140                .map(|(pn, _info)| pn)
3141                .collect();
3142
3143            for pn in spurious_losses {
3144                lost_packets.remove(pn);
3145            }
3146        }
3147
3148        // If this ACK frame acknowledged all deemed lost packets,
3149        // then we have raised a spurious congestion event in the past.
3150        // We cannot conclude when there are remaining packets,
3151        // but future ACK frames might indicate a spurious loss detection.
3152        lost_packets.is_empty()
3153    }
3154
3155    /// Drain lost packets that we reasonably think will never arrive
3156    ///
3157    /// The current criterion is copied from `msquic`:
3158    /// discard packets that were sent earlier than 2 probe timeouts ago.
3159    fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) {
3160        let two_pto = 2 * self.path_data(path).rtt.pto_base();
3161
3162        let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3163        lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto);
3164    }
3165
3166    /// Process a new ECN block from an in-order ACK
3167    fn process_ecn(
3168        &mut self,
3169        now: Instant,
3170        space: SpaceId,
3171        path: PathId,
3172        newly_acked_pn: u64,
3173        ecn: frame::EcnCounts,
3174        largest_sent_time: Instant,
3175        largest_sent_pn: u64,
3176    ) {
3177        match self.spaces[space]
3178            .for_path(path)
3179            .detect_ecn(newly_acked_pn, ecn)
3180        {
3181            Err(e) => {
3182                debug!("halting ECN due to verification failure: {}", e);
3183
3184                self.path_data_mut(path).sending_ecn = false;
3185                // Wipe out the existing value because it might be garbage and could interfere with
3186                // future attempts to use ECN on new paths.
3187                self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO;
3188            }
3189            Ok(false) => {}
3190            Ok(true) => {
3191                self.path_stats.get_mut(path).congestion_events += 1;
3192                self.path_data_mut(path)
3193                    .congestion
3194                    .on_congestion_event_space(
3195                        now,
3196                        largest_sent_time,
3197                        false,
3198                        true,
3199                        0,
3200                        PacketId {
3201                            space: space.kind(),
3202                            number: largest_sent_pn,
3203                        },
3204                    );
3205            }
3206        }
3207    }
3208
3209    // Not timing-aware, so it's safe to call this for inferred acks, such as arise from
3210    // high-latency handshakes
3211    fn on_packet_acked(
3212        &mut self,
3213        now: Instant,
3214        path_id: PathId,
3215        space: SpaceKind,
3216        pn: u64,
3217        info: SentPacket,
3218    ) {
3219        let path = self.path_data_mut(path_id);
3220        let app_limited = path.app_limited;
3221        path.remove_in_flight(&info);
3222        if info.ack_eliciting && info.path_generation == path.generation() {
3223            // Only pass ACKs to the congestion controller if it belongs to this exact
3224            // generation of the path. Otherwise we might be feeding ACKs from the previous
3225            // 4-tuple into our congestion controller.
3226            let rtt = path.rtt;
3227            let packet = PacketId { space, number: pn };
3228            path.congestion.on_packet_space_acked(
3229                now,
3230                info.time_sent,
3231                info.size.into(),
3232                packet,
3233                app_limited,
3234                &rtt,
3235            );
3236        }
3237
3238        // Update state for confirmed delivery of frames
3239        if let Some(retransmits) = info.retransmits.get() {
3240            for (id, _) in retransmits.reset_stream.iter() {
3241                self.streams.reset_acked(*id);
3242            }
3243        }
3244
3245        for frame in info.stream_frames {
3246            self.streams.received_ack_of(frame);
3247        }
3248    }
3249
3250    fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) {
3251        let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) {
3252            now
3253        } else {
3254            self.crypto_state
3255                .prev_crypto
3256                .as_ref()
3257                .expect("no previous keys")
3258                .end_packet
3259                .as_ref()
3260                .expect("update not acknowledged yet")
3261                .1
3262        };
3263
3264        // QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO of all paths.
3265        self.timers.set(
3266            Timer::Conn(ConnTimer::KeyDiscard),
3267            start + self.max_pto_for_space(space) * 3,
3268            self.qlog.with_time(now),
3269        );
3270    }
3271
3272    /// Handle a [`PathTimer::LossDetection`] timeout.
3273    ///
3274    /// This timer expires for two reasons:
3275    /// - An ACK-eliciting packet we sent should be considered lost.
3276    /// - The PTO may have expired and a tail-loss probe needs to be scheduled.
3277    ///
3278    /// The former needs us to schedule re-transmission of the lost data.
3279    ///
3280    /// The latter means we have not received an ACK for an ack-eliciting packet we sent
3281    /// within the PTO time-window. We need to schedule a tail-loss probe, an ack-eliciting
3282    /// packet, to try and elicit new acknowledgements. These new acknowledgements will
3283    /// indicate whether the previously sent packets were lost or not.
3284    fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) {
3285        if let Some((_, pn_space)) = self.loss_time_and_space(path_id) {
3286            // Time threshold loss Detection
3287            self.detect_lost_packets(now, pn_space, path_id, false);
3288            self.set_loss_detection_timer(now, path_id);
3289            return;
3290        }
3291
3292        let Some((_, space)) = self.pto_time_and_space(now, path_id) else {
3293            debug!(%path_id, "PTO expired while unset");
3294            return;
3295        };
3296        trace!(
3297            in_flight = self.path_data(path_id).in_flight.bytes,
3298            count = self.path_data(path_id).pto_count,
3299            ?space,
3300            %path_id,
3301            "PTO fired"
3302        );
3303
3304        let count = match self.path_data(path_id).in_flight.ack_eliciting {
3305            // A PTO when we're not expecting any ACKs must be due to handshake
3306            // anti-amplification deadlock prevention.
3307            0 => {
3308                debug_assert!(!self.peer_completed_handshake_address_validation());
3309                1
3310            }
3311            // Conventional loss probe
3312            _ => 2,
3313        };
3314        let pns = self.spaces[space].for_path(path_id);
3315        pns.loss_probes = pns.loss_probes.saturating_add(count);
3316        let path_data = self.path_data_mut(path_id);
3317        path_data.pto_count = path_data.pto_count.saturating_add(1);
3318        self.set_loss_detection_timer(now, path_id);
3319    }
3320
3321    /// Detect any lost packets
3322    ///
3323    /// There are two cases in which we detects lost packets:
3324    ///
3325    /// - We received an ACK packet.
3326    /// - The [`PathTimer::LossDetection`] timer expired. So there is an un-acknowledged packet that
3327    ///   was followed by an acknowledged packet. The loss timer for this un-acknowledged packet
3328    ///   expired and we need to detect that packet as lost.
3329    ///
3330    /// Packets are lost if they are both (See RFC9002 §6.1):
3331    ///
3332    /// - Unacknowledged, in flight and sent prior to an acknowledged packet.
3333    /// - Old enough by either:
3334    ///   - Having a packet number [`TransportConfig::packet_threshold`] lower then the last
3335    ///     acknowledged packet.
3336    ///   - Being sent [`TransportConfig::time_threshold`] * RTT in the past.
3337    fn detect_lost_packets(
3338        &mut self,
3339        now: Instant,
3340        pn_space: SpaceId,
3341        path_id: PathId,
3342        due_to_ack: bool,
3343    ) {
3344        let mut lost_packets = Vec::<u64>::new();
3345        let mut lost_mtu_probe = None;
3346        let mut in_persistent_congestion = false;
3347        let mut size_of_lost_packets = 0u64;
3348        self.spaces[pn_space].for_path(path_id).loss_time = None;
3349
3350        // Find all the lost packets, populating all variables initialised above.
3351
3352        let path = self.path_data(path_id);
3353        let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3354        let loss_delay = path
3355            .rtt
3356            .conservative()
3357            .mul_f32(self.config.time_threshold)
3358            .max(TIMER_GRANULARITY);
3359        let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample;
3360
3361        let largest_acked_packet_pn = self.spaces[pn_space]
3362            .for_path(path_id)
3363            .largest_acked_packet_pn
3364            .expect("detect_lost_packets only to be called if path received at least one ACK");
3365        let packet_threshold = self.config.packet_threshold as u64;
3366
3367        // InPersistentCongestion: Determine if all packets in the time period before the newest
3368        // lost packet, including the edges, are marked lost. PTO computation must always
3369        // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1).
3370        let congestion_period = self
3371            .pto(SpaceKind::Data, path_id)
3372            .saturating_mul(self.config.persistent_congestion_threshold);
3373        let mut persistent_congestion_start: Option<Instant> = None;
3374        let mut prev_packet = None;
3375        let space = self.spaces[pn_space].for_path(path_id);
3376
3377        for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) {
3378            if prev_packet != Some(packet.wrapping_sub(1)) {
3379                // An intervening packet was acknowledged
3380                persistent_congestion_start = None;
3381            }
3382
3383            // Packets sent before now - loss_delay are deemed lost.
3384            // However, we avoid subtraction as it can panic and there's no
3385            // saturating equivalent of this subtraction operation with a Duration.
3386            let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay;
3387            if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold {
3388                // The packet should be declared lost.
3389                if Some(packet) == in_flight_mtu_probe {
3390                    // Lost MTU probes are not included in `lost_packets`, because they
3391                    // should not trigger a congestion control response
3392                    lost_mtu_probe = in_flight_mtu_probe;
3393                } else {
3394                    lost_packets.push(packet);
3395                    size_of_lost_packets += info.size as u64;
3396                    if info.ack_eliciting && due_to_ack {
3397                        match persistent_congestion_start {
3398                            // Two ACK-eliciting packets lost more than
3399                            // congestion_period apart, with no ACKed packets in between
3400                            Some(start) if info.time_sent - start > congestion_period => {
3401                                in_persistent_congestion = true;
3402                            }
3403                            // Persistent congestion must start after the first RTT sample
3404                            None if first_packet_after_rtt_sample
3405                                .is_some_and(|x| x < (pn_space.kind(), packet)) =>
3406                            {
3407                                persistent_congestion_start = Some(info.time_sent);
3408                            }
3409                            _ => {}
3410                        }
3411                    }
3412                }
3413            } else {
3414                // The packet should not yet be declared lost.
3415                if space.loss_time.is_none() {
3416                    // Since we iterate in order the lowest packet number's loss time will
3417                    // always be the earliest.
3418                    space.loss_time = Some(info.time_sent + loss_delay);
3419                }
3420                persistent_congestion_start = None;
3421            }
3422
3423            prev_packet = Some(packet);
3424        }
3425
3426        self.handle_lost_packets(
3427            pn_space,
3428            path_id,
3429            now,
3430            lost_packets,
3431            lost_mtu_probe,
3432            loss_delay,
3433            in_persistent_congestion,
3434            size_of_lost_packets,
3435        );
3436    }
3437
3438    /// Drops the path state, declaring any remaining in-flight packets as lost
3439    fn discard_path(&mut self, path_id: PathId, now: Instant) {
3440        trace!(%path_id, "dropping path state");
3441        let path = self.path_data(path_id);
3442        let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3443
3444        let mut size_of_lost_packets = 0u64; // add to path_stats.lost_bytes;
3445        let lost_pns: Vec<_> = self.spaces[SpaceId::Data]
3446            .for_path(path_id)
3447            .sent_packets
3448            .iter()
3449            .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe)
3450            .map(|(pn, info)| {
3451                size_of_lost_packets += info.size as u64;
3452                pn
3453            })
3454            .collect();
3455
3456        if !lost_pns.is_empty() {
3457            trace!(
3458                %path_id,
3459                count = lost_pns.len(),
3460                lost_bytes = size_of_lost_packets,
3461                "packets lost on path abandon"
3462            );
3463            self.handle_lost_packets(
3464                SpaceId::Data,
3465                path_id,
3466                now,
3467                lost_pns,
3468                in_flight_mtu_probe,
3469                Duration::ZERO,
3470                false,
3471                size_of_lost_packets,
3472            );
3473        }
3474        // Before removing the path, we fetch the final path stats via `Self::path_stats`.
3475        // This ensures snapshot values (like rtt) are properly updated.
3476        let path_stats = self.path_stats(path_id).unwrap_or_default();
3477        self.path_stats.discard(&path_id);
3478        self.partial_stats += path_stats;
3479        self.paths.remove(&path_id);
3480        self.spaces[SpaceId::Data].number_spaces.remove(&path_id);
3481
3482        self.events.push_back(
3483            PathEvent::Discarded {
3484                id: path_id,
3485                path_stats: Box::new(path_stats),
3486            }
3487            .into(),
3488        );
3489    }
3490
3491    fn handle_lost_packets(
3492        &mut self,
3493        pn_space: SpaceId,
3494        path_id: PathId,
3495        now: Instant,
3496        lost_packets: Vec<u64>,
3497        lost_mtu_probe: Option<u64>,
3498        loss_delay: Duration,
3499        in_persistent_congestion: bool,
3500        size_of_lost_packets: u64,
3501    ) {
3502        debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted");
3503
3504        self.drain_lost_packets(now, pn_space, path_id);
3505
3506        // OnPacketsLost
3507        if let Some(largest_lost) = lost_packets.last().cloned() {
3508            let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes;
3509            let largest_lost_sent = self.spaces[pn_space]
3510                .for_path(path_id)
3511                .sent_packets
3512                .get(largest_lost)
3513                .unwrap()
3514                .time_sent;
3515            let path_stats = self.path_stats.get_mut(path_id);
3516            path_stats.lost_packets += lost_packets.len() as u64;
3517            path_stats.lost_bytes += size_of_lost_packets;
3518            trace!(
3519                %path_id,
3520                count = lost_packets.len(),
3521                lost_bytes = size_of_lost_packets,
3522                "packets lost",
3523            );
3524
3525            for &packet in &lost_packets {
3526                let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else {
3527                    continue;
3528                };
3529                self.qlog
3530                    .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now);
3531                self.paths
3532                    .get_mut(&path_id)
3533                    .unwrap()
3534                    .remove_in_flight(&info);
3535
3536                for frame in info.stream_frames {
3537                    self.streams.retransmit(frame);
3538                }
3539                self.spaces[pn_space].pending |= info.retransmits;
3540                let path = self.path_data_mut(path_id);
3541                path.pending |= info.path_retransmits;
3542                path.mtud.on_non_probe_lost(packet, info.size);
3543                let lost = PacketId {
3544                    space: pn_space.kind(),
3545                    number: packet,
3546                };
3547                path.congestion.on_packet_space_lost(info.size, lost, now);
3548
3549                self.spaces[pn_space].for_path(path_id).lost_packets.insert(
3550                    packet,
3551                    LostPacket {
3552                        time_sent: info.time_sent,
3553                    },
3554                );
3555            }
3556
3557            let path = self.path_data_mut(path_id);
3558            if path.mtud.black_hole_detected(now) {
3559                path.congestion.on_mtu_update(path.mtud.current_mtu());
3560                if let Some(max_datagram_size) = self.datagrams().max_size()
3561                    && self.datagrams.drop_oversized(max_datagram_size)
3562                    && self.datagrams.send_blocked
3563                {
3564                    self.datagrams.send_blocked = false;
3565                    self.events.push_back(Event::DatagramsUnblocked);
3566                }
3567                self.path_stats.get_mut(path_id).black_holes_detected += 1;
3568            }
3569
3570            // Don't apply congestion penalty for lost ack-only packets
3571            let lost_ack_eliciting =
3572                old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes;
3573
3574            if lost_ack_eliciting {
3575                self.path_stats.get_mut(path_id).congestion_events += 1;
3576                self.path_data_mut(path_id)
3577                    .congestion
3578                    .on_congestion_event_space(
3579                        now,
3580                        largest_lost_sent,
3581                        in_persistent_congestion,
3582                        false,
3583                        size_of_lost_packets,
3584                        PacketId {
3585                            space: pn_space.kind(),
3586                            number: largest_lost,
3587                        },
3588                    );
3589            }
3590        }
3591
3592        // Handle a lost MTU probe
3593        if let Some(packet) = lost_mtu_probe {
3594            let info = self.spaces[SpaceId::Data]
3595                .for_path(path_id)
3596                .take(packet)
3597                .unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and
3598            // therefore must not have been removed yet
3599            self.paths
3600                .get_mut(&path_id)
3601                .unwrap()
3602                .remove_in_flight(&info);
3603            self.path_data_mut(path_id).mtud.on_probe_lost();
3604            self.path_stats.get_mut(path_id).lost_plpmtud_probes += 1;
3605        }
3606    }
3607
3608    /// Returns the earliest time packets should be declared lost for all spaces on a path.
3609    ///
3610    /// If a path has an acknowledged packet with any prior un-acknowledged packets, the
3611    /// earliest un-acknowledged packet can be declared lost after a timeout has elapsed.
3612    /// The time returned is when this packet should be declared lost.
3613    fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> {
3614        SpaceId::iter()
3615            .filter_map(|id| {
3616                self.spaces[id]
3617                    .number_spaces
3618                    .get(&path_id)
3619                    .and_then(|pns| pns.loss_time)
3620                    .map(|time| (time, id))
3621            })
3622            .min_by_key(|&(time, _)| time)
3623    }
3624
3625    /// Returns the earliest next PTO should fire for all spaces on a path.
3626    ///
3627    /// This needs to be fully deterministic because it is also used to determine the PTO
3628    /// that fired, not just to set the next timer. So if it fired in the past it needs to
3629    /// return the time from the past at which it fired.
3630    ///
3631    /// This is the next time a tail-loss probe should be sent.
3632    fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> {
3633        let path = self.path(path_id)?;
3634        let pto_count = path.pto_count;
3635
3636        // The idle timeout the probes have to beat, as `reset_idle_timeout` arms it.
3637        let idle = if self.state.is_handshake() {
3638            Some(self.config.handshake_idle_timeout)
3639        } else {
3640            path.idle_timeout.or(self.idle_timeout)
3641        };
3642
3643        // Cap the maximum interval between two tail-loss probes.
3644        let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD {
3645            // For slow links we want to increase the interval beyond 2s.
3646            (path.rtt.get() * 3) / 2
3647        } else if let Some(idle) = idle
3648            && idle <= MIN_IDLE_FOR_FAST_PTO
3649        {
3650            // If the idle timeout is relatively low, cap at 1s so we get plenty of retries
3651            // before the idle timeout fires.
3652            MAX_PTO_FAST_INTERVAL
3653        } else {
3654            // Otherwise cap to 2s.
3655            MAX_PTO_INTERVAL
3656        };
3657
3658        if path_id == PathId::ZERO
3659            && path.in_flight.ack_eliciting == 0
3660            && !self.peer_completed_handshake_address_validation()
3661        {
3662            // Address Validation during Connection Establishment:
3663            // https://www.rfc-editor.org/rfc/rfc9000.html#section-8.1. To prevent a
3664            // deadlock if an Initial or Handshake packet from the server is lost and the
3665            // server can not send more due to its anti-amplification limit the client must
3666            // send another packet on PTO.
3667            let space = match self.highest_space {
3668                SpaceKind::Handshake => SpaceId::Handshake,
3669                _ => SpaceId::Initial,
3670            };
3671
3672            let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT));
3673            let duration = path.rtt.pto_base() * backoff;
3674            let duration = duration.min(max_interval);
3675            return Some((now + duration, space));
3676        }
3677
3678        let mut result = None;
3679        for space in SpaceId::iter() {
3680            let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else {
3681                continue;
3682            };
3683
3684            if space == SpaceId::Data && !self.is_handshake_confirmed() {
3685                // https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-7:
3686                // An endpoint MUST NOT set its PTO timer for the Application Data packet
3687                // number space until the handshake is confirmed.
3688                continue;
3689            }
3690
3691            if !pns.has_in_flight() {
3692                continue;
3693            }
3694
3695            // Compute the PTO duration for this space, we want to cap the maximum interval
3696            // between two tail-loss probes so to not do a simple exponential backoff but
3697            // rather iterate through the probes to compute the capped increment for an
3698            // exponential backoff at each step.
3699            let duration = {
3700                let max_ack_delay = if space == SpaceId::Data {
3701                    self.ack_frequency.max_ack_delay_for_pto()
3702                } else {
3703                    Duration::ZERO
3704                };
3705                let pto_base = path.rtt.pto_base() + max_ack_delay;
3706                let mut duration = pto_base;
3707                for i in 1..=pto_count {
3708                    let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT));
3709                    let max_duration = duration + max_interval;
3710                    duration = exponential_duration.min(max_duration);
3711                }
3712                duration
3713            };
3714
3715            let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else {
3716                continue;
3717            };
3718            // Base the deadline on when the last probe was sent, so the PTO
3719            // doesn't fire before the response has had time to arrive.
3720            let pto = last_ack_eliciting + duration;
3721            if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) {
3722                if path.anti_amplification_blocked(1) {
3723                    // Nothing would be able to be sent.
3724                    continue;
3725                }
3726                if path.in_flight.ack_eliciting == 0 {
3727                    // Nothing ack-eliciting, no PTO to arm/fire.
3728                    continue;
3729                }
3730                result = Some((pto, space));
3731            }
3732        }
3733        result
3734    }
3735
3736    /// Whether the peer validated our address in the connection handshake.
3737    fn peer_completed_handshake_address_validation(&self) -> bool {
3738        if self.side.is_server() || self.state.is_closed() {
3739            return true;
3740        }
3741        // The server is guaranteed to have validated our address if any of our handshake or
3742        // 1-RTT packets are acknowledged or we've seen HANDSHAKE_DONE and discarded
3743        // handshake keys.
3744        self.spaces[SpaceId::Handshake]
3745            .path_space(PathId::ZERO)
3746            .and_then(|pns| pns.largest_acked_packet_pn)
3747            .is_some()
3748            || self.spaces[SpaceId::Data]
3749                .path_space(PathId::ZERO)
3750                .and_then(|pns| pns.largest_acked_packet_pn)
3751                .is_some()
3752            || (self.crypto_state.has_keys(EncryptionLevel::OneRtt)
3753                && !self.crypto_state.has_keys(EncryptionLevel::Handshake))
3754    }
3755
3756    /// Resets the the [`PathTimer::LossDetection`] timer to the next instant it may be needed
3757    ///
3758    /// The timer must fire if either:
3759    /// - An ack-eliciting packet we sent needs to be declared lost.
3760    /// - A tail-loss probe needs to be sent.
3761    ///
3762    /// See [`Connection::on_loss_detection_timeout`] for details.
3763    fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) {
3764        if self.state.is_closed() {
3765            // No loss detection takes place on closed connections, and `close_common` already
3766            // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a
3767            // reordered packet being handled by state-insensitive code.
3768            return;
3769        }
3770
3771        if let Some((loss_time, _)) = self.loss_time_and_space(path_id) {
3772            // Time threshold loss detection.
3773            self.timers.set(
3774                Timer::PerPath(path_id, PathTimer::LossDetection),
3775                loss_time,
3776                self.qlog.with_time(now),
3777            );
3778            return;
3779        }
3780
3781        // Determine which PN space to arm PTO for.
3782        // We can only send tail-loss probes on paths that aren't abandoned yet.
3783        if !self.abandoned_paths.contains(&path_id)
3784            && let Some((timeout, _)) = self.pto_time_and_space(now, path_id)
3785        {
3786            self.timers.set(
3787                Timer::PerPath(path_id, PathTimer::LossDetection),
3788                timeout,
3789                self.qlog.with_time(now),
3790            );
3791        } else {
3792            self.timers.stop(
3793                Timer::PerPath(path_id, PathTimer::LossDetection),
3794                self.qlog.with_time(now),
3795            );
3796        }
3797    }
3798
3799    /// The maximum probe timeout across all paths
3800    ///
3801    /// See [`Connection::pto`]
3802    fn max_pto_for_space(&self, space: SpaceKind) -> Duration {
3803        self.paths
3804            .keys()
3805            .map(|path_id| self.pto(space, *path_id))
3806            .max()
3807            .unwrap_or_else(|| {
3808                // No paths remain (e.g. last path was abandoned and the NoAvailablePath grace timer
3809                // fired before any new path was opened). Fall back to a PTO derived from the
3810                // configured initial RTT, matching RFC 9002 §6.2.2 initial values.
3811                let rtt = self.config.initial_rtt;
3812                let max_ack_delay = match space {
3813                    SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3814                    SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3815                };
3816                rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay
3817            })
3818    }
3819
3820    /// Probe Timeout
3821    ///
3822    /// The PTO is logically the time in which you'd expect to receive an acknowledgement
3823    /// for a packet. So approximately RTT + max_ack_delay.
3824    fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration {
3825        let max_ack_delay = match space {
3826            SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3827            SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3828        };
3829        self.path_data(path_id).rtt.pto_base() + max_ack_delay
3830    }
3831
3832    fn on_packet_authenticated(
3833        &mut self,
3834        now: Instant,
3835        space_id: SpaceKind,
3836        path_id: PathId,
3837        ecn: Option<EcnCodepoint>,
3838        packet_number: Option<u64>,
3839        spin: bool,
3840        is_1rtt: bool,
3841        remote: &FourTuple,
3842    ) {
3843        // During the handshake we already have discarded packets that do not match the path
3844        // remote. So any off-path packet here is either a probing packet or a
3845        // migration. Handling probing packets here means that the path's idle timeout will
3846        // be reset and will delay detecting the path as idle. However tail-loss probes
3847        // would still not get acknowledged if the path was broken so eventually the path
3848        // would still become idle.
3849        let is_on_path = self
3850            .path_data(path_id)
3851            .network_path
3852            .is_probably_same_path(remote);
3853
3854        self.total_authed_packets += 1;
3855        self.reset_keep_alive(path_id, now);
3856        self.reset_idle_timeout(now, space_id, path_id);
3857        self.path_data_mut(path_id).permit_idle_reset = true;
3858
3859        // Do not process ECN for off-path packets. If this is a migration we'll get ECN
3860        // back once we've migrated.
3861        if is_on_path {
3862            self.receiving_ecn |= ecn.is_some();
3863            if let Some(x) = ecn {
3864                let space = &mut self.spaces[space_id];
3865                space.for_path(path_id).ecn_counters += x;
3866
3867                if x.is_ce() {
3868                    space
3869                        .for_path(path_id)
3870                        .pending_acks
3871                        .set_immediate_ack_required();
3872                }
3873            }
3874        }
3875
3876        let Some(packet_number) = packet_number else {
3877            return;
3878        };
3879        match &self.side {
3880            ConnectionSide::Client { .. } => {
3881                // If we received a handshake packet that authenticated, then we're talking to
3882                // the real server.  From now on we should no longer allow the server to migrate
3883                // its address.
3884                if space_id == SpaceKind::Handshake
3885                    && let Some(hs) = self.state.as_handshake_mut()
3886                {
3887                    hs.allow_server_migration = false;
3888                }
3889            }
3890            ConnectionSide::Server { .. } => {
3891                if self.crypto_state.has_keys(EncryptionLevel::Initial)
3892                    && space_id == SpaceKind::Handshake
3893                {
3894                    // A server stops sending and processing Initial packets when it receives its
3895                    // first Handshake packet.
3896                    self.discard_space(now, SpaceKind::Initial);
3897                }
3898                if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt {
3899                    // Discard 0-RTT keys soon after receiving a 1-RTT packet
3900                    self.set_key_discard_timer(now, space_id)
3901                }
3902            }
3903        }
3904        let space = self.spaces[space_id].for_path(path_id);
3905
3906        space.pending_acks.insert_one(packet_number, now);
3907        if packet_number >= space.largest_received_packet_number.unwrap_or_default() {
3908            space.largest_received_packet_number = Some(packet_number);
3909
3910            // Update outgoing spin bit for on-path packets, inverting iff we're the client
3911            if is_on_path {
3912                self.spin = self.side.is_client() ^ spin;
3913            }
3914        }
3915    }
3916
3917    /// Resets the idle timeout timers.
3918    ///
3919    /// Without multipath there is only the connection-wide idle timeout. When multipath is
3920    /// enabled there is an additional per-path idle timeout.
3921    fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
3922        // First reset the global idle timeout.
3923        let timeout = if self.state.is_closed() {
3924            None
3925        } else if self.state.is_handshake() {
3926            Some(self.config.handshake_idle_timeout)
3927        } else {
3928            self.idle_timeout
3929        };
3930        // A deadline too far out to represent never fires.
3931        let deadline = timeout.and_then(|timeout| {
3932            now.checked_add(cmp::max(timeout, 3 * self.max_pto_for_space(space)))
3933        });
3934        match deadline {
3935            Some(deadline) => {
3936                self.timers.set(
3937                    Timer::Conn(ConnTimer::Idle),
3938                    deadline,
3939                    self.qlog.with_time(now),
3940                );
3941            }
3942            None => self
3943                .timers
3944                .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now)),
3945        }
3946
3947        // Now handle the per-path state.
3948        self.rearm_path_max_idle_timer(now, space, path_id);
3949    }
3950
3951    /// Resets both the [`ConnTimer::KeepAlive`] and [`PathTimer::PathKeepAlive`] timers
3952    fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) {
3953        if !self.state.is_established() {
3954            return;
3955        }
3956
3957        if let Some(interval) = self.config.keep_alive_interval {
3958            self.timers.set(
3959                Timer::Conn(ConnTimer::KeepAlive),
3960                now + interval,
3961                self.qlog.with_time(now),
3962            );
3963        }
3964
3965        if let Some(interval) = self.path_data(path_id).keep_alive {
3966            self.timers.set(
3967                Timer::PerPath(path_id, PathTimer::PathKeepAlive),
3968                now + interval,
3969                self.qlog.with_time(now),
3970            );
3971        }
3972    }
3973
3974    /// Sets the timer for when a previously issued CID should be retired next
3975    fn reset_cid_retirement(&mut self, now: Instant) {
3976        if let Some((_path, t)) = self.next_cid_retirement() {
3977            self.timers.set(
3978                Timer::Conn(ConnTimer::PushNewCid),
3979                t,
3980                self.qlog.with_time(now),
3981            );
3982        }
3983    }
3984
3985    /// The next time when a previously issued CID should be retired
3986    fn next_cid_retirement(&self) -> Option<(PathId, Instant)> {
3987        self.local_cid_state
3988            .iter()
3989            .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t)))
3990            .min_by_key(|(_path_id, timeout)| *timeout)
3991    }
3992
3993    /// Handle the already-decrypted first packet from the client
3994    ///
3995    /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more
3996    /// efficient.
3997    pub(crate) fn handle_first_packet(
3998        &mut self,
3999        now: Instant,
4000        network_path: FourTuple,
4001        ecn: Option<EcnCodepoint>,
4002        packet_number: u64,
4003        packet: InitialPacket,
4004        remaining: Option<BytesMut>,
4005    ) -> Result<(), ConnectionError> {
4006        let span = trace_span!("first recv");
4007        let _guard = span.enter();
4008        debug_assert!(self.side.is_server());
4009        let len = packet.header_data.len() + packet.payload.len();
4010        let path_id = PathId::ZERO;
4011        self.path_data_mut(path_id).total_recvd = len as u64;
4012
4013        if let Some(hs) = self.state.as_handshake_mut() {
4014            hs.expected_token = packet.header.token.clone();
4015        } else {
4016            unreachable!("first packet must be delivered in Handshake state");
4017        }
4018
4019        // The first packet is always on PathId::ZERO
4020        self.on_packet_authenticated(
4021            now,
4022            SpaceKind::Initial,
4023            path_id,
4024            ecn,
4025            Some(packet_number),
4026            false,
4027            false,
4028            &network_path,
4029        );
4030
4031        let packet: Packet = packet.into();
4032
4033        let mut qlog = QlogRecvPacket::new(len);
4034        qlog.header(&packet.header, Some(packet_number), path_id);
4035
4036        self.process_decrypted_packet(
4037            now,
4038            network_path,
4039            path_id,
4040            Some(packet_number),
4041            packet,
4042            &mut qlog,
4043        )?;
4044        self.qlog.emit_packet_received(qlog, now);
4045        if let Some(data) = remaining {
4046            self.handle_coalesced(now, network_path, path_id, ecn, data);
4047        }
4048
4049        self.qlog.emit_recovery_metrics(
4050            path_id,
4051            &mut self
4052                .paths
4053                .get_mut(&path_id)
4054                .expect("path_id was supplied by the caller for an active path")
4055                .data,
4056            now,
4057        );
4058
4059        Ok(())
4060    }
4061
4062    fn init_0rtt(&mut self, now: Instant) {
4063        let Some((header, packet)) = self.crypto_state.session.early_crypto() else {
4064            return;
4065        };
4066        if self.side.is_client() {
4067            match self.crypto_state.session.transport_parameters() {
4068                Ok(params) => {
4069                    let params = params
4070                        .expect("crypto layer didn't supply transport parameters with ticket");
4071                    // Certain values must not be cached
4072                    let params = TransportParameters {
4073                        initial_src_cid: None,
4074                        original_dst_cid: None,
4075                        preferred_address: None,
4076                        retry_src_cid: None,
4077                        stateless_reset_token: None,
4078                        min_ack_delay: None,
4079                        ack_delay_exponent: TransportParameters::default().ack_delay_exponent,
4080                        max_ack_delay: TransportParameters::default().max_ack_delay,
4081                        initial_max_path_id: None,
4082                        ..params
4083                    };
4084                    self.set_peer_params(params);
4085                    self.qlog.emit_peer_transport_params_restored(self, now);
4086                }
4087                Err(e) => {
4088                    error!("session ticket has malformed transport parameters: {}", e);
4089                    return;
4090                }
4091            }
4092        }
4093        trace!("0-RTT enabled");
4094        self.crypto_state.enable_zero_rtt(header, packet);
4095    }
4096
4097    fn read_crypto(
4098        &mut self,
4099        space: SpaceId,
4100        crypto: &frame::Crypto,
4101        payload_len: usize,
4102    ) -> Result<(), TransportError> {
4103        let expected = if !self.state.is_handshake() {
4104            SpaceId::Data
4105        } else if self.highest_space == SpaceKind::Initial {
4106            SpaceId::Initial
4107        } else {
4108            // On the server, self.highest_space can be Data after receiving the client's first
4109            // flight, but we expect Handshake CRYPTO until the handshake is complete.
4110            SpaceId::Handshake
4111        };
4112        // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT
4113        // packets are illegal, and we don't process 1-RTT packets until the handshake is
4114        // complete. Therefore, we will never see CRYPTO data from a later-than-expected space.
4115        debug_assert!(space <= expected, "received out-of-order CRYPTO data");
4116
4117        let end = crypto.offset + crypto.data.len() as u64;
4118        if space < expected
4119            && end
4120                > self.crypto_state.spaces[space.kind()]
4121                    .crypto_stream
4122                    .bytes_read()
4123        {
4124            warn!(
4125                "received new {:?} CRYPTO data when expecting {:?}",
4126                space, expected
4127            );
4128            return Err(TransportError::PROTOCOL_VIOLATION(
4129                "new data at unexpected encryption level",
4130            ));
4131        }
4132
4133        let crypto_space = &mut self.crypto_state.spaces[space.kind()];
4134        let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read());
4135        if max > self.config.crypto_buffer_size as u64 {
4136            return Err(TransportError::CRYPTO_BUFFER_EXCEEDED(""));
4137        }
4138
4139        crypto_space
4140            .crypto_stream
4141            .insert(crypto.offset, crypto.data.clone(), payload_len)
4142            .map_err(|_| TransportError::INTERNAL_ERROR("too many gaps in crypto stream buffer"))?;
4143
4144        while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) {
4145            trace!("consumed {} CRYPTO bytes", chunk.bytes.len());
4146            if self.crypto_state.session.read_handshake(&chunk.bytes)? {
4147                self.events.push_back(Event::HandshakeDataReady);
4148            }
4149        }
4150
4151        Ok(())
4152    }
4153
4154    fn write_crypto(&mut self) {
4155        loop {
4156            let space = self.highest_space;
4157            let mut outgoing = Vec::new();
4158            if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) {
4159                match space {
4160                    SpaceKind::Initial => {
4161                        self.upgrade_crypto(SpaceKind::Handshake, crypto);
4162                    }
4163                    SpaceKind::Handshake => {
4164                        self.upgrade_crypto(SpaceKind::Data, crypto);
4165                    }
4166                    SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"),
4167                }
4168            }
4169            if outgoing.is_empty() {
4170                if space == self.highest_space {
4171                    break;
4172                } else {
4173                    // Keys updated, check for more data to send
4174                    continue;
4175                }
4176            }
4177            let offset = self.crypto_state.spaces[space].crypto_offset;
4178            let outgoing = Bytes::from(outgoing);
4179            if let Some(hs) = self.state.as_handshake_mut()
4180                && space == SpaceKind::Initial
4181                && offset == 0
4182                && self.side.is_client()
4183            {
4184                hs.client_hello = Some(outgoing.clone());
4185            }
4186            self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64;
4187            trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space);
4188            self.spaces[space].pending.crypto.push_back(frame::Crypto {
4189                offset,
4190                data: outgoing,
4191            });
4192        }
4193    }
4194
4195    /// Switch to stronger cryptography during handshake
4196    fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) {
4197        debug_assert!(
4198            !self.crypto_state.has_keys(space.encryption_level()),
4199            "already reached packet space {space:?}"
4200        );
4201        trace!("{:?} keys ready", space);
4202        if space == SpaceKind::Data {
4203            // Precompute the first key update
4204            self.crypto_state.next_crypto = Some(
4205                self.crypto_state
4206                    .session
4207                    .next_1rtt_keys()
4208                    .expect("handshake should be complete"),
4209            );
4210        }
4211
4212        self.crypto_state.spaces[space].keys = Some(crypto);
4213        debug_assert!(space > self.highest_space);
4214        self.highest_space = space;
4215        if space == SpaceKind::Data && self.side.is_client() {
4216            // Discard 0-RTT keys because 1-RTT keys are available.
4217            self.crypto_state.discard_zero_rtt();
4218        }
4219    }
4220
4221    fn discard_space(&mut self, now: Instant, space: SpaceKind) {
4222        debug_assert!(space != SpaceKind::Data);
4223        trace!("discarding {:?} keys", space);
4224        if space == SpaceKind::Initial {
4225            // No longer needed
4226            if let ConnectionSide::Client { token, .. } = &mut self.side {
4227                *token = Bytes::new();
4228            }
4229        }
4230        self.crypto_state.spaces[space].keys = None;
4231        let space = &mut self.spaces[space];
4232        let pns = space.for_path(PathId::ZERO);
4233        pns.time_of_last_ack_eliciting_packet = None;
4234        pns.loss_time = None;
4235        pns.loss_probes = 0;
4236        let sent_packets = mem::take(&mut pns.sent_packets);
4237        let path = self
4238            .paths
4239            .get_mut(&PathId::ZERO)
4240            .expect("PathId::ZERO is alive while Initial/Handshake spaces exist");
4241        for (_, packet) in sent_packets.into_iter() {
4242            path.data.remove_in_flight(&packet);
4243        }
4244        // Discarding keys is progress, so the backoff from probing the old space
4245        // must not delay the next one (RFC 9002 A.11). A client never resets it on
4246        // an Initial ACK, so this is where its handshake backoff ends.
4247        path.data.pto_count = 0;
4248
4249        self.set_loss_detection_timer(now, PathId::ZERO)
4250    }
4251
4252    fn handle_coalesced(
4253        &mut self,
4254        now: Instant,
4255        network_path: FourTuple,
4256        path_id: PathId,
4257        ecn: Option<EcnCodepoint>,
4258        data: BytesMut,
4259    ) {
4260        let Some(path) = self.paths.get_mut(&path_id) else {
4261            trace!(%path_id, "discarding coalesced datagram tail for unknown path");
4262            return;
4263        };
4264        path.data.inc_total_recvd(data.len() as u64);
4265        let mut remaining = Some(data);
4266        let cid_len = self
4267            .local_cid_state
4268            .values()
4269            .map(|cid_state| cid_state.cid_len())
4270            .next()
4271            .expect("one cid_state must exist");
4272        while let Some(data) = remaining {
4273            match PartialDecode::new(
4274                data,
4275                &FixedLengthConnectionIdParser::new(cid_len),
4276                &[self.version],
4277                self.endpoint_config.grease_quic_bit,
4278            ) {
4279                Ok((partial_decode, rest)) => {
4280                    remaining = rest;
4281                    self.handle_decode(now, network_path, path_id, ecn, partial_decode);
4282                }
4283                Err(e) => {
4284                    trace!("malformed header: {}", e);
4285                    return;
4286                }
4287            }
4288        }
4289    }
4290
4291    /// Decrypts the packet and processes the payload.
4292    ///
4293    /// Processes the entire packet, starting with removing header protection, then handling
4294    /// a stateless reset if needed, and decrypting and processing the frames in the payload
4295    /// if not a stateless reset.
4296    fn handle_decode(
4297        &mut self,
4298        now: Instant,
4299        network_path: FourTuple,
4300        path_id: PathId,
4301        ecn: Option<EcnCodepoint>,
4302        partial_decode: PartialDecode,
4303    ) {
4304        let qlog = QlogRecvPacket::new(partial_decode.len());
4305        if let Some(decoded) = self
4306            .crypto_state
4307            .unprotect_header(partial_decode, self.peer_params.stateless_reset_token)
4308        {
4309            self.handle_packet(
4310                now,
4311                network_path,
4312                path_id,
4313                ecn,
4314                decoded.packet,
4315                decoded.stateless_reset,
4316                qlog,
4317            );
4318        }
4319    }
4320
4321    /// Handles a packet with header protection removed.
4322    ///
4323    /// The packet body is still encrypted at this point.
4324    ///
4325    /// If the datagram was a stateless reset we may have failed to remove header protection
4326    /// and thus `packet` may be `None`.
4327    fn handle_packet(
4328        &mut self,
4329        now: Instant,
4330        network_path: FourTuple,
4331        path_id: PathId,
4332        ecn: Option<EcnCodepoint>,
4333        packet: Option<Packet>,
4334        stateless_reset: bool,
4335        mut qlog: QlogRecvPacket,
4336    ) {
4337        if let Some(ref packet) = packet {
4338            trace!(
4339                "got {:?} packet ({} bytes) from {} using id {}",
4340                packet.header.space(),
4341                packet.payload.len() + packet.header_data.len(),
4342                network_path,
4343                packet.header.dst_cid(),
4344            );
4345        }
4346
4347        let was_closed = self.state.is_closed();
4348        let was_drained = self.state.is_drained();
4349
4350        // Now decrypt the packet payload in-place.
4351        let decrypted = match packet {
4352            None => Err(None),
4353            Some(mut packet) => self
4354                .decrypt_packet(now, path_id, &mut packet)
4355                .map(move |number| (packet, number)),
4356        };
4357        let result = match decrypted {
4358            _ if stateless_reset => {
4359                debug!("got stateless reset");
4360                Err(ConnectionError::Reset)
4361            }
4362            Err(Some(e)) => {
4363                warn!("illegal packet: {}", e);
4364                Err(e.into())
4365            }
4366            Err(None) => {
4367                debug!("failed to authenticate packet");
4368                self.authentication_failures += 1;
4369                let integrity_limit = self
4370                    .crypto_state
4371                    .integrity_limit(self.highest_space)
4372                    .unwrap();
4373                if self.authentication_failures > integrity_limit {
4374                    Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into())
4375                } else {
4376                    return;
4377                }
4378            }
4379            Ok((packet, pn)) => {
4380                // We received an authenticated packet and decrypted it.
4381                qlog.header(&packet.header, pn, path_id);
4382                let span = match pn {
4383                    Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn),
4384                    None => trace_span!("recv", space = ?packet.header.space()),
4385                };
4386                let _guard = span.enter();
4387
4388                // Now the packet is authenticated we do the migration during the handshake,
4389                // see Handshake::allow_server_migration for details.  Be careful here to
4390                // not yet rely on the path existing however, new paths are accepted and
4391                // created later.
4392                // Note that we can't do any other migrations yet, for those we need to know
4393                // whether this was a probing packet or not. See the end of
4394                // Self::process_packet for that.
4395                if self.is_handshaking()
4396                    && self
4397                        .path(path_id)
4398                        .map(|path_data| {
4399                            !path_data.network_path.is_probably_same_path(&network_path)
4400                        })
4401                        .unwrap_or(false)
4402                {
4403                    if let Some(hs) = self.state.as_handshake()
4404                        && hs.allow_server_migration
4405                    {
4406                        trace!(
4407                            %network_path,
4408                            prev = %self.path_data(path_id).network_path,
4409                            "server migrated to new remote",
4410                        );
4411                        self.path_data_mut(path_id).network_path = network_path;
4412                        self.qlog.emit_tuple_assigned(path_id, network_path, now);
4413                    } else {
4414                        debug!(
4415                            recv_path = %network_path,
4416                            expected_path = %self.path_data_mut(path_id).network_path,
4417                            "discarding packet with unexpected remote during handshake",
4418                        );
4419                        return;
4420                    }
4421                }
4422
4423                let dedup = self.spaces[packet.header.space()]
4424                    .path_space_mut(path_id)
4425                    .map(|pns| &mut pns.dedup);
4426                if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) {
4427                    debug!("discarding possible duplicate packet");
4428                    self.qlog.emit_packet_received(qlog, now);
4429                    return;
4430                } else if self.state.is_handshake() && packet.header.is_short() {
4431                    // TODO: SHOULD buffer these to improve reordering tolerance.
4432                    trace!("dropping short packet during handshake");
4433                    self.qlog.emit_packet_received(qlog, now);
4434                    return;
4435                } else {
4436                    if let Header::Initial(InitialHeader { ref token, .. }) = packet.header
4437                        && let Some(hs) = self.state.as_handshake()
4438                        && self.side.is_server()
4439                        && token != &hs.expected_token
4440                    {
4441                        // Clients must send the same retry token in every Initial. Initial
4442                        // packets can be spoofed, so we discard rather than killing the
4443                        // connection.
4444                        warn!("discarding Initial with invalid retry token");
4445                        self.qlog.emit_packet_received(qlog, now);
4446                        return;
4447                    }
4448
4449                    if !self.state.is_closed() {
4450                        let spin = match packet.header {
4451                            Header::Short { spin, .. } => spin,
4452                            _ => false,
4453                        };
4454
4455                        if self.side().is_server() && !self.abandoned_paths.contains(&path_id) {
4456                            // Only the client is allowed to open paths
4457                            self.create_path(path_id, network_path, now, pn);
4458                        }
4459                        if self.paths.contains_key(&path_id) {
4460                            self.on_packet_authenticated(
4461                                now,
4462                                packet.header.space(),
4463                                path_id,
4464                                ecn,
4465                                pn,
4466                                spin,
4467                                packet.header.is_1rtt(),
4468                                &network_path,
4469                            );
4470                        }
4471                    }
4472
4473                    let res = self.process_decrypted_packet(
4474                        now,
4475                        network_path,
4476                        path_id,
4477                        pn,
4478                        packet,
4479                        &mut qlog,
4480                    );
4481
4482                    self.qlog.emit_packet_received(qlog, now);
4483                    res
4484                }
4485            }
4486        };
4487
4488        // State transitions for error cases
4489        if let Err(conn_err) = result {
4490            match conn_err {
4491                ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason),
4492                ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason),
4493                ConnectionError::Reset
4494                | ConnectionError::TransportError(TransportError {
4495                    code: TransportErrorCode::AEAD_LIMIT_REACHED,
4496                    ..
4497                }) => {
4498                    if !self.state.is_drained() {
4499                        self.state
4500                            .move_to_drained(Some(conn_err), &mut self.endpoint_events);
4501                    }
4502                }
4503                ConnectionError::TimedOut => {
4504                    unreachable!("timeouts aren't generated by packet processing");
4505                }
4506                ConnectionError::TransportError(err) => {
4507                    debug!("closing connection due to transport error: {}", err);
4508                    self.state.move_to_closed(err);
4509                }
4510                ConnectionError::VersionMismatch => {
4511                    self.state
4512                        .move_to_draining(Some(conn_err), &mut self.endpoint_events);
4513                }
4514                ConnectionError::LocallyClosed => {
4515                    unreachable!("LocallyClosed isn't generated by packet processing");
4516                }
4517                ConnectionError::CidsExhausted => {
4518                    unreachable!("CidsExhausted isn't generated by packet processing");
4519                }
4520            };
4521        }
4522
4523        if !was_closed && self.state.is_closed() {
4524            self.close_common();
4525            if !self.state.is_drained() {
4526                self.set_close_timer(now);
4527            }
4528        }
4529        if !was_drained && self.state.is_drained() {
4530            // Close timer may have been started previously, e.g. if we sent a close and got a
4531            // stateless reset in response
4532            self.timers
4533                .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now));
4534        }
4535
4536        // Transmit CONNECTION_CLOSE if necessary.
4537        //
4538        // If we received a valid packet and we are in the closed state we should respond
4539        // with a CONNECTION_CLOSE frame.
4540        // TODO: This SHOULD be rate-limited according to §10.2.1 of QUIC-TRANSPORT, but
4541        //    that does not yet happen. This is triggered by each received packet.
4542        if matches!(self.state.as_type(), StateType::Closed) {
4543            // From https://www.rfc-editor.org/rfc/rfc9000.html#section-10.2.1-7
4544            //
4545            // While in the closing state we must either:
4546            // - discard packets coming from an un-validated remote OR
4547            // - ensure we do not send more than 3 times the received data
4548            //
4549            // Doing the 2nd would mean we would be able to send CONNECTION_CLOSE to a peer
4550            // who was (involuntary) migrated just at the time we initiated immediate
4551            // close. It is a lot more work though. So while we would like to do this for
4552            // now we only do 1.
4553            //
4554            // Another shortcoming of the current implementation is that when we have a
4555            // previous PathData which is validated and the remote matches that path, we
4556            // should schedule CONNECTION_CLOSE on that path. However currently we can not
4557            // schedule such a packet. We should also fix this some day. This makes us
4558            // vulnerable to an attacker faking a migration at the right time and then we'd
4559            // be unable to send the CONNECTION_CLOSE to the real remote.
4560            if self
4561                .paths
4562                .get(&path_id)
4563                .map(|p| p.data.validated && p.data.network_path == network_path)
4564                .unwrap_or(false)
4565            {
4566                self.connection_close_pending = true;
4567            }
4568        }
4569    }
4570
4571    fn process_decrypted_packet(
4572        &mut self,
4573        now: Instant,
4574        network_path: FourTuple,
4575        path_id: PathId,
4576        number: Option<u64>,
4577        packet: Packet,
4578        qlog: &mut QlogRecvPacket,
4579    ) -> Result<(), ConnectionError> {
4580        if !self.paths.contains_key(&path_id) {
4581            // There is a chance this is a server side, first (for this path) packet, which would
4582            // be a protocol violation. It's more likely, however, that this is a packet of a
4583            // pruned path
4584            trace!(%path_id, ?number, "discarding packet for unknown path");
4585            return Ok(());
4586        }
4587        let state = match self.state.as_type() {
4588            StateType::Established => {
4589                match packet.header.space() {
4590                    SpaceKind::Data => self.process_payload(
4591                        now,
4592                        network_path,
4593                        path_id,
4594                        number.unwrap(),
4595                        packet,
4596                        qlog,
4597                    )?,
4598                    _ if packet.header.has_frames() => {
4599                        self.process_early_payload(now, path_id, packet, qlog)?
4600                    }
4601                    _ => {
4602                        trace!("discarding unexpected pre-handshake packet");
4603                    }
4604                }
4605                return Ok(());
4606            }
4607            StateType::Closed => {
4608                for result in frame::Iter::new(packet.payload.freeze())? {
4609                    let frame = match result {
4610                        Ok(frame) => frame,
4611                        Err(err) => {
4612                            debug!("frame decoding error: {err:?}");
4613                            continue;
4614                        }
4615                    };
4616                    qlog.frame(&frame);
4617
4618                    if let Frame::Padding = frame {
4619                        continue;
4620                    };
4621
4622                    trace!(?frame, "processing frame in closed state");
4623
4624                    self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4625
4626                    if let Frame::Close(_error) = frame {
4627                        self.state.move_to_draining(None, &mut self.endpoint_events);
4628                        break;
4629                    }
4630                }
4631                return Ok(());
4632            }
4633            StateType::Draining | StateType::Drained => return Ok(()),
4634            StateType::Handshake => self.state.as_handshake_mut().expect("checked"),
4635        };
4636
4637        match packet.header {
4638            Header::Retry {
4639                src_cid: remote_cid,
4640                ..
4641            } => {
4642                debug_assert_eq!(path_id, PathId::ZERO);
4643                if self.side.is_server() {
4644                    return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into());
4645                }
4646
4647                let is_valid_retry = self
4648                    .remote_cids
4649                    .get(&path_id)
4650                    .map(|cids| cids.active())
4651                    .map(|orig_dst_cid| {
4652                        self.crypto_state.session.is_valid_retry(
4653                            orig_dst_cid,
4654                            &packet.header_data,
4655                            &packet.payload,
4656                        )
4657                    })
4658                    .unwrap_or_default();
4659                if self.total_authed_packets > 1
4660                    || packet.payload.len() <= 16 // token + 16 byte tag
4661                    || !is_valid_retry
4662                {
4663                    trace!("discarding invalid Retry");
4664                    // - After the client has received and processed an Initial or Retry packet from
4665                    //   the server, it MUST discard any subsequent Retry packets that it receives.
4666                    // - A client MUST discard a Retry packet with a zero-length Retry Token field.
4667                    // - Clients MUST discard Retry packets that have a Retry Integrity Tag that
4668                    //   cannot be validated
4669                    return Ok(());
4670                }
4671
4672                trace!("retrying with CID {}", remote_cid);
4673                let client_hello = state.client_hello.take().unwrap();
4674                self.retry_src_cid = Some(remote_cid);
4675                self.remote_cids
4676                    .get_mut(&path_id)
4677                    .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false")
4678                    .update_initial_cid(remote_cid);
4679                self.remote_handshake_cid = remote_cid;
4680
4681                let space = &mut self.spaces[SpaceId::Initial];
4682                if let Some(info) = space.for_path(PathId::ZERO).take(0) {
4683                    self.on_packet_acked(now, PathId::ZERO, SpaceKind::Initial, 0, info);
4684                };
4685
4686                self.discard_space(now, SpaceKind::Initial); // Make sure we clean up after
4687                // any retransmitted Initials
4688                let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial];
4689                crypto_space.keys = Some(
4690                    self.crypto_state
4691                        .session
4692                        .initial_keys(remote_cid, self.side.side()),
4693                );
4694                crypto_space.crypto_offset = client_hello.len() as u64;
4695
4696                let next_pn = self.spaces[SpaceId::Initial]
4697                    .for_path(path_id)
4698                    .next_packet_number;
4699                self.spaces[SpaceId::Initial] = {
4700                    let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng);
4701                    space.for_path(path_id).next_packet_number = next_pn;
4702                    space.pending.crypto.push_back(frame::Crypto {
4703                        offset: 0,
4704                        data: client_hello,
4705                    });
4706                    space
4707                };
4708
4709                // Retransmit all 0-RTT data
4710                let zero_rtt = mem::take(
4711                    &mut self.spaces[SpaceId::Data]
4712                        .for_path(PathId::ZERO)
4713                        .sent_packets,
4714                );
4715                for (_, info) in zero_rtt.into_iter() {
4716                    self.paths
4717                        .get_mut(&PathId::ZERO)
4718                        .unwrap()
4719                        .remove_in_flight(&info);
4720                    self.spaces[SpaceId::Data].pending |= info.retransmits;
4721                }
4722                self.streams.retransmit_all_for_0rtt();
4723
4724                let token_len = packet.payload.len() - 16;
4725                let ConnectionSide::Client { ref mut token, .. } = self.side else {
4726                    unreachable!("we already short-circuited if we're server");
4727                };
4728                *token = packet.payload.freeze().split_to(token_len);
4729
4730                self.state = State::handshake(state::Handshake {
4731                    expected_token: Bytes::new(),
4732                    remote_cid_set: false,
4733                    client_hello: None,
4734                    allow_server_migration: self.config.server_handshake_migration,
4735                });
4736                Ok(())
4737            }
4738            Header::Long {
4739                ty: LongType::Handshake,
4740                src_cid: remote_cid,
4741                dst_cid: local_cid,
4742                ..
4743            } => {
4744                debug_assert_eq!(path_id, PathId::ZERO);
4745                if remote_cid != self.remote_handshake_cid {
4746                    debug!(
4747                        "discarding packet with mismatched remote CID: {} != {}",
4748                        self.remote_handshake_cid, remote_cid
4749                    );
4750                    return Ok(());
4751                }
4752                self.on_path_validated(path_id);
4753
4754                self.process_early_payload(now, path_id, packet, qlog)?;
4755                if self.state.is_closed() {
4756                    return Ok(());
4757                }
4758
4759                if self.crypto_state.session.is_handshaking() {
4760                    trace!("handshake ongoing");
4761                    return Ok(());
4762                }
4763
4764                if self.side.is_client() {
4765                    // Client-only because server params were set from the client's Initial
4766                    let params = self
4767                        .crypto_state
4768                        .session
4769                        .transport_parameters()?
4770                        .ok_or_else(|| {
4771                            TransportError::new(
4772                                TransportErrorCode::crypto(0x6d),
4773                                "transport parameters missing".to_owned(),
4774                            )
4775                        })?;
4776
4777                    if self.has_0rtt() {
4778                        if !self.crypto_state.session.early_data_accepted().unwrap() {
4779                            debug_assert!(self.side.is_client());
4780                            debug!("0-RTT rejected");
4781                            self.crypto_state.accepted_0rtt = false;
4782                            self.streams.zero_rtt_rejected();
4783
4784                            // Discard already-queued frames
4785                            self.spaces[SpaceId::Data].pending = Retransmits::default();
4786
4787                            // Discard 0-RTT packets
4788                            let sent_packets = mem::take(
4789                                &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets,
4790                            );
4791                            for (_, packet) in sent_packets.into_iter() {
4792                                self.paths
4793                                    .get_mut(&path_id)
4794                                    .unwrap()
4795                                    .remove_in_flight(&packet);
4796                            }
4797                        } else {
4798                            self.crypto_state.accepted_0rtt = true;
4799                            params.validate_resumption_from(&self.peer_params)?;
4800                        }
4801                    }
4802                    if let Some(token) = params.stateless_reset_token {
4803                        let remote = self.path_data(path_id).network_path.remote;
4804                        debug_assert!(!self.state.is_drained()); // requirement for endpoint events, checked above
4805                        self.endpoint_events
4806                            .push_back(EndpointEventInner::ResetToken(path_id, remote, token));
4807                    }
4808                    self.handle_peer_params(params, local_cid, remote_cid, now)?;
4809                    self.issue_first_cids(now);
4810                } else {
4811                    // Server-only
4812                    self.spaces[SpaceId::Data].pending.handshake_done = true;
4813                    self.discard_space(now, SpaceKind::Handshake);
4814                    self.events.push_back(Event::HandshakeConfirmed);
4815                    trace!("handshake confirmed");
4816                }
4817
4818                self.events.push_back(Event::Connected);
4819                self.state.move_to_established();
4820                // Swap the handshake idle timeout for the negotiated one.
4821                self.reset_idle_timeout(now, SpaceKind::Data, path_id);
4822                trace!("established");
4823
4824                // Multipath can only be enabled after the state has reached Established.
4825                // So this can not happen any earlier.
4826                self.issue_first_path_cids(now);
4827                self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
4828                Ok(())
4829            }
4830            Header::Initial(InitialHeader {
4831                src_cid: remote_cid,
4832                dst_cid: local_cid,
4833                ..
4834            }) => {
4835                debug_assert_eq!(path_id, PathId::ZERO);
4836                if !state.remote_cid_set {
4837                    trace!("switching remote CID to {}", remote_cid);
4838                    let mut state = state.clone();
4839                    self.remote_cids
4840                        .get_mut(&path_id)
4841                        .expect("PathId::ZERO not yet abandoned")
4842                        .update_initial_cid(remote_cid);
4843                    self.remote_handshake_cid = remote_cid;
4844                    self.original_remote_cid = remote_cid;
4845                    state.remote_cid_set = true;
4846                    self.state.move_to_handshake(state);
4847                } else if remote_cid != self.remote_handshake_cid {
4848                    debug!(
4849                        "discarding packet with mismatched remote CID: {} != {}",
4850                        self.remote_handshake_cid, remote_cid
4851                    );
4852                    return Ok(());
4853                }
4854
4855                let starting_space = self.highest_space;
4856                self.process_early_payload(now, path_id, packet, qlog)?;
4857
4858                if self.side.is_server()
4859                    && starting_space == SpaceKind::Initial
4860                    && self.highest_space != SpaceKind::Initial
4861                {
4862                    let params = self
4863                        .crypto_state
4864                        .session
4865                        .transport_parameters()?
4866                        .ok_or_else(|| {
4867                            TransportError::new(
4868                                TransportErrorCode::crypto(0x6d),
4869                                "transport parameters missing".to_owned(),
4870                            )
4871                        })?;
4872                    self.handle_peer_params(params, local_cid, remote_cid, now)?;
4873                    self.issue_first_cids(now);
4874                    self.init_0rtt(now);
4875                }
4876                Ok(())
4877            }
4878            Header::Long {
4879                ty: LongType::ZeroRtt,
4880                ..
4881            } => {
4882                self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?;
4883                Ok(())
4884            }
4885            Header::VersionNegotiate { .. } => {
4886                if self.total_authed_packets > 1 {
4887                    return Ok(());
4888                }
4889                let supported = packet
4890                    .payload
4891                    .chunks(4)
4892                    .any(|x| match <[u8; 4]>::try_from(x) {
4893                        Ok(version) => self.version == u32::from_be_bytes(version),
4894                        Err(_) => false,
4895                    });
4896                if supported {
4897                    return Ok(());
4898                }
4899                debug!("remote doesn't support our version");
4900                Err(ConnectionError::VersionMismatch)
4901            }
4902            Header::Short { .. } => unreachable!(
4903                "short packets received during handshake are discarded in handle_packet"
4904            ),
4905        }
4906    }
4907
4908    /// Process an Initial or Handshake packet payload
4909    fn process_early_payload(
4910        &mut self,
4911        now: Instant,
4912        path_id: PathId,
4913        packet: Packet,
4914        #[allow(unused)] qlog: &mut QlogRecvPacket,
4915    ) -> Result<(), TransportError> {
4916        debug_assert_ne!(packet.header.space(), SpaceKind::Data);
4917        debug_assert_eq!(path_id, PathId::ZERO);
4918        let payload_len = packet.payload.len();
4919        let mut ack_eliciting = false;
4920        for result in frame::Iter::new(packet.payload.freeze())? {
4921            let frame = result?;
4922            qlog.frame(&frame);
4923            let span = match frame {
4924                Frame::Padding => continue,
4925                _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)),
4926            };
4927
4928            self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4929
4930            let _guard = span.as_ref().map(|x| x.enter());
4931            ack_eliciting |= frame.is_ack_eliciting();
4932
4933            // Process frames
4934            if frame.is_1rtt() && packet.header.space() != SpaceKind::Data {
4935                return Err(TransportError::PROTOCOL_VIOLATION(
4936                    "illegal frame type in handshake",
4937                ));
4938            }
4939
4940            match frame {
4941                Frame::Padding | Frame::Ping => {}
4942                Frame::Crypto(frame) => {
4943                    self.read_crypto(packet.header.space().into(), &frame, payload_len)?;
4944                }
4945                Frame::Ack(ack) => {
4946                    self.on_ack_received(now, packet.header.space().into(), ack)?;
4947                }
4948                Frame::PathAck(ack) => {
4949                    span.as_ref()
4950                        .map(|span| span.record("path", tracing::field::display(&ack.path_id)));
4951                    self.on_path_ack_received(now, packet.header.space().into(), ack)?;
4952                }
4953                Frame::Close(reason) => {
4954                    self.state
4955                        .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
4956                    return Ok(());
4957                }
4958                _ => {
4959                    let mut err =
4960                        TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake");
4961                    err.frame = frame::MaybeFrame::Known(frame.ty());
4962                    return Err(err);
4963                }
4964            }
4965        }
4966
4967        if ack_eliciting {
4968            // In the initial and handshake spaces, ACKs must be sent immediately
4969            self.spaces[packet.header.space()]
4970                .for_path(path_id)
4971                .pending_acks
4972                .set_immediate_ack_required();
4973        }
4974
4975        self.write_crypto();
4976        Ok(())
4977    }
4978
4979    /// Processes the decrypted packet payload, always in the data space.
4980    fn process_payload(
4981        &mut self,
4982        now: Instant,
4983        network_path: FourTuple,
4984        path_id: PathId,
4985        number: u64,
4986        packet: Packet,
4987        #[allow(unused)] qlog: &mut QlogRecvPacket,
4988    ) -> Result<(), TransportError> {
4989        let payload = packet.payload.freeze();
4990        let mut is_probing_packet = true;
4991        let mut close = None;
4992        let payload_len = payload.len();
4993        let mut ack_eliciting = false;
4994        // if this packet triggers a path migration and includes a observed address frame, it's
4995        // stored here
4996        let mut migration_observed_addr = None;
4997        for result in frame::Iter::new(payload)? {
4998            let frame = result?;
4999            qlog.frame(&frame);
5000            let span = match frame {
5001                Frame::Padding => continue,
5002                _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty),
5003            };
5004
5005            self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
5006            // Crypto, Stream and Datagram frames are special cased in order no pollute
5007            // the log with payload data
5008            match &frame {
5009                Frame::Crypto(f) => {
5010                    trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO");
5011                }
5012                Frame::Stream(f) => {
5013                    trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM");
5014                }
5015                Frame::Datagram(f) => {
5016                    trace!(len = f.data.len(), "got frame DATAGRAM");
5017                }
5018                f => {
5019                    trace!("got frame {f}");
5020                }
5021            }
5022
5023            let _guard = span.enter();
5024            if packet.header.is_0rtt() {
5025                match frame {
5026                    Frame::Crypto(_) | Frame::Close(Close::Application(_)) => {
5027                        return Err(TransportError::PROTOCOL_VIOLATION(
5028                            "illegal frame type in 0-RTT",
5029                        ));
5030                    }
5031                    _ => {
5032                        if frame.is_1rtt() {
5033                            return Err(TransportError::PROTOCOL_VIOLATION(
5034                                "illegal frame type in 0-RTT",
5035                            ));
5036                        }
5037                    }
5038                }
5039            }
5040            ack_eliciting |= frame.is_ack_eliciting();
5041
5042            // Check whether this could be a probing packet
5043            match frame {
5044                Frame::Padding
5045                | Frame::PathChallenge(_)
5046                | Frame::PathResponse(_)
5047                | Frame::NewConnectionId(_)
5048                | Frame::ObservedAddr(_) => {}
5049                _ => {
5050                    is_probing_packet = false;
5051                }
5052            }
5053
5054            match frame {
5055                Frame::Crypto(frame) => {
5056                    self.read_crypto(SpaceId::Data, &frame, payload_len)?;
5057                }
5058                Frame::Stream(frame) => {
5059                    if self.streams.received(frame, payload_len)?.should_transmit() {
5060                        self.spaces[SpaceId::Data].pending.max_data = true;
5061                    }
5062                }
5063                Frame::Ack(ack) => {
5064                    self.on_ack_received(now, SpaceId::Data, ack)?;
5065                }
5066                Frame::PathAck(ack) => {
5067                    if !self.is_multipath_negotiated() {
5068                        return Err(TransportError::PROTOCOL_VIOLATION(
5069                            "received PATH_ACK frame when multipath was not negotiated",
5070                        ));
5071                    }
5072                    span.record("path", tracing::field::display(&ack.path_id));
5073                    self.on_path_ack_received(now, SpaceId::Data, ack)?;
5074                }
5075                Frame::Padding | Frame::Ping => {}
5076                Frame::Close(reason) => {
5077                    close = Some(reason);
5078                }
5079                Frame::PathChallenge(challenge) => {
5080                    self.spaces[SpaceKind::Data]
5081                        .for_path(path_id)
5082                        .pending_path_responses
5083                        .push(number, challenge.0, network_path);
5084                    // If we were passively migrated (e.g. NAT rebinding), our local_ip will
5085                    // not match. Once we processed a non-probing packet the local_ip will
5086                    // finally be updated.
5087                    let path = &mut self
5088                        .path_mut(path_id)
5089                        .expect("payload is processed only after the path becomes known");
5090                    if network_path.remote == path.network_path.remote {
5091                        // PATH_CHALLENGE on active path, possible off-path packet
5092                        // forwarding attack. Send a non-probing packet to recover the
5093                        // active path. See
5094                        // https://www.rfc-editor.org/rfc/rfc9000.html#section-9.3.3-3. In
5095                        // rare cases NAT probes might also appear on-path and would also
5096                        // get a non-probing packet as response. There is little harm in
5097                        // this.
5098                        match self.peer_supports_ack_frequency() {
5099                            true => self.immediate_ack(path_id),
5100                            false => {
5101                                self.ping_path(path_id).ok();
5102                            }
5103                        }
5104                    }
5105                }
5106                Frame::PathResponse(response) => {
5107                    // First try to see if this is a NAT probe response.
5108                    if self
5109                        .n0_nat_traversal
5110                        .handle_path_response(network_path, response.0)
5111                    {
5112                        self.open_nat_traversed_paths(now);
5113                    } else {
5114                        // Try to see if this is a response to an on-path PATH_CHALLENGE.
5115                        self.handle_path_response_on_path(now, response, path_id);
5116                    }
5117                }
5118                Frame::MaxData(frame::MaxData(bytes)) => {
5119                    self.streams.received_max_data(bytes);
5120                }
5121                Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => {
5122                    self.streams.received_max_stream_data(id, offset)?;
5123                }
5124                Frame::MaxStreams(frame::MaxStreams { dir, count }) => {
5125                    self.streams.received_max_streams(dir, count)?;
5126                }
5127                Frame::ResetStream(frame) => {
5128                    if self.streams.received_reset(frame)?.should_transmit() {
5129                        self.spaces[SpaceId::Data].pending.max_data = true;
5130                    }
5131                }
5132                Frame::DataBlocked(DataBlocked(offset)) => {
5133                    debug!(offset, "peer claims to be blocked at connection level");
5134                }
5135                Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => {
5136                    if id.initiator() == self.side.side() && id.dir() == Dir::Uni {
5137                        debug!("got STREAM_DATA_BLOCKED on send-only {}", id);
5138                        return Err(TransportError::STREAM_STATE_ERROR(
5139                            "STREAM_DATA_BLOCKED on send-only stream",
5140                        ));
5141                    }
5142                    debug!(
5143                        stream = %id,
5144                        offset, "peer claims to be blocked at stream level"
5145                    );
5146                }
5147                Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => {
5148                    if limit > MAX_STREAM_COUNT {
5149                        return Err(TransportError::FRAME_ENCODING_ERROR(
5150                            "unrepresentable stream limit",
5151                        ));
5152                    }
5153                    debug!(
5154                        "peer claims to be blocked opening more than {} {} streams",
5155                        limit, dir
5156                    );
5157                }
5158                Frame::StopSending(frame::StopSending { id, error_code }) => {
5159                    if id.initiator() != self.side.side() {
5160                        if id.dir() == Dir::Uni {
5161                            debug!("got STOP_SENDING on recv-only {}", id);
5162                            return Err(TransportError::STREAM_STATE_ERROR(
5163                                "STOP_SENDING on recv-only stream",
5164                            ));
5165                        }
5166                    } else if self.streams.is_local_unopened(id) {
5167                        return Err(TransportError::STREAM_STATE_ERROR(
5168                            "STOP_SENDING on unopened stream",
5169                        ));
5170                    }
5171                    self.streams.received_stop_sending(id, error_code);
5172                }
5173                Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => {
5174                    if let Some(ref path_id) = path_id {
5175                        span.record("path", tracing::field::display(&path_id));
5176                    }
5177                    let path_id = path_id.unwrap_or_default();
5178                    match self.local_cid_state.get_mut(&path_id) {
5179                        None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"),
5180                        Some(cid_state) => {
5181                            let allow_more_cids = cid_state
5182                                .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?;
5183
5184                            // If the path has closed, we do not issue more CIDs for this path
5185                            // For details see  https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-3.2.2
5186                            // > an endpoint SHOULD provide new connection IDs for that path, if still open, using PATH_NEW_CONNECTION_ID frames.
5187                            let has_path = !self.abandoned_paths.contains(&path_id);
5188                            let allow_more_cids = allow_more_cids && has_path;
5189
5190                            debug_assert!(!self.state.is_drained()); // required for adding endpoint events, process_payload is never called for drained connections
5191                            self.endpoint_events
5192                                .push_back(EndpointEventInner::RetireConnectionId(
5193                                    now,
5194                                    path_id,
5195                                    sequence,
5196                                    allow_more_cids,
5197                                ));
5198                        }
5199                    }
5200                }
5201                Frame::NewConnectionId(frame) => {
5202                    let path_id = if let Some(path_id) = frame.path_id {
5203                        if !self.is_multipath_negotiated() {
5204                            return Err(TransportError::PROTOCOL_VIOLATION(
5205                                "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated",
5206                            ));
5207                        }
5208                        if path_id > self.local_max_path_id {
5209                            return Err(TransportError::PROTOCOL_VIOLATION(
5210                                "PATH_NEW_CONNECTION_ID contains path_id exceeding current max",
5211                            ));
5212                        }
5213                        path_id
5214                    } else {
5215                        PathId::ZERO
5216                    };
5217
5218                    if let Some(ref path_id) = frame.path_id {
5219                        span.record("path", tracing::field::display(&path_id));
5220                    }
5221
5222                    if self.abandoned_paths.contains(&path_id) {
5223                        trace!("ignoring issued CID for abandoned path");
5224                        continue;
5225                    }
5226                    let remote_cids = self
5227                        .remote_cids
5228                        .entry(path_id)
5229                        .or_insert_with(|| CidQueue::new(frame.id));
5230                    if remote_cids.active().is_empty() {
5231                        return Err(TransportError::PROTOCOL_VIOLATION(
5232                            "NEW_CONNECTION_ID when CIDs aren't in use",
5233                        ));
5234                    }
5235                    if frame.retire_prior_to > frame.sequence {
5236                        return Err(TransportError::PROTOCOL_VIOLATION(
5237                            "NEW_CONNECTION_ID retiring unissued CIDs",
5238                        ));
5239                    }
5240
5241                    use crate::cid_queue::InsertError;
5242                    match remote_cids.insert(frame) {
5243                        Ok(None) => {
5244                            self.open_nat_traversed_paths(now);
5245                        }
5246                        Ok(Some((retired, reset_token))) => {
5247                            let pending_retired =
5248                                &mut self.spaces[SpaceId::Data].pending.retire_cids;
5249                            /// Ensure `pending_retired` cannot grow without bound. Limit is
5250                            /// somewhat arbitrary but very permissive.
5251                            const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10;
5252                            // We don't bother counting in-flight frames because those are bounded
5253                            // by congestion control.
5254                            if (pending_retired.len() as u64)
5255                                .saturating_add(retired.end.saturating_sub(retired.start))
5256                                > MAX_PENDING_RETIRED_CIDS
5257                            {
5258                                return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(
5259                                    "queued too many retired CIDs",
5260                                ));
5261                            }
5262                            pending_retired.extend(retired.map(|seq| (path_id, seq)));
5263                            self.set_reset_token(path_id, network_path.remote, reset_token);
5264                            self.open_nat_traversed_paths(now);
5265                        }
5266                        Err(InsertError::ExceedsLimit) => {
5267                            return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(""));
5268                        }
5269                        Err(InsertError::Retired) => {
5270                            trace!("discarding already-retired");
5271                            // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a
5272                            // range of connection IDs larger than the active connection ID limit
5273                            // was retired all at once via retire_prior_to.
5274                            self.spaces[SpaceId::Data]
5275                                .pending
5276                                .retire_cids
5277                                .push((path_id, frame.sequence));
5278                            continue;
5279                        }
5280                    };
5281
5282                    if self.side.is_server()
5283                        && path_id == PathId::ZERO
5284                        && self
5285                            .remote_cids
5286                            .get(&PathId::ZERO)
5287                            .map(|cids| cids.active_seq() == 0)
5288                            .unwrap_or_default()
5289                    {
5290                        // We're a server still using the initial remote CID for the client, so
5291                        // let's switch immediately to enable clientside stateless resets.
5292                        self.update_remote_cid(PathId::ZERO);
5293                    }
5294                }
5295                Frame::NewToken(NewToken { token }) => {
5296                    let ConnectionSide::Client {
5297                        token_store,
5298                        server_name,
5299                        ..
5300                    } = &self.side
5301                    else {
5302                        return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN"));
5303                    };
5304                    if token.is_empty() {
5305                        return Err(TransportError::FRAME_ENCODING_ERROR("empty token"));
5306                    }
5307                    trace!("got new token");
5308                    token_store.insert(server_name, token);
5309                }
5310                Frame::Datagram(datagram) => {
5311                    if self
5312                        .datagrams
5313                        .received(datagram, &self.config.datagram_receive_buffer_size)?
5314                    {
5315                        self.events.push_back(Event::DatagramReceived);
5316                    }
5317                }
5318                Frame::AckFrequency(ack_frequency) => {
5319                    // This frame can only be sent in the Data space
5320
5321                    if !self.ack_frequency.ack_frequency_received(&ack_frequency)? {
5322                        // The AckFrequency frame is stale (we have already received a more
5323                        // recent one)
5324                        continue;
5325                    }
5326
5327                    // Update the params for all of our paths
5328                    for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() {
5329                        space.pending_acks.set_ack_frequency_params(&ack_frequency);
5330
5331                        // Our `max_ack_delay` has been updated, so we may need to adjust
5332                        // its associated timeout.
5333                        // Packets received on abandoned paths are always acknowledged immediately.
5334                        if !self.abandoned_paths.contains(path_id)
5335                            && let Some(timeout) = space
5336                                .pending_acks
5337                                .max_ack_delay_timeout(self.ack_frequency.max_ack_delay)
5338                        {
5339                            self.timers.set(
5340                                Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
5341                                timeout,
5342                                self.qlog.with_time(now),
5343                            );
5344                        }
5345                    }
5346                }
5347                Frame::ImmediateAck => {
5348                    // This frame can only be sent in the Data space
5349                    for pns in self.spaces[SpaceId::Data].iter_paths_mut() {
5350                        pns.pending_acks.set_immediate_ack_required();
5351                    }
5352                }
5353                Frame::HandshakeDone => {
5354                    if self.side.is_server() {
5355                        return Err(TransportError::PROTOCOL_VIOLATION(
5356                            "client sent HANDSHAKE_DONE",
5357                        ));
5358                    }
5359                    if self.crypto_state.has_keys(EncryptionLevel::Handshake) {
5360                        self.discard_space(now, SpaceKind::Handshake);
5361                        self.events.push_back(Event::HandshakeConfirmed);
5362                        trace!("handshake confirmed");
5363                    }
5364                }
5365                Frame::ObservedAddr(observed) => {
5366                    // check if params allows the peer to send report and this node to receive it
5367                    trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port);
5368                    if !self
5369                        .peer_params
5370                        .address_discovery_role
5371                        .should_report(&self.config.address_discovery_role)
5372                    {
5373                        return Err(TransportError::PROTOCOL_VIOLATION(
5374                            "received OBSERVED_ADDRESS frame when not negotiated",
5375                        ));
5376                    }
5377                    // must only be sent in data space
5378                    if packet.header.space() != SpaceKind::Data {
5379                        return Err(TransportError::PROTOCOL_VIOLATION(
5380                            "OBSERVED_ADDRESS frame outside data space",
5381                        ));
5382                    }
5383
5384                    let space_open_status =
5385                        self.spaces[SpaceKind::Data].for_path(path_id).open_status;
5386                    let path = self.path_data_mut(path_id);
5387                    if path.network_path.remote == network_path.remote {
5388                        if let Some(updated) = path.update_observed_addr_report(observed)
5389                            && space_open_status == OpenStatus::Informed
5390                        {
5391                            self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5392                                id: path_id,
5393                                addr: updated,
5394                            }));
5395                            // otherwise the event is reported when the path is deemed open
5396                        }
5397                    } else {
5398                        // include in migration
5399                        migration_observed_addr = Some(observed)
5400                    }
5401                }
5402                Frame::PathAbandon(frame::PathAbandon {
5403                    path_id,
5404                    error_code,
5405                }) => {
5406                    span.record("path", tracing::field::display(&path_id));
5407                    match self.close_path_inner(
5408                        now,
5409                        path_id,
5410                        PathAbandonReason::RemoteAbandoned {
5411                            error_code: error_code.into(),
5412                        },
5413                    ) {
5414                        Ok(()) => {
5415                            trace!("peer abandoned path");
5416                        }
5417                        Err(ClosePathError::ClosedPath) => {
5418                            trace!("peer abandoned already closed path");
5419                        }
5420                        Err(ClosePathError::MultipathNotNegotiated) => {
5421                            return Err(TransportError::PROTOCOL_VIOLATION(
5422                                "received PATH_ABANDON frame when multipath was not negotiated",
5423                            ));
5424                        }
5425                        Err(ClosePathError::LastOpenPath) => {
5426                            // Not reachable: close_path_inner allows remote abandons
5427                            // for the last path. But handle gracefully just in case.
5428                            error!(
5429                                "peer abandoned last path but close_path_inner returned LastOpenPath"
5430                            );
5431                        }
5432                    };
5433
5434                    // Start draining the path if it still exists and hasn't started draining yet.
5435                    if let Some(path) = self.paths.get_mut(&path_id)
5436                        && !mem::replace(&mut path.data.draining, true)
5437                    {
5438                        let ack_delay = self.ack_frequency.max_ack_delay_for_pto();
5439                        let pto = path.data.rtt.pto_base() + ack_delay;
5440                        self.timers.set(
5441                            Timer::PerPath(path_id, PathTimer::PathDrained),
5442                            now + 3 * pto,
5443                            self.qlog.with_time(now),
5444                        );
5445
5446                        self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8));
5447                    }
5448                }
5449                Frame::PathStatusAvailable(info) => {
5450                    span.record("path", tracing::field::display(&info.path_id));
5451                    if self.is_multipath_negotiated() {
5452                        self.on_path_status(
5453                            info.path_id,
5454                            PathStatus::Available,
5455                            info.status_seq_no,
5456                        );
5457                    } else {
5458                        return Err(TransportError::PROTOCOL_VIOLATION(
5459                            "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated",
5460                        ));
5461                    }
5462                }
5463                Frame::PathStatusBackup(info) => {
5464                    span.record("path", tracing::field::display(&info.path_id));
5465                    if self.is_multipath_negotiated() {
5466                        self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no);
5467                    } else {
5468                        return Err(TransportError::PROTOCOL_VIOLATION(
5469                            "received PATH_STATUS_BACKUP frame when multipath was not negotiated",
5470                        ));
5471                    }
5472                }
5473                Frame::MaxPathId(frame::MaxPathId(path_id)) => {
5474                    span.record("path", tracing::field::display(&path_id));
5475                    if !self.is_multipath_negotiated() {
5476                        return Err(TransportError::PROTOCOL_VIOLATION(
5477                            "received MAX_PATH_ID frame when multipath was not negotiated",
5478                        ));
5479                    }
5480                    // frames that do not increase the path id are ignored
5481                    if path_id > self.remote_max_path_id {
5482                        self.remote_max_path_id = path_id;
5483                        self.issue_first_path_cids(now);
5484                        self.open_nat_traversed_paths(now);
5485                    }
5486                }
5487                Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => {
5488                    // Receipt of a value of Maximum Path Identifier or Path Identifier that
5489                    // is higher than the local maximum value MUST be treated as a
5490                    // connection error of type PROTOCOL_VIOLATION. Ref
5491                    // <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids>
5492                    if self.is_multipath_negotiated() {
5493                        if max_path_id > self.local_max_path_id {
5494                            return Err(TransportError::PROTOCOL_VIOLATION(
5495                                "PATHS_BLOCKED maximum path identifier was larger than local maximum",
5496                            ));
5497                        }
5498                    } else {
5499                        return Err(TransportError::PROTOCOL_VIOLATION(
5500                            "received PATHS_BLOCKED frame when not multipath was not negotiated",
5501                        ));
5502                    }
5503                }
5504                Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => {
5505                    // Nothing to do.  This is recorded in the frame stats, but otherwise we
5506                    // always issue all CIDs we're allowed to issue, so either this is an
5507                    // impatient peer or a bug on our side.
5508
5509                    // Receipt of a value of Maximum Path Identifier or Path Identifier that
5510                    // is higher than the local maximum value MUST be treated as a
5511                    // connection error of type PROTOCOL_VIOLATION. Ref
5512                    // <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-14.html#name-paths_blocked-and-path_cids>
5513                    if self.is_multipath_negotiated() {
5514                        if path_id > self.local_max_path_id {
5515                            return Err(TransportError::PROTOCOL_VIOLATION(
5516                                "PATH_CIDS_BLOCKED path identifier was larger than local maximum",
5517                            ));
5518                        }
5519                        if self
5520                            .local_cid_state
5521                            .get(&path_id)
5522                            // The PATH_CIDS_BLOCKED frame may arrive after we've discarded the path
5523                            // state. In that case, we can't check for
5524                            // the protocol violation.
5525                            .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1)
5526                        {
5527                            return Err(TransportError::PROTOCOL_VIOLATION(
5528                                "PATH_CIDS_BLOCKED next sequence number larger than in local state",
5529                            ));
5530                        }
5531                        debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED");
5532                    } else {
5533                        return Err(TransportError::PROTOCOL_VIOLATION(
5534                            "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated",
5535                        ));
5536                    }
5537                }
5538                Frame::AddAddress(addr) => {
5539                    let client_state = match self.n0_nat_traversal.client_side_mut() {
5540                        Ok(state) => state,
5541                        Err(err) => {
5542                            return Err(TransportError::PROTOCOL_VIOLATION(format!(
5543                                "Nat traversal(ADD_ADDRESS): {err}"
5544                            )));
5545                        }
5546                    };
5547
5548                    if !client_state.check_remote_address(&addr) {
5549                        // if the address is not valid we flag it, but update anyway
5550                        warn!(?addr, "server sent illegal ADD_ADDRESS frame");
5551                    }
5552
5553                    match client_state.add_remote_address(addr) {
5554                        Ok(maybe_added) => {
5555                            if let Some(added) = maybe_added {
5556                                self.events.push_back(Event::NatTraversal(
5557                                    n0_nat_traversal::Event::AddressAdded(added),
5558                                ));
5559                            }
5560                        }
5561                        Err(e) => {
5562                            warn!(%e, "failed to add remote address")
5563                        }
5564                    }
5565                }
5566                Frame::RemoveAddress(addr) => {
5567                    let client_state = match self.n0_nat_traversal.client_side_mut() {
5568                        Ok(state) => state,
5569                        Err(err) => {
5570                            return Err(TransportError::PROTOCOL_VIOLATION(format!(
5571                                "Nat traversal(REMOVE_ADDRESS): {err}"
5572                            )));
5573                        }
5574                    };
5575                    if let Some(removed_addr) = client_state.remove_remote_address(addr) {
5576                        self.events.push_back(Event::NatTraversal(
5577                            n0_nat_traversal::Event::AddressRemoved(removed_addr),
5578                        ));
5579                    }
5580                }
5581                Frame::ReachOut(reach_out) => {
5582                    let ipv6 = self.is_ipv6();
5583                    let server_state = match self.n0_nat_traversal.server_side_mut() {
5584                        Ok(state) => state,
5585                        Err(err) => {
5586                            return Err(TransportError::PROTOCOL_VIOLATION(format!(
5587                                "Nat traversal(REACH_OUT): {err}"
5588                            )));
5589                        }
5590                    };
5591
5592                    let round_before = server_state.current_round();
5593
5594                    if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) {
5595                        return Err(TransportError::PROTOCOL_VIOLATION(format!(
5596                            "Nat traversal(REACH_OUT): {err}"
5597                        )));
5598                    }
5599
5600                    if server_state.current_round() > round_before {
5601                        // A new round was started, reset the NAT probe retry timer.
5602                        if let Some(delay) =
5603                            self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
5604                        {
5605                            self.timers.set(
5606                                Timer::Conn(ConnTimer::NatTraversalProbeRetry),
5607                                now + delay,
5608                                self.qlog.with_time(now),
5609                            );
5610                        }
5611                    }
5612                }
5613            }
5614        }
5615
5616        let space = self.spaces[SpaceId::Data].for_path(path_id);
5617        if space
5618            .pending_acks
5619            .packet_received(now, number, ack_eliciting, &space.dedup)
5620        {
5621            if self.abandoned_paths.contains(&path_id) {
5622                // § 3.4.3 QUIC-MULTIPATH: promptly send ACKs for packets received from
5623                // abandoned paths.
5624                space.pending_acks.set_immediate_ack_required();
5625            } else {
5626                self.timers.set(
5627                    Timer::PerPath(path_id, PathTimer::MaxAckDelay),
5628                    now + self.ack_frequency.max_ack_delay,
5629                    self.qlog.with_time(now),
5630                );
5631            }
5632        }
5633
5634        // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets
5635        // on stopped streams. Incoming finishes/resets on open streams are not handled here as they
5636        // are only freed, and hence only issue credit, once the application has been notified
5637        // during a read on the stream.
5638        let pending = &mut self.spaces[SpaceId::Data].pending;
5639        self.streams.queue_max_stream_id(pending);
5640
5641        if let Some(reason) = close {
5642            self.state
5643                .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
5644            self.connection_close_pending = true;
5645        }
5646
5647        // For Multipath any packet triggers migration. For RFC9000 or QNT (+ Multipath)
5648        // only non-probing packets trigger migration.
5649        let migrate_on_any_packet =
5650            self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated();
5651
5652        // Only migrate if this is the largest packet number seen.
5653        let is_largest_received_pn = Some(number)
5654            == self.spaces[SpaceId::Data]
5655                .for_path(path_id)
5656                .largest_received_packet_number;
5657
5658        // If we receive a non-probing packet on a new local IP that means we had a NAT
5659        // rebinding-like migration. We update our local address but do not otherwise
5660        // validate the new path, we only need to validate the path if the peer migrates per
5661        // RFC9000 §9: https://www.rfc-editor.org/rfc/rfc9000.html#section-9-4
5662        if (migrate_on_any_packet || !is_probing_packet)
5663            && is_largest_received_pn
5664            && self.local_ip_may_migrate()
5665            && let Some(new_local_ip) = network_path.local_ip
5666        {
5667            let path_data = self.path_data_mut(path_id);
5668            if path_data
5669                .network_path
5670                .local_ip
5671                .is_some_and(|ip| ip != new_local_ip)
5672            {
5673                debug!(
5674                    %path_id,
5675                    new_4tuple = %network_path,
5676                    prev_4tuple = %path_data.network_path,
5677                    "local address passive migration"
5678                );
5679            }
5680            path_data.network_path.local_ip = Some(new_local_ip)
5681        }
5682
5683        // If the peer migrated to a new address, trigger migration.
5684        if self.peer_may_migrate()
5685            && (migrate_on_any_packet || !is_probing_packet)
5686            && is_largest_received_pn
5687            && network_path.remote != self.path_data(path_id).network_path.remote
5688        {
5689            self.migrate(path_id, now, network_path, migration_observed_addr);
5690            // Break linkability, if possible
5691            self.update_remote_cid(path_id);
5692            self.spin = false;
5693        }
5694
5695        Ok(())
5696    }
5697
5698    /// Handles any on-path PATH_RESPONSE frames.
5699    ///
5700    /// *path_id* and *network_path* are those on which the PATH_RESPONSE was received.
5701    fn handle_path_response_on_path(
5702        &mut self,
5703        now: Instant,
5704        response: frame::PathResponse,
5705        path_id: PathId,
5706    ) {
5707        let is_multipath_negotiated = self.is_multipath_negotiated();
5708        let path = self
5709            .paths
5710            .get_mut(&path_id)
5711            .expect("payload is processed only after the path becomes known");
5712        match path.data.on_path_response_received(now, response.0) {
5713            paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => {
5714                let qlog = self.qlog.with_time(now);
5715                self.timers.stop(
5716                    Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5717                    qlog.clone(),
5718                );
5719                let next_challenge = path
5720                    .data
5721                    .earliest_on_path_expiring_challenge()
5722                    .map(|time| time + self.ack_frequency.max_ack_delay_for_pto());
5723                self.timers.set_or_stop(
5724                    Timer::PerPath(path_id, PathTimer::PathChallengeLost),
5725                    next_challenge,
5726                    qlog,
5727                );
5728                let pns = self.spaces[SpaceKind::Data].for_path(path_id);
5729                if !matches!(pns.open_status, OpenStatus::Informed) {
5730                    if is_multipath_negotiated {
5731                        self.events
5732                            .push_back(Event::Path(PathEvent::Established { id: path_id }));
5733                    }
5734                    pns.open_status = OpenStatus::Informed;
5735                    if let Some(observed) = path.data.last_observed_addr_report.as_ref() {
5736                        self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5737                            id: path_id,
5738                            addr: observed.socket_addr(),
5739                        }));
5740                    }
5741                }
5742                if let Some((_, ref mut prev)) = path.prev {
5743                    // If an on-path response was received while there is a
5744                    // previous path from a migration, then the new path is
5745                    // validated and we can stop sending challenges that try to
5746                    // re-validate the previous path.
5747                    prev.reset_on_path_challenges();
5748                }
5749            }
5750            paths::OnPathResponseReceived::OnPath => {
5751                trace!(
5752                    %response,
5753                    "ignoring PATH_RESPONSE received after path is abandoned"
5754                );
5755            }
5756            paths::OnPathResponseReceived::Unknown => {
5757                debug!(%response, "ignoring invalid PATH_RESPONSE");
5758            }
5759            paths::OnPathResponseReceived::Ignored {
5760                sent_on,
5761                current_path,
5762            } => {
5763                debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE");
5764            }
5765        }
5766    }
5767
5768    /// Opens any paths that have been successfully NAT traversed.
5769    fn open_nat_traversed_paths(&mut self, now: Instant) {
5770        while let Some(network_path) = self
5771            .n0_nat_traversal
5772            .client_side_mut()
5773            .ok()
5774            .and_then(|s| s.pop_pending_path_open())
5775        {
5776            match self.open_path_ensure(network_path, PathStatus::Backup, now) {
5777                Ok((path_id, already_existed)) => {
5778                    debug!(
5779                        %path_id,
5780                        ?network_path,
5781                        new_path = !already_existed,
5782                        "Opened NAT traversal path",
5783                    );
5784                }
5785                Err(err) => match err {
5786                    PathError::MultipathNotNegotiated
5787                    | PathError::ServerSideNotAllowed
5788                    | PathError::ValidationFailed
5789                    | PathError::InvalidRemoteAddress(_) => {
5790                        error!(
5791                            ?err,
5792                            ?network_path,
5793                            "Failed to open path for successful NAT traversal"
5794                        );
5795                    }
5796                    PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => {
5797                        // Temporary error, put back.
5798                        self.n0_nat_traversal
5799                            .client_side_mut()
5800                            .map(|s| s.push_pending_path_open(network_path))
5801                            .ok();
5802                        debug!(
5803                            ?err,
5804                            ?network_path,
5805                            "Blocked opening NAT traversal path, enqueued"
5806                        );
5807                        return;
5808                    }
5809                },
5810            }
5811        }
5812    }
5813
5814    /// Migrates the 4-tuple of the path.
5815    ///
5816    /// This creates a new [`PathData`] for the migrated path and stores the previous
5817    /// [`PathData`] in [`PathState::prev`].
5818    fn migrate(
5819        &mut self,
5820        path_id: PathId,
5821        now: Instant,
5822        network_path: FourTuple,
5823        observed_addr: Option<ObservedAddr>,
5824    ) {
5825        trace!(
5826            new_4tuple = %network_path,
5827            prev_4tuple = %self.path_data(path_id).network_path,
5828            %path_id,
5829            "migration initiated",
5830        );
5831        self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
5832        // TODO(@divma): conditions for path migration in multipath are very specific, check them
5833        // again to prevent path migrations that should actually create a new path
5834
5835        // Reset rtt/congestion state for new path unless it looks like a NAT rebinding.
5836        // Note that the congestion window will not grow until validation terminates. Helps mitigate
5837        // amplification attacks performed by spoofing source addresses.
5838        let prev_pto = self.pto(SpaceKind::Data, path_id);
5839        let path = self.paths.get_mut(&path_id).expect("known path");
5840        let mut new_path_data = if network_path.remote.is_ipv4()
5841            && network_path.remote.ip() == path.data.network_path.remote.ip()
5842        {
5843            PathData::from_previous(network_path, &path.data, self.path_generation_counter, now)
5844        } else {
5845            let peer_max_udp_payload_size =
5846                u16::try_from(self.peer_params.max_udp_payload_size.into_inner())
5847                    .unwrap_or(u16::MAX);
5848            PathData::new(
5849                network_path,
5850                self.allow_mtud,
5851                Some(peer_max_udp_payload_size),
5852                self.path_generation_counter,
5853                now,
5854                &self.config,
5855            )
5856        };
5857        new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone();
5858        if let Some(report) = observed_addr
5859            && let Some(updated) = new_path_data.update_observed_addr_report(report)
5860        {
5861            tracing::info!("adding observed addr event from migration");
5862            self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5863                id: path_id,
5864                addr: updated,
5865            }));
5866        }
5867        new_path_data.pending_challenge = true;
5868        new_path_data.pending.observed_address = self
5869            .config
5870            .address_discovery_role
5871            .should_report(&self.peer_params.address_discovery_role);
5872
5873        let mut prev_path_data = mem::replace(&mut path.data, new_path_data);
5874
5875        // Only store this as previous path if it was validated. For all we know there could
5876        // already be a previous path stored which might have been validated in the past,
5877        // which is more valuable than one that's not yet validated.
5878        //
5879        // With multipath it is possible that there are no remote CIDs for the path ID
5880        // yet. In this case we would never have sent on this path yet and would not be able
5881        // to send a PATH_CHALLENGE either, which is currently a fire-and-forget affair
5882        // anyway. So don't store such a path either.
5883        if !prev_path_data.validated
5884            && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active)
5885        {
5886            prev_path_data.pending_challenge = true;
5887            // We haven't updated the remote CID yet, this captures the remote CID we were using on
5888            // the previous path.
5889            path.prev = Some((cid, prev_path_data));
5890        }
5891
5892        // We need to re-assign the correct remote to this path in qlog
5893        self.qlog.emit_tuple_assigned(path_id, network_path, now);
5894
5895        self.timers.set(
5896            Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5897            now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto),
5898            self.qlog.with_time(now),
5899        );
5900    }
5901
5902    /// Handle a change in the local address, i.e. an active migration
5903    ///
5904    /// In the general (non-multipath) case, paths will perform a RFC9000 migration and be pinged
5905    /// for a liveness check. This is the behaviour of a path assumed to be recoverable, even if
5906    /// this is not the case.
5907    ///
5908    /// Clients in a connection in which multipath has been negotiated should migrate paths to new
5909    /// [`PathId`]s. For paths that are known to be non-recoverable can be migrated to a new
5910    /// [`PathId`] by closing the current path, and opening a new one to the same remote. Treating
5911    /// paths as non recoverable when necessary accelerates connectivity re-establishment, or might
5912    /// allow it altogether.
5913    ///
5914    /// The optional `hint` allows callers to indicate when paths are non-recoverable and should be
5915    /// migrated to new a [`PathId`].
5916    // NOTE: only clients are allowed to migrate, but generally dealing with RFC9000 migrations is
5917    // lacking <https://github.com/n0-computer/noq/issues/364>
5918    pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) {
5919        debug!("network changed");
5920        if self.state.is_drained() {
5921            return;
5922        }
5923        if self.highest_space < SpaceKind::Data {
5924            for path in self.paths.values_mut() {
5925                // Clear the local address for it to be obtained from the socket again.
5926                path.data.network_path.local_ip = None;
5927            }
5928
5929            self.update_remote_cid(PathId::ZERO);
5930            self.ping();
5931
5932            return;
5933        }
5934
5935        // Paths that can't recover so a new path should be open instead. If multipath is not
5936        // negotiated, this will be empty.
5937        let mut non_recoverable_paths = Vec::default();
5938        let mut recoverable_paths = Vec::default();
5939        let mut open_paths = 0;
5940
5941        let is_multipath_negotiated = self.is_multipath_negotiated();
5942        let is_client = self.side().is_client();
5943        let immediate_ack_allowed = self.peer_supports_ack_frequency();
5944
5945        for (path_id, path) in self.paths.iter_mut() {
5946            if self.abandoned_paths.contains(path_id) {
5947                continue;
5948            }
5949            open_paths += 1;
5950
5951            // Read the network path BEFORE clearing local_ip, so the hint can
5952            // check which interface the path was using.
5953            let network_path = path.data.network_path;
5954
5955            // Clear the local address for it to be obtained from the socket again. This applies to
5956            // all paths, regardless of being considered recoverable or not
5957            path.data.network_path.local_ip = None;
5958            let remote = network_path.remote;
5959
5960            // Without multipath, the connection tries to recover the single path, whereas with
5961            // multipath, even in a single-path scenario, we attempt to migrate the path to a new
5962            // PathId.
5963            let attempt_to_recover = if is_multipath_negotiated {
5964                // Use the hint to determine if the path can recover. When no hint is
5965                // provided, clients default to non-recoverable (abandon and re-open)
5966                // while servers default to recoverable (attempt in-place recovery).
5967                hint.map(|h| h.is_path_recoverable(*path_id, network_path))
5968                    .unwrap_or(!is_client)
5969            } else {
5970                // In the non multipath case, we try to recover the single active path
5971                true
5972            };
5973
5974            if attempt_to_recover {
5975                recoverable_paths.push((*path_id, remote));
5976            } else {
5977                non_recoverable_paths.push((*path_id, remote, path.data.local_status()))
5978            }
5979        }
5980
5981        /* NON RECOVERABLE PATHS */
5982        // This are handled first, so that in case the treatment intended for these fails, we can
5983        // go the recoverable route instead.
5984
5985        // Decide if we need to close first or open first in the multipath case.
5986        // - Opening first has a higher risk of getting limited by the negotiated MAX_PATH_ID.
5987        // - Closing first risks this being the only open path.
5988        // We prefer closing paths first unless we identify this is the last open path.
5989        let open_first = open_paths == non_recoverable_paths.len();
5990
5991        for (path_id, remote, status) in non_recoverable_paths.into_iter() {
5992            let network_path = FourTuple {
5993                remote,
5994                local_ip: None, /* allow the local ip to be discovered */
5995            };
5996
5997            if open_first && let Err(e) = self.open_path(network_path, status, now) {
5998                if self.side().is_client() {
5999                    debug!(%e, "Failed to open new path for network change");
6000                }
6001                // if this fails, let the path try to recover itself
6002                recoverable_paths.push((path_id, remote));
6003                continue;
6004            }
6005
6006            if let Err(e) =
6007                self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange)
6008            {
6009                debug!(%e,"Failed to close unrecoverable path after network change");
6010                recoverable_paths.push((path_id, remote));
6011                continue;
6012            }
6013
6014            if !open_first && let Err(e) = self.open_path(network_path, status, now) {
6015                // Path has already been closed if we got here. Since the path was not recoverable,
6016                // this might be desirable in any case, because other paths exist (!open_first) and
6017                // this was is considered non recoverable
6018                debug!(%e,"Failed to open new path for network change");
6019            }
6020        }
6021
6022        /* RECOVERABLE PATHS */
6023
6024        for (path_id, remote) in recoverable_paths.into_iter() {
6025            // Schedule a Ping for a liveness check.
6026            if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) {
6027                path_space.pending_ping = true;
6028
6029                if immediate_ack_allowed {
6030                    path_space.pending_immediate_ack = true;
6031                }
6032            }
6033
6034            // Reset PTO backoff so retransmits resume promptly. Congestion controller and
6035            // RTT are intentionally preserved for recoverable paths. We explicitly allow
6036            // this reset also during the handshake, so do not check
6037            // Self::peer_competed_handshake_address_validation.
6038            if let Some(path) = self.paths.get_mut(&path_id) {
6039                path.data.pto_count = 0;
6040            }
6041            self.set_loss_detection_timer(now, path_id);
6042
6043            let Some((reset_token, retired)) =
6044                self.remote_cids.get_mut(&path_id).and_then(CidQueue::next)
6045            else {
6046                continue;
6047            };
6048
6049            // Retire the current remote CID and any CIDs we had to skip.
6050            self.spaces[SpaceId::Data]
6051                .pending
6052                .retire_cids
6053                .extend(retired.map(|seq| (path_id, seq)));
6054
6055            debug_assert!(!self.state.is_drained()); // required for endpoint_events, checked above
6056            self.endpoint_events
6057                .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
6058        }
6059    }
6060
6061    /// Switch to a previously unused remote connection ID, if possible
6062    fn update_remote_cid(&mut self, path_id: PathId) {
6063        let Some((reset_token, retired)) = self
6064            .remote_cids
6065            .get_mut(&path_id)
6066            .and_then(|cids| cids.next())
6067        else {
6068            return;
6069        };
6070
6071        // Retire the current remote CID and any CIDs we had to skip.
6072        self.spaces[SpaceId::Data]
6073            .pending
6074            .retire_cids
6075            .extend(retired.map(|seq| (path_id, seq)));
6076        let remote = self.path_data(path_id).network_path.remote;
6077        self.set_reset_token(path_id, remote, reset_token);
6078    }
6079
6080    /// Sends this reset token to the endpoint
6081    ///
6082    /// The endpoint needs to know the reset tokens issued by the peer, so that if the peer
6083    /// sends a reset token it knows to route it to this connection. See RFC 9000 section
6084    /// 10.3. Stateless Reset.
6085    ///
6086    /// Reset tokens are different for each path, the endpoint identifies paths by peer
6087    /// socket address however, not by path ID.
6088    fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) {
6089        debug_assert!(!self.state.is_drained()); // required for endpoint events, set_reset_token is never called for drained connections
6090        self.endpoint_events
6091            .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
6092
6093        // During the handshake the server sends a reset token in the transport
6094        // parameters. When we are the client and we receive the reset token during the
6095        // handshake we want this to affect our peer transport parameters.
6096        // TODO(flub): Pretty sure this is pointless, the entire params is overwritten
6097        //    shortly after this was called.  And then the params don't have this anymore.
6098        if path_id == PathId::ZERO {
6099            self.peer_params.stateless_reset_token = Some(reset_token);
6100        }
6101    }
6102
6103    /// Issue an initial set of connection IDs to the peer upon connection
6104    fn issue_first_cids(&mut self, now: Instant) {
6105        if self
6106            .local_cid_state
6107            .get(&PathId::ZERO)
6108            .expect("PathId::ZERO exists when the connection is created")
6109            .cid_len()
6110            == 0
6111        {
6112            return;
6113        }
6114
6115        // Subtract 1 to account for the CID we supplied while handshaking
6116        let mut n = self.peer_params.issue_cids_limit() - 1;
6117        if let ConnectionSide::Server { server_config } = &self.side
6118            && server_config.has_preferred_address()
6119        {
6120            // We also sent a CID in the transport parameters
6121            n -= 1;
6122        }
6123        debug_assert!(!self.state.is_drained()); // requirement for endpoint_events
6124        self.endpoint_events
6125            .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6126    }
6127
6128    /// Issues an initial set of CIDs for paths that have not yet had any CIDs issued
6129    ///
6130    /// Later CIDs are issued when CIDs expire or are retired by the peer.
6131    fn issue_first_path_cids(&mut self, now: Instant) {
6132        if let Some(max_path_id) = self.max_path_id() {
6133            let mut path_id = self.max_path_id_with_cids.next();
6134            while path_id <= max_path_id {
6135                self.endpoint_events
6136                    .push_back(EndpointEventInner::NeedIdentifiers(
6137                        path_id,
6138                        now,
6139                        self.peer_params.issue_cids_limit(),
6140                    ));
6141                path_id = path_id.next();
6142            }
6143            self.max_path_id_with_cids = max_path_id;
6144        }
6145    }
6146
6147    /// Populates a packet with frames
6148    ///
6149    /// This tries to fit as many frames as possible into the packet.
6150    ///
6151    /// *path_exclusive_only* means to only build frames which can only be sent on this
6152    /// *path.  This is used in multipath for backup paths while there is still an active
6153    /// *path.
6154    fn populate_packet<'a, 'b>(
6155        &mut self,
6156        now: Instant,
6157        space_id: SpaceId,
6158        path_id: PathId,
6159        scheduling_info: &PathSchedulingInfo,
6160        builder: &mut PacketBuilder<'a, 'b>,
6161    ) {
6162        let is_multipath_negotiated = self.is_multipath_negotiated();
6163        let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level());
6164        let is_0rtt = space_id == SpaceId::Data && !space_has_keys;
6165        let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
6166        let space = &mut self.spaces[space_id];
6167        let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6168        space
6169            .for_path(path_id)
6170            .pending_acks
6171            .maybe_ack_non_eliciting();
6172
6173        // HANDSHAKE_DONE
6174        if !is_0rtt
6175            && !scheduling_info.is_abandoned
6176            && scheduling_info.may_send_data
6177            && mem::replace(&mut space.pending.handshake_done, false)
6178        {
6179            builder.write_frame(frame::HandshakeDone, stats);
6180        }
6181
6182        // PING
6183        if !scheduling_info.is_abandoned
6184            && mem::replace(&mut space.for_path(path_id).pending_ping, false)
6185        {
6186            builder.write_frame(frame::Ping, stats);
6187        }
6188
6189        // IMMEDIATE_ACK
6190        if !scheduling_info.is_abandoned
6191            && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false)
6192        {
6193            debug_assert_eq!(
6194                space_id,
6195                SpaceId::Data,
6196                "immediate acks must be sent in the data space"
6197            );
6198            builder.write_frame(frame::ImmediateAck, stats);
6199        }
6200
6201        // ACK
6202        //
6203        // In the Initial and Handshake spaces, every packet repeats the pending ACK ranges. A
6204        // lost ACK of a multi-datagram flight's head otherwise makes the peer resend the whole
6205        // flight on each PTO, and each resend can lose the tail again, until an ACK gets through.
6206        if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6207            for path_id in space
6208                .number_spaces
6209                .iter_mut()
6210                .filter(|(_, pns)| {
6211                    pns.pending_acks.can_send()
6212                        || (space_id != SpaceId::Data && !pns.pending_acks.ranges().is_empty())
6213                })
6214                .map(|(&path_id, _)| path_id)
6215                .collect::<Vec<_>>()
6216            {
6217                Self::populate_acks(
6218                    now,
6219                    self.receiving_ecn,
6220                    path_id,
6221                    space_id,
6222                    space,
6223                    is_multipath_negotiated,
6224                    builder,
6225                    stats,
6226                    space_has_keys,
6227                );
6228            }
6229        }
6230
6231        // ACK_FREQUENCY
6232        if !scheduling_info.is_abandoned
6233            && scheduling_info.may_send_data
6234            && mem::replace(&mut space.pending.ack_frequency, false)
6235        {
6236            let sequence_number = self.ack_frequency.next_sequence_number();
6237
6238            // Safe to unwrap because this is always provided when ACK frequency is enabled
6239            let config = self.config.ack_frequency_config.as_ref().unwrap();
6240
6241            // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error
6242            let max_ack_delay = self.ack_frequency.candidate_max_ack_delay(
6243                path.rtt.get(),
6244                config,
6245                &self.peer_params,
6246            );
6247
6248            let frame = frame::AckFrequency {
6249                sequence: sequence_number,
6250                ack_eliciting_threshold: config.ack_eliciting_threshold,
6251                request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX),
6252                reordering_threshold: config.reordering_threshold,
6253            };
6254            builder.write_frame(frame, stats);
6255
6256            self.ack_frequency
6257                .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay);
6258            path.congestion.on_ack_frequency_update(
6259                config.ack_eliciting_threshold.into_inner(),
6260                max_ack_delay,
6261            );
6262        }
6263
6264        // PATH_CHALLENGE (on-path)
6265        if !scheduling_info.is_abandoned
6266            && space_id == SpaceId::Data
6267            && path.pending_challenge
6268            // we don't want to send new challenges if we are already closing
6269            && !self.state.is_closed()
6270            && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND
6271            // An on-path PATH_CHALLENGE must be part of datagrams expanded to the
6272            // MIN_INITIAL_SIZE (1200 bytes).
6273            && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6274        {
6275            path.pending_challenge = false;
6276
6277            let token = self.rng.random();
6278            path.record_path_challenge_sent(now, token, path.network_path);
6279            // Generate a new challenge every time we send a new PATH_CHALLENGE
6280            let challenge = frame::PathChallenge(token);
6281            builder.write_frame(challenge, stats);
6282            builder.require_padding();
6283
6284            // On-path challenges need a PATH_RESPONSE and not only an ACK which can be
6285            // received on any path. So set a timer manually instead of relying on the usual
6286            // LossDetection/PTO timer. This timer interval keeps exponentially increasing
6287            // with missing responses like the normal PTO interval.
6288            self.timers.set(
6289                Timer::PerPath(path_id, PathTimer::PathChallengeLost),
6290                now + path.on_path_challenge_pto(),
6291                self.qlog.with_time(now),
6292            );
6293
6294            if is_multipath_negotiated && !path.validated && path.pending_challenge {
6295                // queue informing the path status along with the challenge
6296                space.pending.path_status.insert(path_id);
6297            }
6298
6299            // Always include an OBSERVED_ADDR frame with a PATH_CHALLENGE, regardless
6300            // of whether one has already been sent on this path.
6301            path.pending.observed_address = self
6302                .config
6303                .address_discovery_role
6304                .should_report(&self.peer_params.address_discovery_role);
6305        }
6306
6307        // PATH_RESPONSE (on-path)
6308        if !scheduling_info.is_abandoned
6309            && space_id == SpaceId::Data
6310            && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND
6311            // An on-path PATH_RESPONSE must be part of datagrams expanded to the
6312            // MIN_INITIAL_SIZE (1200 bytes).
6313            && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6314            && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path)
6315        {
6316            let response = frame::PathResponse(token);
6317            builder.write_frame(response, stats);
6318            builder.require_padding();
6319
6320            // NOTE: this is technically not required but might be useful to ride the
6321            // request/response nature of path challenges to refresh an observation
6322            // Since PATH_RESPONSE is a probing frame, this is allowed by the spec.
6323            path.pending.observed_address = self
6324                .config
6325                .address_discovery_role
6326                .should_report(&self.peer_params.address_discovery_role);
6327        }
6328
6329        // ADD_ADDRESS
6330        while space_id == SpaceId::Data
6331            && !scheduling_info.is_abandoned
6332            && scheduling_info.may_send_data
6333            && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining()
6334        {
6335            if let Some(added_address) = space.pending.add_address.pop_last() {
6336                builder.write_frame(added_address, stats);
6337            } else {
6338                break;
6339            }
6340        }
6341
6342        // REMOVE_ADDRESS
6343        while space_id == SpaceId::Data
6344            && !scheduling_info.is_abandoned
6345            && scheduling_info.may_send_data
6346            && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining()
6347        {
6348            if let Some(removed_address) = space.pending.remove_address.pop_last() {
6349                builder.write_frame(removed_address, stats);
6350            } else {
6351                break;
6352            }
6353        }
6354
6355        // REACH_OUT
6356        while !scheduling_info.is_abandoned
6357            && scheduling_info.may_send_data
6358            && let Some(reach_out) = space
6359                .pending
6360                .reach_out
6361                .pop_if(|frame| builder.frame_space_remaining() >= frame.size())
6362        {
6363            builder.write_frame(reach_out, stats);
6364        }
6365
6366        // PATH_ABANDON
6367        if space_id == SpaceId::Data
6368            && scheduling_info.is_abandoned
6369            && scheduling_info.may_self_abandon
6370            && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6371            && let Some(error_code) = space.pending.path_abandon.remove(&path_id)
6372        {
6373            let frame = frame::PathAbandon {
6374                path_id,
6375                error_code,
6376            };
6377            builder.write_frame(frame, stats);
6378
6379            // Consider remotely issued CIDs as retired now that we have sent this frame at
6380            // least once.
6381            self.remote_cids.remove(&path_id);
6382        }
6383        while space_id == SpaceId::Data
6384            && scheduling_info.may_send_data
6385            && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6386            && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first()
6387        {
6388            let frame = frame::PathAbandon {
6389                path_id: abandoned_path_id,
6390                error_code,
6391            };
6392            builder.write_frame(frame, stats);
6393
6394            // Consider remotely issued CIDs as retired now that we have sent this frame at
6395            // least once.
6396            self.remote_cids.remove(&abandoned_path_id);
6397        }
6398
6399        // OBSERVED_ADDR
6400        if !scheduling_info.is_abandoned
6401            && space_id == SpaceId::Data
6402            && path.pending.observed_address
6403        {
6404            let frame = ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no);
6405            if builder.frame_space_remaining() > frame.size() {
6406                builder.write_frame(frame, stats);
6407
6408                self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8);
6409                path.pending.observed_address = false;
6410            }
6411        }
6412
6413        // CRYPTO
6414        while !is_0rtt
6415            && !scheduling_info.is_abandoned
6416            && scheduling_info.may_send_data
6417            && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND
6418        {
6419            let Some(mut frame) = space.pending.crypto.pop_front() else {
6420                break;
6421            };
6422
6423            // Calculate the maximum amount of crypto data we can store in the buffer.
6424            // Since the offset is known, we can reserve the exact size required to encode it.
6425            // For length we reserve 2bytes which allows to encode up to 2^14,
6426            // which is more than what fits into normally sized QUIC frames.
6427            let max_crypto_data_size = builder.frame_space_remaining()
6428                - 1 // Frame Type
6429                - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) })
6430                - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes
6431
6432            let len = frame
6433                .data
6434                .len()
6435                .min(2usize.pow(14) - 1)
6436                .min(max_crypto_data_size);
6437
6438            let data = frame.data.split_to(len);
6439            let offset = frame.offset;
6440            let truncated = frame::Crypto { offset, data };
6441            builder.write_frame(truncated, stats);
6442
6443            if !frame.data.is_empty() {
6444                frame.offset += len as u64;
6445                space.pending.crypto.push_front(frame);
6446            }
6447        }
6448
6449        // PATH_STATUS_AVAILABLE & PATH_STATUS_BACKUP
6450        while space_id == SpaceId::Data
6451            && !scheduling_info.is_abandoned
6452            && scheduling_info.may_send_data
6453            && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining()
6454        {
6455            let Some(path_id) = space.pending.path_status.pop_first() else {
6456                break;
6457            };
6458            let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else {
6459                trace!(%path_id, "discarding queued path status for unknown path");
6460                continue;
6461            };
6462
6463            let seq = path.status.seq();
6464            match path.local_status() {
6465                PathStatus::Available => {
6466                    let frame = frame::PathStatusAvailable {
6467                        path_id,
6468                        status_seq_no: seq,
6469                    };
6470                    builder.write_frame(frame, stats);
6471                }
6472                PathStatus::Backup => {
6473                    let frame = frame::PathStatusBackup {
6474                        path_id,
6475                        status_seq_no: seq,
6476                    };
6477                    builder.write_frame(frame, stats);
6478                }
6479            }
6480        }
6481
6482        // MAX_PATH_ID
6483        if space_id == SpaceId::Data
6484            && !scheduling_info.is_abandoned
6485            && scheduling_info.may_send_data
6486            && space.pending.max_path_id
6487            && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining()
6488        {
6489            let frame = frame::MaxPathId(self.local_max_path_id);
6490            builder.write_frame(frame, stats);
6491            space.pending.max_path_id = false;
6492        }
6493
6494        // PATHS_BLOCKED
6495        if space_id == SpaceId::Data
6496            && !scheduling_info.is_abandoned
6497            && scheduling_info.may_send_data
6498            && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6499            && let Some(remote_max_path_id) = space.pending.paths_blocked.take()
6500        {
6501            let frame = frame::PathsBlocked(remote_max_path_id);
6502            builder.write_frame(frame, stats);
6503        }
6504
6505        // PATH_CIDS_BLOCKED
6506        while space_id == SpaceId::Data
6507            && !scheduling_info.is_abandoned
6508            && scheduling_info.may_send_data
6509            && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6510        {
6511            let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else {
6512                break;
6513            };
6514            let frame = frame::PathCidsBlocked { path_id, next_seq };
6515            builder.write_frame(frame, stats);
6516        }
6517
6518        // RESET_STREAM, STOP_SENDING, MAX_DATA, MAX_STREAM_DATA, MAX_STREAMS
6519        if space_id == SpaceId::Data
6520            && !scheduling_info.is_abandoned
6521            && scheduling_info.may_send_data
6522        {
6523            self.streams
6524                .write_control_frames(builder, &mut space.pending, stats);
6525        }
6526
6527        // NEW_CONNECTION_ID
6528        let cid_len = self
6529            .local_cid_state
6530            .values()
6531            .map(|cid_state| cid_state.cid_len())
6532            .max()
6533            .expect("some local CID state must exist");
6534        let new_cid_size_bound =
6535            frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len);
6536        while !scheduling_info.is_abandoned
6537            && scheduling_info.may_send_data
6538            && builder.frame_space_remaining() > new_cid_size_bound
6539        {
6540            let Some(issued) = space.pending.new_cids.pop() else {
6541                break;
6542            };
6543            // Path was discarded after this CID was queued, drop.
6544            let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else {
6545                debug!(
6546                    path = %issued.path_id, seq = issued.sequence,
6547                    "dropping queued NEW_CONNECTION_ID for discarded path",
6548                );
6549                continue;
6550            };
6551            let retire_prior_to = cid_state.retire_prior_to();
6552
6553            let cid_path_id = match is_multipath_negotiated {
6554                true => Some(issued.path_id),
6555                false => {
6556                    debug_assert_eq!(issued.path_id, PathId::ZERO);
6557                    None
6558                }
6559            };
6560            let frame = frame::NewConnectionId {
6561                path_id: cid_path_id,
6562                sequence: issued.sequence,
6563                retire_prior_to,
6564                id: issued.id,
6565                reset_token: issued.reset_token,
6566            };
6567            builder.write_frame(frame, stats);
6568        }
6569
6570        // RETIRE_CONNECTION_ID
6571        let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated);
6572        while !scheduling_info.is_abandoned
6573            && scheduling_info.may_send_data
6574            && builder.frame_space_remaining() > retire_cid_bound
6575        {
6576            let (path_id, sequence) = match space.pending.retire_cids.pop() {
6577                Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq),
6578                Some((path_id, seq)) => (Some(path_id), seq),
6579                None => break,
6580            };
6581            let frame = frame::RetireConnectionId { path_id, sequence };
6582            builder.write_frame(frame, stats);
6583        }
6584
6585        // DATAGRAM
6586        let mut sent_datagrams = false;
6587        while !scheduling_info.is_abandoned
6588            && scheduling_info.may_send_data
6589            && builder.frame_space_remaining() > Datagram::SIZE_BOUND
6590            && space_id == SpaceId::Data
6591        {
6592            match self.datagrams.write(builder, stats) {
6593                true => {
6594                    sent_datagrams = true;
6595                }
6596                false => break,
6597            }
6598        }
6599        if self.datagrams.send_blocked && sent_datagrams {
6600            self.events.push_back(Event::DatagramsUnblocked);
6601            self.datagrams.send_blocked = false;
6602        }
6603
6604        let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6605
6606        // NEW_TOKEN
6607        if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6608            while let Some(network_path) = space.pending.new_tokens.pop() {
6609                debug_assert_eq!(space_id, SpaceId::Data);
6610                let ConnectionSide::Server { server_config } = &self.side else {
6611                    panic!("NEW_TOKEN frames should not be enqueued by clients");
6612                };
6613
6614                if !network_path.is_probably_same_path(&path.network_path) {
6615                    // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only
6616                    // useful if used from the same IP address.  Thus, we abandon enqueued NEW_TOKEN
6617                    // frames upon an path change. Instead, when the new path becomes validated,
6618                    // NEW_TOKEN frames may be enqueued for the new path instead.
6619                    continue;
6620                }
6621
6622                let token = Token::new(
6623                    TokenPayload::Validation {
6624                        ip: network_path.remote.ip(),
6625                        issued: server_config.time_source.now(),
6626                    },
6627                    &mut self.rng,
6628                );
6629                let new_token = NewToken {
6630                    token: token.encode(&*server_config.token_key).into(),
6631                };
6632
6633                if builder.frame_space_remaining() < new_token.size() {
6634                    space.pending.new_tokens.push(network_path);
6635                    break;
6636                }
6637
6638                builder.write_frame(new_token, stats);
6639                builder.retransmits_mut().new_tokens.push(network_path);
6640            }
6641        }
6642
6643        // STREAM
6644        if !scheduling_info.is_abandoned
6645            && scheduling_info.may_send_data
6646            && space_id == SpaceId::Data
6647        {
6648            self.streams
6649                .write_stream_frames(builder, self.config.send_fairness, stats);
6650        }
6651    }
6652
6653    /// Write pending ACKs into a buffer
6654    fn populate_acks<'a, 'b>(
6655        now: Instant,
6656        receiving_ecn: bool,
6657        path_id: PathId,
6658        space_id: SpaceId,
6659        space: &mut PacketSpace,
6660        is_multipath_negotiated: bool,
6661        builder: &mut PacketBuilder<'a, 'b>,
6662        stats: &mut FrameStats,
6663        space_has_keys: bool,
6664    ) {
6665        // 0-RTT packets must never carry acks (which would have to be of handshake packets)
6666        debug_assert!(space_has_keys, "tried to send ACK in 0-RTT");
6667
6668        debug_assert!(
6669            is_multipath_negotiated || path_id == PathId::ZERO,
6670            "Only PathId::ZERO allowed without multipath (have {path_id:?})"
6671        );
6672        if is_multipath_negotiated {
6673            debug_assert!(
6674                space_id == SpaceId::Data || path_id == PathId::ZERO,
6675                "path acks must be sent in 1RTT space (have {space_id:?})"
6676            );
6677        }
6678
6679        let pns = space.for_path(path_id);
6680        let ranges = pns.pending_acks.ranges();
6681        debug_assert!(!ranges.is_empty(), "can not send empty ACK range");
6682        let ecn = if receiving_ecn {
6683            Some(&pns.ecn_counters)
6684        } else {
6685            None
6686        };
6687
6688        let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64;
6689        // TODO: This should come from `TransportConfig` if that gets configurable.
6690        let ack_delay_exp = TransportParameters::default().ack_delay_exponent;
6691        let delay = delay_micros >> ack_delay_exp.into_inner();
6692
6693        if is_multipath_negotiated && space_id == SpaceId::Data {
6694            if !ranges.is_empty() {
6695                let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn);
6696                builder.write_frame(frame, stats);
6697            }
6698        } else {
6699            builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats);
6700        }
6701    }
6702
6703    fn close_common(&mut self) {
6704        trace!("connection closed");
6705        self.timers.reset();
6706    }
6707
6708    fn set_close_timer(&mut self, now: Instant) {
6709        // QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO using the max PTO of
6710        // all paths.
6711        let pto_max = self.max_pto_for_space(self.highest_space);
6712        self.timers.set(
6713            Timer::Conn(ConnTimer::Close),
6714            now + 3 * pto_max,
6715            self.qlog.with_time(now),
6716        );
6717    }
6718
6719    /// Handle transport parameters received from the peer
6720    ///
6721    /// *remote_cid* and *local_cid* are the source and destination CIDs respectively of the
6722    /// *packet into which the transport parameters arrived.
6723    fn handle_peer_params(
6724        &mut self,
6725        params: TransportParameters,
6726        local_cid: ConnectionId,
6727        remote_cid: ConnectionId,
6728        now: Instant,
6729    ) -> Result<(), TransportError> {
6730        if Some(self.original_remote_cid) != params.initial_src_cid
6731            || (self.side.is_client()
6732                && (Some(self.initial_dst_cid) != params.original_dst_cid
6733                    || self.retry_src_cid != params.retry_src_cid))
6734        {
6735            return Err(TransportError::TRANSPORT_PARAMETER_ERROR(
6736                "CID authentication failure",
6737            ));
6738        }
6739        if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) {
6740            return Err(TransportError::PROTOCOL_VIOLATION(
6741                "multipath must not use zero-length CIDs",
6742            ));
6743        }
6744
6745        self.set_peer_params(params);
6746        self.qlog.emit_peer_transport_params_received(self, now);
6747
6748        Ok(())
6749    }
6750
6751    fn set_peer_params(&mut self, params: TransportParameters) {
6752        self.streams.set_params(&params);
6753        self.idle_timeout =
6754            negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout));
6755        trace!("negotiated max idle timeout {:?}", self.idle_timeout);
6756
6757        if let Some(ref info) = params.preferred_address {
6758            // During the handshake PathId::ZERO exists.
6759            self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId {
6760                path_id: None,
6761                sequence: 1,
6762                id: info.connection_id,
6763                reset_token: info.stateless_reset_token,
6764                retire_prior_to: 0,
6765            })
6766            .expect(
6767                "preferred address CID is the first received, and hence is guaranteed to be legal",
6768            );
6769            let remote = self.path_data(PathId::ZERO).network_path.remote;
6770            self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token);
6771        }
6772        self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(&params);
6773
6774        let mut multipath_enabled = false;
6775        if let (Some(local_max_path_id), Some(remote_max_path_id)) = (
6776            self.config.get_initial_max_path_id(),
6777            params.initial_max_path_id,
6778        ) {
6779            // multipath is enabled, register the local and remote maximums
6780            self.local_max_path_id = local_max_path_id;
6781            self.remote_max_path_id = remote_max_path_id;
6782            let initial_max_path_id = local_max_path_id.min(remote_max_path_id);
6783            debug!(%initial_max_path_id, "multipath negotiated");
6784            multipath_enabled = true;
6785        }
6786
6787        if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) =
6788            self.config
6789                .max_remote_nat_traversal_addresses
6790                .zip(params.max_remote_nat_traversal_addresses)
6791        {
6792            if multipath_enabled {
6793                let max_local_addresses = max_remotely_allowed_remote_addresses.get();
6794                let max_remote_addresses = max_locally_allowed_remote_addresses.get();
6795                self.n0_nat_traversal = n0_nat_traversal::State::new(
6796                    max_remote_addresses,
6797                    max_local_addresses,
6798                    self.side(),
6799                );
6800                debug!(
6801                    %max_remote_addresses, %max_local_addresses,
6802                    "n0's nat traversal negotiated"
6803                );
6804            } else {
6805                debug!("n0 nat traversal enabled for both endpoints, but multipath is missing")
6806            }
6807        }
6808
6809        self.peer_params = params;
6810        let peer_max_udp_payload_size =
6811            u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
6812        let address_discovery_negotiated = self
6813            .config
6814            .address_discovery_role
6815            .should_report(&self.peer_params.address_discovery_role);
6816
6817        let path = self.path_data_mut(PathId::ZERO);
6818        path.pending.observed_address = address_discovery_negotiated;
6819        path.mtud
6820            .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size);
6821    }
6822
6823    /// Decrypts a packet, returning the packet number on success
6824    fn decrypt_packet(
6825        &mut self,
6826        now: Instant,
6827        path_id: PathId,
6828        packet: &mut Packet,
6829    ) -> Result<Option<u64>, Option<TransportError>> {
6830        let result = self
6831            .crypto_state
6832            .decrypt_packet_body(packet, path_id, &self.spaces)?;
6833
6834        let Some(result) = result else {
6835            return Ok(None);
6836        };
6837
6838        if result.outgoing_key_update_acked
6839            && let Some(prev) = self.crypto_state.prev_crypto.as_mut()
6840        {
6841            prev.end_packet = Some((result.packet_number, now));
6842            self.set_key_discard_timer(now, packet.header.space());
6843        }
6844
6845        if result.incoming_key_update {
6846            trace!("key update authenticated");
6847            self.crypto_state
6848                .update_keys(Some((result.packet_number, now)), true);
6849            self.set_key_discard_timer(now, packet.header.space());
6850        }
6851
6852        Ok(Some(result.packet_number))
6853    }
6854
6855    fn peer_supports_ack_frequency(&self) -> bool {
6856        self.peer_params.min_ack_delay.is_some()
6857    }
6858
6859    /// Send an IMMEDIATE_ACK frame to the remote endpoint
6860    ///
6861    /// According to the spec, this will result in an error if the remote endpoint does not support
6862    /// the Acknowledgement Frequency extension
6863    pub(crate) fn immediate_ack(&mut self, path_id: PathId) {
6864        debug_assert_eq!(
6865            self.highest_space,
6866            SpaceKind::Data,
6867            "immediate ack must be written in the data space"
6868        );
6869        self.spaces[SpaceId::Data]
6870            .for_path(path_id)
6871            .pending_immediate_ack = true;
6872    }
6873
6874    /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests
6875    #[cfg(test)]
6876    pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> {
6877        let ConnectionEventInner::Datagram(DatagramConnectionEvent {
6878            path_id,
6879            first_decode,
6880            remaining,
6881            ..
6882        }) = &event.0
6883        else {
6884            return None;
6885        };
6886
6887        if remaining.is_some() {
6888            panic!("Packets should never be coalesced in tests");
6889        }
6890
6891        let decrypted_header = self
6892            .crypto_state
6893            .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?;
6894
6895        let mut packet = decrypted_header.packet?;
6896        self.crypto_state
6897            .decrypt_packet_body(&mut packet, *path_id, &self.spaces)
6898            .ok()?;
6899
6900        Some(packet.payload.to_vec())
6901    }
6902
6903    /// The number of bytes of packets containing retransmittable frames that have not been
6904    /// acknowledged or declared lost.
6905    #[cfg(test)]
6906    pub(crate) fn bytes_in_flight(&self) -> u64 {
6907        // TODO(@divma): consider including for multipath?
6908        self.path_data(PathId::ZERO).in_flight.bytes
6909    }
6910
6911    /// Number of bytes worth of non-ack-only packets that may be sent
6912    #[cfg(test)]
6913    pub(crate) fn congestion_window(&self) -> u64 {
6914        let path = self.path_data(PathId::ZERO);
6915        path.congestion
6916            .window()
6917            .saturating_sub(path.in_flight.bytes)
6918    }
6919
6920    /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running
6921    #[cfg(test)]
6922    pub(crate) fn is_idle(&self) -> bool {
6923        let current_timers = self.timers.values();
6924        current_timers
6925            .into_iter()
6926            .filter(|(timer, _)| {
6927                !matches!(
6928                    timer,
6929                    Timer::Conn(ConnTimer::KeepAlive)
6930                        | Timer::PerPath(_, PathTimer::PathKeepAlive)
6931                        | Timer::Conn(ConnTimer::PushNewCid)
6932                        | Timer::Conn(ConnTimer::KeyDiscard)
6933                )
6934            })
6935            .min_by_key(|(_, time)| *time)
6936            .is_none_or(|(timer, _)| {
6937                matches!(
6938                    timer,
6939                    Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle)
6940                )
6941            })
6942    }
6943
6944    /// Whether explicit congestion notification is in use on outgoing packets.
6945    #[cfg(test)]
6946    pub(crate) fn using_ecn(&self) -> bool {
6947        self.path_data(PathId::ZERO).sending_ecn
6948    }
6949
6950    /// The number of received bytes in the current path
6951    #[cfg(test)]
6952    pub(crate) fn total_recvd(&self) -> u64 {
6953        self.path_data(PathId::ZERO).total_recvd
6954    }
6955
6956    #[cfg(test)]
6957    pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) {
6958        self.local_cid_state
6959            .get(&PathId::ZERO)
6960            .unwrap()
6961            .active_seq()
6962    }
6963
6964    #[cfg(test)]
6965    #[track_caller]
6966    pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) {
6967        self.local_cid_state
6968            .get(&PathId(path_id))
6969            .unwrap()
6970            .active_seq()
6971    }
6972
6973    /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame
6974    /// with updated `retire_prior_to` field set to `v`
6975    #[cfg(test)]
6976    pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) {
6977        let n = self
6978            .local_cid_state
6979            .get_mut(&PathId::ZERO)
6980            .unwrap()
6981            .assign_retire_seq(v);
6982        debug_assert!(!self.state.is_drained()); // requirement for endpoint_events
6983        self.endpoint_events
6984            .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6985    }
6986
6987    /// Check the current active remote CID sequence for `PathId::ZERO`
6988    #[cfg(test)]
6989    pub(crate) fn active_remote_cid_seq(&self) -> u64 {
6990        self.remote_cids.get(&PathId::ZERO).unwrap().active_seq()
6991    }
6992
6993    /// Returns the detected maximum udp payload size for the current path
6994    #[cfg(test)]
6995    pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 {
6996        self.path_data(path_id).current_mtu()
6997    }
6998
6999    /// Triggers path validation on all paths
7000    #[cfg(test)]
7001    pub(crate) fn trigger_path_validation(&mut self) {
7002        for path in self.paths.values_mut() {
7003            path.data.pending_challenge = true;
7004        }
7005    }
7006
7007    /// Simulates a protocol violation error for test purposes.
7008    #[cfg(test)]
7009    pub fn simulate_protocol_violation(&mut self, now: Instant) {
7010        if !self.state.is_closed() {
7011            self.state
7012                .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation"));
7013            self.close_common();
7014            if !self.state.is_drained() {
7015                self.set_close_timer(now);
7016            }
7017            self.connection_close_pending = true;
7018        }
7019    }
7020
7021    /// Whether we have **on-path** 1-RTT data to send.
7022    ///
7023    /// This checks for frames that can only be sent in the data space (1-RTT):
7024    /// - Pending PATH_CHALLENGE frames on the active and previous path if just migrated.
7025    /// - Pending PATH_RESPONSE frames.
7026    /// - Pending data to send in STREAM frames.
7027    /// - Pending DATAGRAM frames to send.
7028    ///
7029    /// See also [`PacketSpace::can_send`] which keeps track of all other frame types that
7030    /// may need to be sent.
7031    fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames {
7032        let network_path = self.path_data(path_id).network_path;
7033        let space_specific = self
7034            .paths
7035            .get(&path_id)
7036            .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty())
7037            || self.spaces[SpaceKind::Data]
7038                .number_spaces
7039                .get(&path_id)
7040                .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path));
7041
7042        // Stream control frames are checked in PacketSpace::can_send, only check data here.
7043        let other = self.streams.can_send_stream_data()
7044            || self
7045                .datagrams
7046                .outgoing
7047                .front()
7048                .is_some_and(|x| x.size(true) <= max_size);
7049
7050        // All `false` fields are set in PacketSpace::can_send.
7051        SendableFrames {
7052            acks: false,
7053            close: false,
7054            space_specific,
7055            other,
7056        }
7057    }
7058
7059    /// Terminate the connection instantly, without sending a close packet
7060    fn kill(&mut self, reason: ConnectionError) {
7061        self.close_common();
7062        self.state
7063            .move_to_drained(Some(reason), &mut self.endpoint_events);
7064    }
7065
7066    /// Storage size required for the largest packet that can be transmitted on all currently
7067    /// available paths
7068    ///
7069    /// Buffers passed to [`Connection::poll_transmit`] should be at least this large.
7070    ///
7071    /// When multipath is enabled, this value is the minimum MTU across all available paths.
7072    pub fn current_mtu(&self) -> u16 {
7073        self.paths
7074            .iter()
7075            .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id))
7076            .map(|(_path_id, path_state)| path_state.data.current_mtu())
7077            .min()
7078            .unwrap_or(INITIAL_MTU)
7079    }
7080
7081    /// Size of non-frame data for a 1-RTT packet
7082    ///
7083    /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are
7084    /// frames. Changes if the length of the remote connection ID changes, which is expected to be
7085    /// rare. If `pn` is specified, may additionally change unpredictably due to variations in
7086    /// latency and packet loss.
7087    fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize {
7088        let pn_len = PacketNumber::new(
7089            pn,
7090            self.spaces[SpaceId::Data]
7091                .for_path(path)
7092                .largest_acked_packet_pn
7093                .unwrap_or(0),
7094        )
7095        .len();
7096
7097        // 1 byte for flags
7098        1 + self
7099            .remote_cids
7100            .get(&path)
7101            .map(|cids| cids.active().len())
7102            .unwrap_or(20)      // Max CID len in QUIC v1
7103            + pn_len
7104            + self.tag_len_1rtt()
7105    }
7106
7107    fn predict_1rtt_overhead_no_pn(&self) -> usize {
7108        let pn_len = 4;
7109
7110        let cid_len = self
7111            .remote_cids
7112            .values()
7113            .map(|cids| cids.active().len())
7114            .max()
7115            .unwrap_or(20); // Max CID len in QUIC v1
7116
7117        // 1 byte for flags
7118        1 + cid_len + pn_len + self.tag_len_1rtt()
7119    }
7120
7121    fn tag_len_1rtt(&self) -> usize {
7122        // encryption_keys for Data space returns 1-RTT keys if available, otherwise 0-RTT keys
7123        let packet_crypto = self
7124            .crypto_state
7125            .encryption_keys(SpaceKind::Data, self.side.side())
7126            .map(|(_header, packet, _level)| packet);
7127        // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of
7128        // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead,
7129        // but that would needlessly prevent sending datagrams during 0-RTT.
7130        packet_crypto.map_or(16, |x| x.tag_len())
7131    }
7132
7133    /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate
7134    fn on_path_validated(&mut self, path_id: PathId) {
7135        self.path_data_mut(path_id).validated = true;
7136        let ConnectionSide::Server { server_config } = &self.side else {
7137            return;
7138        };
7139        let network_path = self.path_data(path_id).network_path;
7140        let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens;
7141        new_tokens.clear();
7142        for _ in 0..server_config.validation_token.sent {
7143            new_tokens.push(network_path);
7144        }
7145    }
7146
7147    /// Handle new path status information: PATH_STATUS_AVAILABLE, PATH_STATUS_BACKUP
7148    fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) {
7149        if let Some(path) = self.paths.get_mut(&path_id) {
7150            path.data.status.remote_update(status, status_seq_no);
7151        } else {
7152            debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id);
7153        }
7154        self.events.push_back(
7155            PathEvent::RemoteStatus {
7156                id: path_id,
7157                status,
7158            }
7159            .into(),
7160        );
7161    }
7162
7163    /// Returns the maximum [`PathId`] to be used for sending in this connection.
7164    ///
7165    /// This is calculated as minimum between the local and remote's maximums when multipath is
7166    /// enabled, or `None` when disabled.
7167    ///
7168    /// For data that's received, we should use [`Self::local_max_path_id`] instead.
7169    /// The reasoning is that the remote might already have updated to its own newer
7170    /// [`Self::max_path_id`] after sending out a `MAX_PATH_ID` frame, but it got re-ordered.
7171    fn max_path_id(&self) -> Option<PathId> {
7172        if self.is_multipath_negotiated() {
7173            Some(self.remote_max_path_id.min(self.local_max_path_id))
7174        } else {
7175            None
7176        }
7177    }
7178
7179    /// Returns whether this connection has a socket that supports IPv6.
7180    ///
7181    /// TODO(matheus23): This is related to noq endpoint state's `ipv6` bool. We should move that
7182    /// info here instead of trying to hack around not knowing it exactly.
7183    pub(crate) fn is_ipv6(&self) -> bool {
7184        self.paths
7185            .values()
7186            .any(|p| p.data.network_path.remote.is_ipv6())
7187    }
7188
7189    /// Add addresses the local endpoint considers are reachable for nat traversal.
7190    pub fn add_nat_traversal_address(
7191        &mut self,
7192        address: SocketAddr,
7193    ) -> Result<(), n0_nat_traversal::Error> {
7194        if let Some(added) = self.n0_nat_traversal.add_local_address(address)? {
7195            self.spaces[SpaceId::Data].pending.add_address.insert(added);
7196        };
7197        Ok(())
7198    }
7199
7200    /// Removes an address the endpoing no longer considers reachable for nat traversal
7201    ///
7202    /// Addresses not present in the set will be silently ignored.
7203    pub fn remove_nat_traversal_address(
7204        &mut self,
7205        address: SocketAddr,
7206    ) -> Result<(), n0_nat_traversal::Error> {
7207        if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? {
7208            self.spaces[SpaceId::Data]
7209                .pending
7210                .remove_address
7211                .insert(removed);
7212        }
7213        Ok(())
7214    }
7215
7216    /// Get the current local nat traversal addresses
7217    pub fn get_local_nat_traversal_addresses(
7218        &self,
7219    ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7220        self.n0_nat_traversal.get_local_nat_traversal_addresses()
7221    }
7222
7223    /// Get the currently advertised nat traversal addresses by the server
7224    pub fn get_remote_nat_traversal_addresses(
7225        &self,
7226    ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7227        Ok(self
7228            .n0_nat_traversal
7229            .client_side()?
7230            .get_remote_nat_traversal_addresses())
7231    }
7232
7233    /// Initiates a new nat traversal round
7234    ///
7235    /// A nat traversal round involves advertising the client's local addresses in
7236    /// `REACH_OUT` frames, and initiating probing of the known remote addresses. When a new
7237    /// round is initiated, the previous one is cancelled.
7238    ///
7239    /// For all probes that succeed, if any, a new path will be opened on the successful
7240    /// 4-tuple.
7241    ///
7242    /// Returns the server addresses that are now being probed. If addresses fail due to
7243    /// spurious errors, these might succeed later and not be returned in this set.
7244    pub fn initiate_nat_traversal_round(
7245        &mut self,
7246        now: Instant,
7247    ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7248        if self.state.is_closed() {
7249            return Err(n0_nat_traversal::Error::Closed);
7250        }
7251
7252        let ipv6 = self.is_ipv6();
7253        let client_state = self.n0_nat_traversal.client_side_mut()?;
7254        let (mut reach_out_frames, probed_addrs) =
7255            client_state.initiate_nat_traversal_round(ipv6)?;
7256        if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) {
7257            self.timers.set(
7258                Timer::Conn(ConnTimer::NatTraversalProbeRetry),
7259                now + delay,
7260                self.qlog.with_time(now),
7261            );
7262        }
7263
7264        self.spaces[SpaceId::Data]
7265            .pending
7266            .reach_out
7267            .append(&mut reach_out_frames);
7268
7269        Ok(probed_addrs)
7270    }
7271
7272    /// Whether the handshake is considered **confirmed**.
7273    ///
7274    /// <https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2> defines a handshake to be
7275    /// confirmed when you know the peer successfully received and successfully processed
7276    /// your TLS Finished message.
7277    ///
7278    /// Implementation-wise this is the point at which the handshake crypto keys are
7279    /// discarded. So we can use this to know if the handshake is confirmed.
7280    fn is_handshake_confirmed(&self) -> bool {
7281        !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake)
7282    }
7283}
7284
7285impl fmt::Debug for Connection {
7286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7287        f.debug_struct("Connection")
7288            .field("handshake_cid", &self.handshake_cid)
7289            .finish()
7290    }
7291}
7292
7293/// The set of abandoned paths.
7294///
7295/// Implementation based on ArrayRangeSet to share more code. The memory space is
7296/// proportional to the number of concurrently open paths allowed. So does not grow
7297/// unbounded.
7298#[derive(Debug, Default)]
7299struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>);
7300
7301/// Size of the stack-allocated array in the [`ArrayRangeSet`].
7302///
7303/// A range is 2 u32's, so this is 16 * (4 + 4) = 128 bytes. A good size for inline data,
7304/// with plenty of ranges for common multipath use.
7305const ABANDONED_PATH_INLINE_RANGES: usize = 16;
7306
7307impl AbandonedPaths {
7308    /// The number of abandoned paths.
7309    fn len(&self) -> u32 {
7310        self.0.elts_count()
7311    }
7312
7313    /// The largest abandoned path.
7314    fn max(&self) -> Option<PathId> {
7315        self.0.max().map(PathId::from)
7316    }
7317
7318    /// Whether the path is already abandoned.
7319    fn contains(&self, val: &PathId) -> bool {
7320        self.0.contains(val.as_u32())
7321    }
7322
7323    /// Adds another abandoned path.
7324    fn insert(&mut self, val: PathId) {
7325        self.0.insert_one(val.as_u32());
7326    }
7327}
7328
7329/// Hints when the caller identifies a network change.
7330pub trait NetworkChangeHint: fmt::Debug + 'static {
7331    /// Inform the connection if a path may recover after a network change.
7332    ///
7333    /// After network changes, paths may not be recoverable. In this case, waiting for the path to
7334    /// become idle may take longer than what is desirable. If [`Self::is_path_recoverable`]
7335    /// returns `false`, a multipath-enabled, client-side connection will establish a new path to
7336    /// the same remote, closing the current one, instead of migrating the path.
7337    ///
7338    /// Paths that are deemed recoverable will simply be sent a PING for a liveness check.
7339    fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool;
7340}
7341
7342/// Return value for [`Connection::poll_transmit_path_space`].
7343#[derive(Debug)]
7344enum PollPathSpaceStatus {
7345    /// Nothing was written into the [`TransmitBuf`].
7346    NothingToSend {
7347        /// [`PathBlocked`] helps differentiate whether the path had something but was blocked by
7348        /// the congestoin window/pacing vs the path having no data queued for sending.
7349        path_blocked: PathBlocked,
7350    },
7351    /// One or more packets have been written into the [`TransmitBuf`].
7352    WrotePacket {
7353        /// The highest packet number.
7354        last_packet_number: u64,
7355        /// Whether to pad an already started datagram in the next packet.
7356        ///
7357        /// When packets in Initial, 0-RTT or Handshake packet do not fill the entire
7358        /// datagram they may decide to coalesce with the next packet from a higher
7359        /// encryption level on the same path. But the earlier packet may require specific
7360        /// size requirements for the datagram they are sent in.
7361        ///
7362        /// If a space did not complete the datagram, they use this to request the correct
7363        /// padding in the final packet of the datagram so that the final datagram will have
7364        /// the correct size.
7365        ///
7366        /// If a space did fill an entire datagram, it leaves this to the default of
7367        /// [`PadDatagram::No`].
7368        pad_datagram: PadDatagram,
7369    },
7370    /// Send the contents of the transmit immediately.
7371    ///
7372    /// Packets were written and the GSO batch must end now, regardless from whether higher
7373    /// spaces still have frames to write. This is used when the last datagram written would
7374    /// require too much padding to continue a GSO batch, which would waste space on the
7375    /// wire.
7376    Send {
7377        /// The highest packet number written into the transmit.
7378        last_packet_number: u64,
7379    },
7380}
7381
7382/// Information used to decide what frames to schedule into which packets.
7383///
7384/// Primarily used by [`Connection::poll_transmit_on_path`] and the functions that help
7385/// building packets for it: [`Connection::poll_transmit_path_space`] and
7386/// [`Connection::populate_packet`].
7387#[derive(Debug, Copy, Clone)]
7388struct PathSchedulingInfo {
7389    /// Whether the path is abandoned.
7390    ///
7391    /// Note that a path that is abandoned but still has CIDs can still send a packet. After
7392    /// sending that packet the CIDs issued by the remote have to be considered retired as
7393    /// well.
7394    is_abandoned: bool,
7395    /// Whether the path may send [`SpaceKind::Data`] frames.
7396    ///
7397    /// Some paths should only send frames from [`SendableFrames::space_specific`]. All other
7398    /// frames are essentially frames that can be sent on any [`SpaceKind::Data`] space. For
7399    /// those we want to respect packet scheduling rules however.
7400    ///
7401    /// Roughly speaking data frames are only sent on spaces that have CIDs, are not
7402    /// abandoned and have no *better* spaces. However see to comments where this is
7403    /// populated for the exact packet scheduling implementation.
7404    ///
7405    /// This essentially marks this paths as the best validated space ID. Except during
7406    /// the handshake in which case it does not need to be validated. Several paths could be
7407    /// equally good and all have this set to `true`, in that case packet scheduling can
7408    /// choose which path to use. Currently it chooses the lowest path that is not
7409    /// congestion blocked.
7410    ///
7411    /// Note that once in the closed or draining states this will never be true.
7412    may_send_data: bool,
7413    /// Whether the path may send a CONNECTION_CLOSE frame.
7414    ///
7415    /// This essentially marks this path as the best validated space ID with a fallback
7416    /// to unvalidated spaces if there are no validated spaces. Like for
7417    /// [`Self::may_send_data`] other paths could be equally good.
7418    may_send_close: bool,
7419    may_self_abandon: bool,
7420}
7421
7422#[derive(Debug, Copy, Clone, PartialEq, Eq)]
7423enum PathBlocked {
7424    No,
7425    AntiAmplification,
7426    Congestion,
7427    Pacing,
7428}
7429
7430/// Fields of `Connection` specific to it being client-side or server-side
7431enum ConnectionSide {
7432    Client {
7433        /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded
7434        token: Bytes,
7435        token_store: Arc<dyn TokenStore>,
7436        server_name: String,
7437    },
7438    Server {
7439        server_config: Arc<ServerConfig>,
7440    },
7441}
7442
7443impl ConnectionSide {
7444    fn is_client(&self) -> bool {
7445        self.side().is_client()
7446    }
7447
7448    fn is_server(&self) -> bool {
7449        self.side().is_server()
7450    }
7451
7452    fn side(&self) -> Side {
7453        match *self {
7454            Self::Client { .. } => Side::Client,
7455            Self::Server { .. } => Side::Server,
7456        }
7457    }
7458}
7459
7460impl From<SideArgs> for ConnectionSide {
7461    fn from(side: SideArgs) -> Self {
7462        match side {
7463            SideArgs::Client {
7464                token_store,
7465                server_name,
7466            } => Self::Client {
7467                token: token_store.take(&server_name).unwrap_or_default(),
7468                token_store,
7469                server_name,
7470            },
7471            SideArgs::Server {
7472                server_config,
7473                pref_addr_cid: _,
7474                path_validated: _,
7475            } => Self::Server { server_config },
7476        }
7477    }
7478}
7479
7480/// Parameters to `Connection::new` specific to it being client-side or server-side
7481pub(crate) enum SideArgs {
7482    Client {
7483        token_store: Arc<dyn TokenStore>,
7484        server_name: String,
7485    },
7486    Server {
7487        server_config: Arc<ServerConfig>,
7488        pref_addr_cid: Option<ConnectionId>,
7489        path_validated: bool,
7490    },
7491}
7492
7493impl SideArgs {
7494    pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> {
7495        match *self {
7496            Self::Client { .. } => None,
7497            Self::Server { pref_addr_cid, .. } => pref_addr_cid,
7498        }
7499    }
7500
7501    pub(crate) fn path_validated(&self) -> bool {
7502        match *self {
7503            Self::Client { .. } => true,
7504            Self::Server { path_validated, .. } => path_validated,
7505        }
7506    }
7507
7508    pub(crate) fn side(&self) -> Side {
7509        match *self {
7510            Self::Client { .. } => Side::Client,
7511            Self::Server { .. } => Side::Server,
7512        }
7513    }
7514}
7515
7516/// Reasons why a connection might be lost
7517#[derive(Debug, Error, Clone, PartialEq, Eq)]
7518pub enum ConnectionError {
7519    /// The peer doesn't implement any supported version
7520    #[error("peer doesn't implement any supported version")]
7521    VersionMismatch,
7522    /// The peer violated the QUIC specification as understood by this implementation
7523    #[error(transparent)]
7524    TransportError(#[from] TransportError),
7525    /// The peer's QUIC stack aborted the connection automatically
7526    #[error("aborted by peer: {0}")]
7527    ConnectionClosed(frame::ConnectionClose),
7528    /// The peer closed the connection
7529    #[error("closed by peer: {0}")]
7530    ApplicationClosed(frame::ApplicationClose),
7531    /// The peer is unable to continue processing this connection, usually due to having restarted
7532    #[error("reset by peer")]
7533    Reset,
7534    /// Communication with the peer has lapsed for longer than the negotiated idle timeout
7535    ///
7536    /// If neither side is sending keep-alives, a connection will time out after a long enough idle
7537    /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`]
7538    /// and [`TransportConfig::keep_alive_interval()`].
7539    #[error("timed out")]
7540    TimedOut,
7541    /// The local application closed the connection
7542    #[error("closed")]
7543    LocallyClosed,
7544    /// The connection could not be created because not enough of the CID space is available
7545    ///
7546    /// Try using longer connection IDs.
7547    #[error("CIDs exhausted")]
7548    CidsExhausted,
7549}
7550
7551impl From<Close> for ConnectionError {
7552    fn from(x: Close) -> Self {
7553        match x {
7554            Close::Connection(reason) => Self::ConnectionClosed(reason),
7555            Close::Application(reason) => Self::ApplicationClosed(reason),
7556        }
7557    }
7558}
7559
7560// For compatibility with API consumers
7561impl From<ConnectionError> for io::Error {
7562    fn from(x: ConnectionError) -> Self {
7563        use ConnectionError::*;
7564        let kind = match x {
7565            TimedOut => io::ErrorKind::TimedOut,
7566            Reset => io::ErrorKind::ConnectionReset,
7567            ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted,
7568            TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => {
7569                io::ErrorKind::Other
7570            }
7571        };
7572        Self::new(kind, x)
7573    }
7574}
7575
7576/// Errors that might trigger a path being closed
7577// TODO(@divma): maybe needs to be reworked based on what we want to do with the public API
7578#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
7579pub enum PathError {
7580    /// The extension was not negotiated with the peer
7581    #[error("multipath extension not negotiated")]
7582    MultipathNotNegotiated,
7583    /// Paths can only be opened client-side
7584    #[error("the server side may not open a path")]
7585    ServerSideNotAllowed,
7586    /// Current limits do not allow us to open more paths
7587    #[error("maximum number of concurrent paths reached")]
7588    MaxPathIdReached,
7589    /// No remote CIDs available to open a new path
7590    #[error("remoted CIDs exhausted")]
7591    RemoteCidsExhausted,
7592    /// Path could not be validated and will be abandoned
7593    #[error("path validation failed")]
7594    ValidationFailed,
7595    /// The remote address for the path is not supported by the endpoint
7596    #[error("invalid remote address")]
7597    InvalidRemoteAddress(SocketAddr),
7598}
7599
7600/// Errors triggered when abandoning a path
7601#[derive(Debug, Error, Clone, Eq, PartialEq)]
7602pub enum ClosePathError {
7603    /// Multipath is not negotiated
7604    #[error("Multipath extension not negotiated")]
7605    MultipathNotNegotiated,
7606    /// The path is already closed or was never opened
7607    #[error("closed path")]
7608    ClosedPath,
7609    /// Cannot close the last remaining open path via the local API.
7610    ///
7611    /// Use [`Connection::close`] to end the connection instead.
7612    #[error("last open path")]
7613    LastOpenPath,
7614}
7615
7616/// Error when the multipath extension was not negotiated, but attempted to be used.
7617#[derive(Debug, Error, Clone, Copy)]
7618#[error("Multipath extension not negotiated")]
7619pub struct MultipathNotNegotiated {
7620    _private: (),
7621}
7622
7623/// Events of interest to the application
7624#[derive(Debug)]
7625pub enum Event {
7626    /// The connection's handshake data is ready
7627    HandshakeDataReady,
7628    /// The connection was successfully established
7629    Connected,
7630    /// The TLS handshake was confirmed
7631    HandshakeConfirmed,
7632    /// The connection was lost
7633    ///
7634    /// Emitted when the connection is closed due to an error, a timeout, or the peer closing it.
7635    /// This is **not** emitted when the local application closes the connection via
7636    /// [`Connection::close()`](crate::Connection::close). In that case, pending operations will
7637    /// fail with [`ConnectionError::LocallyClosed`].
7638    ConnectionLost {
7639        /// Reason that the connection was closed
7640        reason: ConnectionError,
7641    },
7642    /// Stream events
7643    Stream(StreamEvent),
7644    /// One or more application datagrams have been received
7645    DatagramReceived,
7646    /// One or more application datagrams have been sent after blocking
7647    DatagramsUnblocked,
7648    /// (Multi)Path events
7649    Path(PathEvent),
7650    /// n0's nat traversal events
7651    NatTraversal(n0_nat_traversal::Event),
7652}
7653
7654impl From<PathEvent> for Event {
7655    fn from(source: PathEvent) -> Self {
7656        Self::Path(source)
7657    }
7658}
7659
7660fn get_max_ack_delay(params: &TransportParameters) -> Duration {
7661    Duration::from_micros(params.max_ack_delay.0 * 1000)
7662}
7663
7664/// Prevents overflow and improves behavior in extreme circumstances.
7665const MAX_BACKOFF_EXPONENT: u32 = 16;
7666
7667/// The max interval between successive tail-loss probes.
7668///
7669/// This is the "normal" value we use.
7670const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2);
7671
7672/// The idle time, below which we use the shorter [`MAX_PTO_FAST_INTERVAL`].
7673const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25);
7674
7675/// The max interval between successive tail-loss probes with short idle times.
7676///
7677/// If the path or connection idle time is less than [`MIN_IDLE_FOR_FAST_PTO`] then we use
7678/// this value to ensure we have plenty of retransmits before we reach the idle time.
7679const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1);
7680
7681/// The RTT threshold above which we cap the PTO interval to 1.5 * smoothed_rtt
7682///
7683/// This is RTT time above which 1.5 * RTT > [`MAX_PTO_INTERVAL`], for these links we want
7684/// to extend the interval between tail-loss probes to not fill the entire pipe with them.
7685const SLOW_RTT_THRESHOLD: Duration =
7686    Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3);
7687
7688/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag
7689///
7690/// This must be at least as large as the header for a well-formed empty packet to be coalesced,
7691/// plus some space for frames. We only care about handshake headers because short header packets
7692/// necessarily have smaller headers, and initial packets are only ever the first packet in a
7693/// datagram (because we coalesce in ascending packet space order and the only reason to split a
7694/// packet is when packet space changes).
7695const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32;
7696
7697/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header
7698///
7699/// Excludes packet-type-specific fields such as packet number or Initial token
7700// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid +
7701// scid len + scid + length + pn
7702const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize =
7703    1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4;
7704
7705#[derive(Default)]
7706struct SentFrames {
7707    retransmits: ThinRetransmits,
7708    path_retransmits: PathRetransmits,
7709    /// The packet number of the largest acknowledged packet for each path
7710    largest_acked: FxHashMap<PathId, u64>,
7711    stream_frames: StreamMetaVec,
7712    /// Whether the packet contains non-retransmittable frames (like datagrams)
7713    non_retransmits: bool,
7714    /// If the datagram containing these frames should be padded to the min MTU
7715    requires_padding: bool,
7716}
7717
7718impl SentFrames {
7719    /// Returns whether the packet contains only ACKs
7720    fn is_ack_only(&self, streams: &StreamsState) -> bool {
7721        !self.largest_acked.is_empty()
7722            && !self.non_retransmits
7723            && self.stream_frames.is_empty()
7724            && self.retransmits.is_empty(streams)
7725    }
7726
7727    fn retransmits_mut(&mut self) -> &mut Retransmits {
7728        self.retransmits.get_or_create()
7729    }
7730
7731    fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) {
7732        use frame::EncodableFrame::*;
7733        match frame {
7734            PathAck(path_ack_encoder) => {
7735                if let Some(max) = path_ack_encoder.ranges.max() {
7736                    self.largest_acked.insert(path_ack_encoder.path_id, max);
7737                }
7738            }
7739            Ack(ack_encoder) => {
7740                if let Some(max) = ack_encoder.ranges.max() {
7741                    self.largest_acked.insert(PathId::ZERO, max);
7742                }
7743            }
7744            Close(_) => { /* non retransmittable, but after this we don't really care */ }
7745            PathResponse(_) => self.non_retransmits = true,
7746            HandshakeDone(_) => self.retransmits_mut().handshake_done = true,
7747            ReachOut(frame) => self.retransmits_mut().reach_out.push(frame),
7748            ObservedAddr(_) => self.path_retransmits.observed_address = true,
7749            Ping(_) => self.non_retransmits = true,
7750            ImmediateAck(_) => self.non_retransmits = true,
7751            AckFrequency(_) => self.retransmits_mut().ack_frequency = true,
7752            PathChallenge(_) => self.non_retransmits = true,
7753            Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto),
7754            PathAbandon(path_abandon) => {
7755                self.retransmits_mut()
7756                    .path_abandon
7757                    .entry(path_abandon.path_id)
7758                    .or_insert(path_abandon.error_code);
7759            }
7760            PathStatusAvailable(frame::PathStatusAvailable { path_id, .. })
7761            | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => {
7762                self.retransmits_mut().path_status.insert(path_id);
7763            }
7764            MaxPathId(_) => self.retransmits_mut().max_path_id = true,
7765            PathsBlocked(frame::PathsBlocked(path_id)) => {
7766                let paths_blocked = &mut self.retransmits_mut().paths_blocked;
7767                *paths_blocked = cmp::max(*paths_blocked, Some(path_id));
7768            }
7769            PathCidsBlocked(path_cids_blocked) => {
7770                self.retransmits_mut()
7771                    .path_cids_blocked
7772                    .entry(path_cids_blocked.path_id)
7773                    .and_modify(|next_seq| {
7774                        *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq);
7775                    })
7776                    .or_insert(path_cids_blocked.next_seq);
7777            }
7778            ResetStream(reset) => self
7779                .retransmits_mut()
7780                .reset_stream
7781                .push((reset.id, reset.error_code)),
7782            StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending),
7783            NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()),
7784            RetireConnectionId(retire_cid) => self
7785                .retransmits_mut()
7786                .retire_cids
7787                .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)),
7788            Datagram(_) => self.non_retransmits = true,
7789            NewToken(_) => {}
7790            AddAddress(add_address) => {
7791                self.retransmits_mut().add_address.insert(add_address);
7792            }
7793            RemoveAddress(remove_address) => {
7794                self.retransmits_mut().remove_address.insert(remove_address);
7795            }
7796            StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta),
7797            MaxData(_) => self.retransmits_mut().max_data = true,
7798            MaxStreamData(max) => {
7799                self.retransmits_mut().max_stream_data.insert(max.id);
7800            }
7801            MaxStreams(max_streams) => {
7802                self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true
7803            }
7804            StreamsBlocked(streams_blocked) => {
7805                self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true
7806            }
7807        }
7808    }
7809}
7810
7811/// Computes the negotiated idle timeout based on the transport parameters.
7812///
7813/// According to the definition of max_idle_timeout, a value of `0` means the timeout is
7814/// disabled; see <https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.4.1.>
7815///
7816/// According to the negotiation procedure, either the minimum of the timeouts or one
7817/// specified is used as the negotiated value; see
7818/// <https://www.rfc-editor.org/rfc/rfc9000#section-10.1-2.>
7819///
7820/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have
7821/// opted out of idle timeout.
7822fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> {
7823    match (x, y) {
7824        (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None,
7825        (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)),
7826        (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)),
7827        (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)),
7828    }
7829}
7830
7831#[cfg(test)]
7832mod tests {
7833    use super::*;
7834
7835    #[test]
7836    fn negotiate_max_idle_timeout_commutative() {
7837        let test_params = [
7838            (None, None, None),
7839            (None, Some(VarInt(0)), None),
7840            (None, Some(VarInt(2)), Some(Duration::from_millis(2))),
7841            (Some(VarInt(0)), Some(VarInt(0)), None),
7842            (
7843                Some(VarInt(2)),
7844                Some(VarInt(0)),
7845                Some(Duration::from_millis(2)),
7846            ),
7847            (
7848                Some(VarInt(1)),
7849                Some(VarInt(4)),
7850                Some(Duration::from_millis(1)),
7851            ),
7852        ];
7853
7854        for (left, right, result) in test_params {
7855            assert_eq!(negotiate_max_idle_timeout(left, right), result);
7856            assert_eq!(negotiate_max_idle_timeout(right, left), result);
7857        }
7858    }
7859
7860    #[test]
7861    fn abandoned_paths() {
7862        let mut t = AbandonedPaths::default();
7863
7864        t.insert(PathId(0));
7865        t.insert(PathId(1));
7866        assert_eq!(t.len(), 2);
7867        assert_eq!(t.0.range_count(), 1); // 2 elements compacted into one range
7868        assert!(t.contains(&PathId(0)));
7869        assert!(t.contains(&PathId(1)));
7870        assert!(!t.contains(&PathId(2)));
7871        assert!(!t.contains(&PathId(3)));
7872        assert_eq!(t.max(), Some(PathId(1)));
7873
7874        t.insert(PathId(3));
7875        assert_eq!(t.len(), 3);
7876        assert_eq!(t.0.range_count(), 2); // 3 elements compacted into 2 ranges
7877        assert!(t.contains(&PathId(0)));
7878        assert!(t.contains(&PathId(1)));
7879        assert!(!t.contains(&PathId(2)));
7880        assert!(t.contains(&PathId(3)));
7881        assert_eq!(t.max(), Some(PathId(3)));
7882
7883        t.insert(PathId(2));
7884        assert_eq!(t.len(), 4);
7885        assert_eq!(t.0.range_count(), 1); // 4 elements compacted into 1 range
7886        assert!(t.contains(&PathId(0)));
7887        assert!(t.contains(&PathId(1)));
7888        assert!(t.contains(&PathId(2)));
7889        assert!(t.contains(&PathId(3)));
7890        assert_eq!(t.max(), Some(PathId(3)));
7891    }
7892}