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