ant_quic/connection/
mod.rs

1use std::{
2    cmp,
3    collections::VecDeque,
4    convert::TryFrom,
5    fmt, io, mem,
6    net::{IpAddr, SocketAddr},
7    sync::Arc,
8};
9
10use bytes::{Bytes, BytesMut};
11use frame::StreamMetaVec;
12// Removed qlog feature
13
14use rand::{Rng, SeedableRng, rngs::StdRng};
15use thiserror::Error;
16use tracing::{debug, error, info, trace, trace_span, warn};
17
18use crate::{
19    Dir, Duration, EndpointConfig, Frame, INITIAL_MTU, Instant, MAX_CID_SIZE, MAX_STREAM_COUNT,
20    MIN_INITIAL_SIZE, Side, StreamId, TIMER_GRANULARITY, TokenStore, Transmit, TransportError,
21    TransportErrorCode, VarInt,
22    cid_generator::ConnectionIdGenerator,
23    cid_queue::CidQueue,
24    coding::BufMutExt,
25    config::{ServerConfig, TransportConfig},
26    crypto::{self, KeyPair, Keys, PacketKey},
27    endpoint::AddressDiscoveryStats,
28    frame::{self, Close, Datagram, FrameStruct, NewToken},
29    packet::{
30        FixedLengthConnectionIdParser, Header, InitialHeader, InitialPacket, LongType, Packet,
31        PacketNumber, PartialDecode, SpaceId,
32    },
33    range_set::ArrayRangeSet,
34    shared::{
35        ConnectionEvent, ConnectionEventInner, ConnectionId, DatagramConnectionEvent, EcnCodepoint,
36        EndpointEvent, EndpointEventInner,
37    },
38    token::{ResetToken, Token, TokenPayload},
39    transport_parameters::TransportParameters,
40};
41
42mod ack_frequency;
43use ack_frequency::AckFrequencyState;
44
45pub(crate) mod nat_traversal;
46use nat_traversal::NatTraversalState;
47pub(crate) use nat_traversal::{CoordinationPhase, NatTraversalError, NatTraversalRole};
48
49mod assembler;
50pub use assembler::Chunk;
51
52mod cid_state;
53use cid_state::CidState;
54
55mod datagrams;
56use datagrams::DatagramState;
57pub use datagrams::{Datagrams, SendDatagramError};
58
59mod mtud;
60mod pacing;
61
62mod packet_builder;
63use packet_builder::PacketBuilder;
64
65mod packet_crypto;
66use packet_crypto::{PrevCrypto, ZeroRttCrypto};
67
68mod paths;
69pub use paths::RttEstimator;
70use paths::{NatTraversalChallenges, PathData, PathResponses};
71
72mod send_buffer;
73
74mod spaces;
75#[cfg(fuzzing)]
76pub use spaces::Retransmits;
77#[cfg(not(fuzzing))]
78use spaces::Retransmits;
79use spaces::{PacketNumberFilter, PacketSpace, SendableFrames, SentPacket, ThinRetransmits};
80
81mod stats;
82pub use stats::{ConnectionStats, FrameStats, PathStats, UdpStats};
83
84mod streams;
85#[cfg(fuzzing)]
86pub use streams::StreamsState;
87#[cfg(not(fuzzing))]
88use streams::StreamsState;
89pub use streams::{
90    Chunks, ClosedStream, FinishError, ReadError, ReadableError, RecvStream, SendStream,
91    ShouldTransmit, StreamEvent, Streams, WriteError, Written,
92};
93
94mod timer;
95use crate::congestion::Controller;
96use timer::{Timer, TimerTable};
97
98/// Protocol state and logic for a single QUIC connection
99///
100/// Objects of this type receive [`ConnectionEvent`]s and emit [`EndpointEvent`]s and application
101/// [`Event`]s to make progress. To handle timeouts, a `Connection` returns timer updates and
102/// expects timeouts through various methods. A number of simple getter methods are exposed
103/// to allow callers to inspect some of the connection state.
104///
105/// `Connection` has roughly 4 types of methods:
106///
107/// - A. Simple getters, taking `&self`
108/// - B. Handlers for incoming events from the network or system, named `handle_*`.
109/// - C. State machine mutators, for incoming commands from the application. For convenience we
110///   refer to this as "performing I/O" below, however as per the design of this library none of the
111///   functions actually perform system-level I/O. For example, [`read`](RecvStream::read) and
112///   [`write`](SendStream::write), but also things like [`reset`](SendStream::reset).
113/// - D. Polling functions for outgoing events or actions for the caller to
114///   take, named `poll_*`.
115///
116/// The simplest way to use this API correctly is to call (B) and (C) whenever
117/// appropriate, then after each of those calls, as soon as feasible call all
118/// polling methods (D) and deal with their outputs appropriately, e.g. by
119/// passing it to the application or by making a system-level I/O call. You
120/// should call the polling functions in this order:
121///
122/// 1. [`poll_transmit`](Self::poll_transmit)
123/// 2. [`poll_timeout`](Self::poll_timeout)
124/// 3. [`poll_endpoint_events`](Self::poll_endpoint_events)
125/// 4. [`poll`](Self::poll)
126///
127/// Currently the only actual dependency is from (2) to (1), however additional
128/// dependencies may be added in future, so the above order is recommended.
129///
130/// (A) may be called whenever desired.
131///
132/// Care should be made to ensure that the input events represent monotonically
133/// increasing time. Specifically, calling [`handle_timeout`](Self::handle_timeout)
134/// with events of the same [`Instant`] may be interleaved in any order with a
135/// call to [`handle_event`](Self::handle_event) at that same instant; however
136/// events or timeouts with different instants must not be interleaved.
137pub struct Connection {
138    endpoint_config: Arc<EndpointConfig>,
139    config: Arc<TransportConfig>,
140    rng: StdRng,
141    crypto: Box<dyn crypto::Session>,
142    /// The CID we initially chose, for use during the handshake
143    handshake_cid: ConnectionId,
144    /// The CID the peer initially chose, for use during the handshake
145    rem_handshake_cid: ConnectionId,
146    /// The "real" local IP address which was was used to receive the initial packet.
147    /// This is only populated for the server case, and if known
148    local_ip: Option<IpAddr>,
149    path: PathData,
150    /// Whether MTU detection is supported in this environment
151    allow_mtud: bool,
152    prev_path: Option<(ConnectionId, PathData)>,
153    state: State,
154    side: ConnectionSide,
155    /// Whether or not 0-RTT was enabled during the handshake. Does not imply acceptance.
156    zero_rtt_enabled: bool,
157    /// Set if 0-RTT is supported, then cleared when no longer needed.
158    zero_rtt_crypto: Option<ZeroRttCrypto>,
159    key_phase: bool,
160    /// How many packets are in the current key phase. Used only for `Data` space.
161    key_phase_size: u64,
162    /// Transport parameters set by the peer
163    peer_params: TransportParameters,
164    /// Source ConnectionId of the first packet received from the peer
165    orig_rem_cid: ConnectionId,
166    /// Destination ConnectionId sent by the client on the first Initial
167    initial_dst_cid: ConnectionId,
168    /// The value that the server included in the Source Connection ID field of a Retry packet, if
169    /// one was received
170    retry_src_cid: Option<ConnectionId>,
171    /// Total number of outgoing packets that have been deemed lost
172    lost_packets: u64,
173    events: VecDeque<Event>,
174    endpoint_events: VecDeque<EndpointEventInner>,
175    /// Whether the spin bit is in use for this connection
176    spin_enabled: bool,
177    /// Outgoing spin bit state
178    spin: bool,
179    /// Packet number spaces: initial, handshake, 1-RTT
180    spaces: [PacketSpace; 3],
181    /// Highest usable packet number space
182    highest_space: SpaceId,
183    /// 1-RTT keys used prior to a key update
184    prev_crypto: Option<PrevCrypto>,
185    /// 1-RTT keys to be used for the next key update
186    ///
187    /// These are generated in advance to prevent timing attacks and/or DoS by third-party attackers
188    /// spoofing key updates.
189    next_crypto: Option<KeyPair<Box<dyn PacketKey>>>,
190    accepted_0rtt: bool,
191    /// Whether the idle timer should be reset the next time an ack-eliciting packet is transmitted.
192    permit_idle_reset: bool,
193    /// Negotiated idle timeout
194    idle_timeout: Option<Duration>,
195    timers: TimerTable,
196    /// Number of packets received which could not be authenticated
197    authentication_failures: u64,
198    /// Why the connection was lost, if it has been
199    error: Option<ConnectionError>,
200    /// Identifies Data-space packet numbers to skip. Not used in earlier spaces.
201    packet_number_filter: PacketNumberFilter,
202
203    //
204    // Queued non-retransmittable 1-RTT data
205    //
206    /// Responses to PATH_CHALLENGE frames
207    path_responses: PathResponses,
208    /// Challenges for NAT traversal candidate validation
209    nat_traversal_challenges: NatTraversalChallenges,
210    close: bool,
211
212    //
213    // ACK frequency
214    //
215    ack_frequency: AckFrequencyState,
216
217    //
218    // Loss Detection
219    //
220    /// The number of times a PTO has been sent without receiving an ack.
221    pto_count: u32,
222
223    //
224    // Congestion Control
225    //
226    /// Whether the most recently received packet had an ECN codepoint set
227    receiving_ecn: bool,
228    /// Number of packets authenticated
229    total_authed_packets: u64,
230    /// Whether the last `poll_transmit` call yielded no data because there was
231    /// no outgoing application data.
232    app_limited: bool,
233
234    streams: StreamsState,
235    /// Surplus remote CIDs for future use on new paths
236    rem_cids: CidQueue,
237    // Attributes of CIDs generated by local peer
238    local_cid_state: CidState,
239    /// State of the unreliable datagram extension
240    datagrams: DatagramState,
241    /// Connection level statistics
242    stats: ConnectionStats,
243    /// QUIC version used for the connection.
244    version: u32,
245
246    /// NAT traversal state for establishing direct P2P connections
247    nat_traversal: Option<NatTraversalState>,
248
249    /// Address discovery state for tracking observed addresses
250    address_discovery_state: Option<AddressDiscoveryState>,
251    
252    /// Trace context for this connection
253    #[cfg(feature = "trace")]
254    trace_context: crate::tracing::TraceContext,
255    
256    /// Event log for tracing
257    #[cfg(feature = "trace")]
258    event_log: Arc<crate::tracing::EventLog>,
259
260    /// Qlog writer
261    #[cfg(feature = "__qlog")]
262    qlog_streamer: Option<Box<dyn std::io::Write + Send + Sync>>,
263}
264
265impl Connection {
266    pub(crate) fn new(
267        endpoint_config: Arc<EndpointConfig>,
268        config: Arc<TransportConfig>,
269        init_cid: ConnectionId,
270        loc_cid: ConnectionId,
271        rem_cid: ConnectionId,
272        remote: SocketAddr,
273        local_ip: Option<IpAddr>,
274        crypto: Box<dyn crypto::Session>,
275        cid_gen: &dyn ConnectionIdGenerator,
276        now: Instant,
277        version: u32,
278        allow_mtud: bool,
279        rng_seed: [u8; 32],
280        side_args: SideArgs,
281    ) -> Self {
282        let pref_addr_cid = side_args.pref_addr_cid();
283        let path_validated = side_args.path_validated();
284        let connection_side = ConnectionSide::from(side_args);
285        let side = connection_side.side();
286        let initial_space = PacketSpace {
287            crypto: Some(crypto.initial_keys(&init_cid, side)),
288            ..PacketSpace::new(now)
289        };
290        let state = State::Handshake(state::Handshake {
291            rem_cid_set: side.is_server(),
292            expected_token: Bytes::new(),
293            client_hello: None,
294        });
295        let mut rng = StdRng::from_seed(rng_seed);
296        let mut this = Self {
297            endpoint_config,
298            crypto,
299            handshake_cid: loc_cid,
300            rem_handshake_cid: rem_cid,
301            local_cid_state: CidState::new(
302                cid_gen.cid_len(),
303                cid_gen.cid_lifetime(),
304                now,
305                if pref_addr_cid.is_some() { 2 } else { 1 },
306            ),
307            path: PathData::new(remote, allow_mtud, None, now, &config),
308            allow_mtud,
309            local_ip,
310            prev_path: None,
311            state,
312            side: connection_side,
313            zero_rtt_enabled: false,
314            zero_rtt_crypto: None,
315            key_phase: false,
316            // A small initial key phase size ensures peers that don't handle key updates correctly
317            // fail sooner rather than later. It's okay for both peers to do this, as the first one
318            // to perform an update will reset the other's key phase size in `update_keys`, and a
319            // simultaneous key update by both is just like a regular key update with a really fast
320            // response. Inspired by quic-go's similar behavior of performing the first key update
321            // at the 100th short-header packet.
322            key_phase_size: rng.gen_range(10..1000),
323            peer_params: TransportParameters::default(),
324            orig_rem_cid: rem_cid,
325            initial_dst_cid: init_cid,
326            retry_src_cid: None,
327            lost_packets: 0,
328            events: VecDeque::new(),
329            endpoint_events: VecDeque::new(),
330            spin_enabled: config.allow_spin && rng.gen_ratio(7, 8),
331            spin: false,
332            spaces: [initial_space, PacketSpace::new(now), PacketSpace::new(now)],
333            highest_space: SpaceId::Initial,
334            prev_crypto: None,
335            next_crypto: None,
336            accepted_0rtt: false,
337            permit_idle_reset: true,
338            idle_timeout: match config.max_idle_timeout {
339                None | Some(VarInt(0)) => None,
340                Some(dur) => Some(Duration::from_millis(dur.0)),
341            },
342            timers: TimerTable::default(),
343            authentication_failures: 0,
344            error: None,
345            #[cfg(test)]
346            packet_number_filter: match config.deterministic_packet_numbers {
347                false => PacketNumberFilter::new(&mut rng),
348                true => PacketNumberFilter::disabled(),
349            },
350            #[cfg(not(test))]
351            packet_number_filter: PacketNumberFilter::new(&mut rng),
352
353            path_responses: PathResponses::default(),
354            nat_traversal_challenges: NatTraversalChallenges::default(),
355            close: false,
356
357            ack_frequency: AckFrequencyState::new(get_max_ack_delay(
358                &TransportParameters::default(),
359            )),
360
361            pto_count: 0,
362
363            app_limited: false,
364            receiving_ecn: false,
365            total_authed_packets: 0,
366
367            streams: StreamsState::new(
368                side,
369                config.max_concurrent_uni_streams,
370                config.max_concurrent_bidi_streams,
371                config.send_window,
372                config.receive_window,
373                config.stream_receive_window,
374            ),
375            datagrams: DatagramState::default(),
376            config,
377            rem_cids: CidQueue::new(rem_cid),
378            rng,
379            stats: ConnectionStats::default(),
380            version,
381            nat_traversal: None, // Will be initialized when NAT traversal is negotiated
382            address_discovery_state: {
383                // Initialize with default config for now
384                // Will be updated when transport parameters are negotiated
385                Some(AddressDiscoveryState::new(
386                    &crate::transport_parameters::AddressDiscoveryConfig::default(),
387                    now
388                ))
389            },
390            
391            #[cfg(feature = "trace")]
392            trace_context: crate::tracing::TraceContext::new(crate::tracing::TraceId::new()),
393            
394            #[cfg(feature = "trace")]
395            event_log: crate::tracing::global_log(),
396
397            #[cfg(feature = "__qlog")]
398            qlog_streamer: None,
399        };
400        
401        // Trace connection creation
402        #[cfg(feature = "trace")]
403        {
404            use crate::tracing::*;
405            use crate::trace_event;
406            let _peer_id = {
407                let mut id = [0u8; 32];
408                let addr_bytes = match remote {
409                    SocketAddr::V4(addr) => addr.ip().octets().to_vec(),
410                    SocketAddr::V6(addr) => addr.ip().octets().to_vec(),
411                };
412                id[..addr_bytes.len().min(32)].copy_from_slice(&addr_bytes[..addr_bytes.len().min(32)]);
413                id
414            };
415            
416            let (addr_bytes, addr_type) = socket_addr_to_bytes(remote);
417            trace_event!(&this.event_log, Event {
418                timestamp: timestamp_now(),
419                trace_id: this.trace_context.trace_id(),
420                sequence: 0,
421                _padding: 0,
422                node_id: [0u8; 32], // Will be set by endpoint
423                event_data: EventData::ConnInit {
424                    endpoint_bytes: addr_bytes,
425                    addr_type,
426                    _padding: [0u8; 45],
427                },
428            });
429        }
430        
431        if path_validated {
432            this.on_path_validated();
433        }
434        if side.is_client() {
435            // Kick off the connection
436            this.write_crypto();
437            this.init_0rtt();
438        }
439        this
440    }
441
442    /// Set up qlog for this connection
443    #[cfg(feature = "__qlog")]
444    pub fn set_qlog(
445        &mut self,
446        writer: Box<dyn std::io::Write + Send + Sync>,
447        _title: Option<String>,
448        _description: Option<String>,
449        _now: Instant,
450    ) {
451        self.qlog_streamer = Some(writer);
452    }
453
454    /// Emit qlog recovery metrics
455    #[cfg(feature = "__qlog")]
456    fn emit_qlog_recovery_metrics(&mut self, _now: Instant) {
457        // TODO: Implement actual qlog recovery metrics emission
458        // For now, this is a stub to allow compilation
459    }
460
461    /// Returns the next time at which `handle_timeout` should be called
462    ///
463    /// The value returned may change after:
464    /// - the application performed some I/O on the connection
465    /// - a call was made to `handle_event`
466    /// - a call to `poll_transmit` returned `Some`
467    /// - a call was made to `handle_timeout`
468    #[must_use]
469    pub fn poll_timeout(&mut self) -> Option<Instant> {
470        let mut next_timeout = self.timers.next_timeout();
471
472        // Check NAT traversal timeouts
473        if let Some(nat_state) = &self.nat_traversal {
474            if let Some(nat_timeout) = nat_state.get_next_timeout(Instant::now()) {
475                // Schedule NAT traversal timer
476                self.timers.set(Timer::NatTraversal, nat_timeout);
477                next_timeout = Some(next_timeout.map_or(nat_timeout, |t| t.min(nat_timeout)));
478            }
479        }
480
481        next_timeout
482    }
483
484    /// Returns application-facing events
485    ///
486    /// Connections should be polled for events after:
487    /// - a call was made to `handle_event`
488    /// - a call was made to `handle_timeout`
489    #[must_use]
490    pub fn poll(&mut self) -> Option<Event> {
491        if let Some(x) = self.events.pop_front() {
492            return Some(x);
493        }
494
495        if let Some(event) = self.streams.poll() {
496            return Some(Event::Stream(event));
497        }
498
499        if let Some(err) = self.error.take() {
500            return Some(Event::ConnectionLost { reason: err });
501        }
502
503        None
504    }
505
506    /// Return endpoint-facing events
507    #[must_use]
508    pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent> {
509        self.endpoint_events.pop_front().map(EndpointEvent)
510    }
511
512    /// Provide control over streams
513    #[must_use]
514    pub fn streams(&mut self) -> Streams<'_> {
515        Streams {
516            state: &mut self.streams,
517            conn_state: &self.state,
518        }
519    }
520    
521    /// Get the trace context for logging
522    #[cfg(feature = "trace")]
523    pub(crate) fn trace_context(&self) -> &crate::tracing::TraceContext {
524        &self.trace_context
525    }
526    
527    /// Get the event log for logging
528    #[cfg(feature = "trace")]
529    pub(crate) fn event_log(&self) -> &Arc<crate::tracing::EventLog> {
530        &self.event_log
531    }
532
533    /// Provide control over streams
534    #[must_use]
535    pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_> {
536        assert!(id.dir() == Dir::Bi || id.initiator() != self.side.side());
537        RecvStream {
538            id,
539            state: &mut self.streams,
540            pending: &mut self.spaces[SpaceId::Data].pending,
541        }
542    }
543
544    /// Provide control over streams
545    #[must_use]
546    pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_> {
547        assert!(id.dir() == Dir::Bi || id.initiator() == self.side.side());
548        SendStream {
549            id,
550            state: &mut self.streams,
551            pending: &mut self.spaces[SpaceId::Data].pending,
552            conn_state: &self.state,
553        }
554    }
555
556    /// Returns packets to transmit
557    ///
558    /// Connections should be polled for transmit after:
559    /// - the application performed some I/O on the connection
560    /// - a call was made to `handle_event`
561    /// - a call was made to `handle_timeout`
562    ///
563    /// `max_datagrams` specifies how many datagrams can be returned inside a
564    /// single Transmit using GSO. This must be at least 1.
565    #[must_use]
566    pub fn poll_transmit(
567        &mut self,
568        now: Instant,
569        max_datagrams: usize,
570        buf: &mut Vec<u8>,
571    ) -> Option<Transmit> {
572        assert!(max_datagrams != 0);
573        let max_datagrams = match self.config.enable_segmentation_offload {
574            false => 1,
575            true => max_datagrams,
576        };
577
578        let mut num_datagrams = 0;
579        // Position in `buf` of the first byte of the current UDP datagram. When coalescing QUIC
580        // packets, this can be earlier than the start of the current QUIC packet.
581        let mut datagram_start = 0;
582        let mut segment_size = usize::from(self.path.current_mtu());
583
584        // Check for NAT traversal coordination timeouts
585        if let Some(nat_traversal) = &mut self.nat_traversal {
586            if nat_traversal.check_coordination_timeout(now) {
587                trace!("NAT traversal coordination timed out, may retry");
588            }
589        }
590
591        // First priority: NAT traversal PATH_CHALLENGE packets (includes coordination)
592        if let Some(challenge) = self.send_nat_traversal_challenge(now, buf) {
593            return Some(challenge);
594        }
595
596        if let Some(challenge) = self.send_path_challenge(now, buf) {
597            return Some(challenge);
598        }
599
600        // If we need to send a probe, make sure we have something to send.
601        for space in SpaceId::iter() {
602            let request_immediate_ack =
603                space == SpaceId::Data && self.peer_supports_ack_frequency();
604            self.spaces[space].maybe_queue_probe(request_immediate_ack, &self.streams);
605        }
606
607        // Check whether we need to send a close message
608        let close = match self.state {
609            State::Drained => {
610                self.app_limited = true;
611                return None;
612            }
613            State::Draining | State::Closed(_) => {
614                // self.close is only reset once the associated packet had been
615                // encoded successfully
616                if !self.close {
617                    self.app_limited = true;
618                    return None;
619                }
620                true
621            }
622            _ => false,
623        };
624
625        // Check whether we need to send an ACK_FREQUENCY frame
626        if let Some(config) = &self.config.ack_frequency_config {
627            self.spaces[SpaceId::Data].pending.ack_frequency = self
628                .ack_frequency
629                .should_send_ack_frequency(self.path.rtt.get(), config, &self.peer_params)
630                && self.highest_space == SpaceId::Data
631                && self.peer_supports_ack_frequency();
632        }
633
634        // Reserving capacity can provide more capacity than we asked for. However, we are not
635        // allowed to write more than `segment_size`. Therefore the maximum capacity is tracked
636        // separately.
637        let mut buf_capacity = 0;
638
639        let mut coalesce = true;
640        let mut builder_storage: Option<PacketBuilder> = None;
641        let mut sent_frames = None;
642        let mut pad_datagram = false;
643        let mut pad_datagram_to_mtu = false;
644        let mut congestion_blocked = false;
645
646        // Iterate over all spaces and find data to send
647        let mut space_idx = 0;
648        let spaces = [SpaceId::Initial, SpaceId::Handshake, SpaceId::Data];
649        // This loop will potentially spend multiple iterations in the same `SpaceId`,
650        // so we cannot trivially rewrite it to take advantage of `SpaceId::iter()`.
651        while space_idx < spaces.len() {
652            let space_id = spaces[space_idx];
653            // Number of bytes available for frames if this is a 1-RTT packet. We're guaranteed to
654            // be able to send an individual frame at least this large in the next 1-RTT
655            // packet. This could be generalized to support every space, but it's only needed to
656            // handle large fixed-size frames, which only exist in 1-RTT (application datagrams). We
657            // don't account for coalesced packets potentially occupying space because frames can
658            // always spill into the next datagram.
659            let pn = self.packet_number_filter.peek(&self.spaces[SpaceId::Data]);
660            let frame_space_1rtt =
661                segment_size.saturating_sub(self.predict_1rtt_overhead(Some(pn)));
662
663            // Is there data or a close message to send in this space?
664            let can_send = self.space_can_send(space_id, frame_space_1rtt);
665            if can_send.is_empty() && (!close || self.spaces[space_id].crypto.is_none()) {
666                space_idx += 1;
667                continue;
668            }
669
670            let mut ack_eliciting = !self.spaces[space_id].pending.is_empty(&self.streams)
671                || self.spaces[space_id].ping_pending
672                || self.spaces[space_id].immediate_ack_pending;
673            if space_id == SpaceId::Data {
674                ack_eliciting |= self.can_send_1rtt(frame_space_1rtt);
675            }
676
677            pad_datagram_to_mtu |= space_id == SpaceId::Data && self.config.pad_to_mtu;
678
679            // Can we append more data into the current buffer?
680            // It is not safe to assume that `buf.len()` is the end of the data,
681            // since the last packet might not have been finished.
682            let buf_end = if let Some(builder) = &builder_storage {
683                buf.len().max(builder.min_size) + builder.tag_len
684            } else {
685                buf.len()
686            };
687
688            let tag_len = if let Some(ref crypto) = self.spaces[space_id].crypto {
689                crypto.packet.local.tag_len()
690            } else if space_id == SpaceId::Data {
691                self.zero_rtt_crypto.as_ref().expect(
692                    "sending packets in the application data space requires known 0-RTT or 1-RTT keys",
693                ).packet.tag_len()
694            } else {
695                unreachable!("tried to send {:?} packet without keys", space_id)
696            };
697            if !coalesce || buf_capacity - buf_end < MIN_PACKET_SPACE + tag_len {
698                // We need to send 1 more datagram and extend the buffer for that.
699
700                // Is 1 more datagram allowed?
701                if num_datagrams >= max_datagrams {
702                    // No more datagrams allowed
703                    break;
704                }
705
706                // Anti-amplification is only based on `total_sent`, which gets
707                // updated at the end of this method. Therefore we pass the amount
708                // of bytes for datagrams that are already created, as well as 1 byte
709                // for starting another datagram. If there is any anti-amplification
710                // budget left, we always allow a full MTU to be sent
711                // (see https://github.com/quinn-rs/quinn/issues/1082)
712                if self
713                    .path
714                    .anti_amplification_blocked(segment_size as u64 * (num_datagrams as u64) + 1)
715                {
716                    trace!("blocked by anti-amplification");
717                    break;
718                }
719
720                // Congestion control and pacing checks
721                // Tail loss probes must not be blocked by congestion, or a deadlock could arise
722                if ack_eliciting && self.spaces[space_id].loss_probes == 0 {
723                    // Assume the current packet will get padded to fill the segment
724                    let untracked_bytes = if let Some(builder) = &builder_storage {
725                        buf_capacity - builder.partial_encode.start
726                    } else {
727                        0
728                    } as u64;
729                    debug_assert!(untracked_bytes <= segment_size as u64);
730
731                    let bytes_to_send = segment_size as u64 + untracked_bytes;
732                    if self.path.in_flight.bytes + bytes_to_send >= self.path.congestion.window() {
733                        space_idx += 1;
734                        congestion_blocked = true;
735                        // We continue instead of breaking here in order to avoid
736                        // blocking loss probes queued for higher spaces.
737                        trace!("blocked by congestion control");
738                        continue;
739                    }
740
741                    // Check whether the next datagram is blocked by pacing
742                    let smoothed_rtt = self.path.rtt.get();
743                    if let Some(delay) = self.path.pacing.delay(
744                        smoothed_rtt,
745                        bytes_to_send,
746                        self.path.current_mtu(),
747                        self.path.congestion.window(),
748                        now,
749                    ) {
750                        self.timers.set(Timer::Pacing, delay);
751                        congestion_blocked = true;
752                        // Loss probes should be subject to pacing, even though
753                        // they are not congestion controlled.
754                        trace!("blocked by pacing");
755                        break;
756                    }
757                }
758
759                // Finish current packet
760                if let Some(mut builder) = builder_storage.take() {
761                    if pad_datagram {
762                        builder.pad_to(MIN_INITIAL_SIZE);
763                    }
764
765                    if num_datagrams > 1 || pad_datagram_to_mtu {
766                        // If too many padding bytes would be required to continue the GSO batch
767                        // after this packet, end the GSO batch here. Ensures that fixed-size frames
768                        // with heterogeneous sizes (e.g. application datagrams) won't inadvertently
769                        // waste large amounts of bandwidth. The exact threshold is a bit arbitrary
770                        // and might benefit from further tuning, though there's no universally
771                        // optimal value.
772                        //
773                        // Additionally, if this datagram is a loss probe and `segment_size` is
774                        // larger than `INITIAL_MTU`, then padding it to `segment_size` to continue
775                        // the GSO batch would risk failure to recover from a reduction in path
776                        // MTU. Loss probes are the only packets for which we might grow
777                        // `buf_capacity` by less than `segment_size`.
778                        const MAX_PADDING: usize = 16;
779                        let packet_len_unpadded = cmp::max(builder.min_size, buf.len())
780                            - datagram_start
781                            + builder.tag_len;
782                        if (packet_len_unpadded + MAX_PADDING < segment_size
783                            && !pad_datagram_to_mtu)
784                            || datagram_start + segment_size > buf_capacity
785                        {
786                            trace!(
787                                "GSO truncated by demand for {} padding bytes or loss probe",
788                                segment_size - packet_len_unpadded
789                            );
790                            builder_storage = Some(builder);
791                            break;
792                        }
793
794                        // Pad the current datagram to GSO segment size so it can be included in the
795                        // GSO batch.
796                        builder.pad_to(segment_size as u16);
797                    }
798
799                    builder.finish_and_track(now, self, sent_frames.take(), buf);
800
801                    if num_datagrams == 1 {
802                        // Set the segment size for this GSO batch to the size of the first UDP
803                        // datagram in the batch. Larger data that cannot be fragmented
804                        // (e.g. application datagrams) will be included in a future batch. When
805                        // sending large enough volumes of data for GSO to be useful, we expect
806                        // packet sizes to usually be consistent, e.g. populated by max-size STREAM
807                        // frames or uniformly sized datagrams.
808                        segment_size = buf.len();
809                        // Clip the unused capacity out of the buffer so future packets don't
810                        // overrun
811                        buf_capacity = buf.len();
812
813                        // Check whether the data we planned to send will fit in the reduced segment
814                        // size. If not, bail out and leave it for the next GSO batch so we don't
815                        // end up trying to send an empty packet. We can't easily compute the right
816                        // segment size before the original call to `space_can_send`, because at
817                        // that time we haven't determined whether we're going to coalesce with the
818                        // first datagram or potentially pad it to `MIN_INITIAL_SIZE`.
819                        if space_id == SpaceId::Data {
820                            let frame_space_1rtt =
821                                segment_size.saturating_sub(self.predict_1rtt_overhead(Some(pn)));
822                            if self.space_can_send(space_id, frame_space_1rtt).is_empty() {
823                                break;
824                            }
825                        }
826                    }
827                }
828
829                // Allocate space for another datagram
830                let next_datagram_size_limit = match self.spaces[space_id].loss_probes {
831                    0 => segment_size,
832                    _ => {
833                        self.spaces[space_id].loss_probes -= 1;
834                        // Clamp the datagram to at most the minimum MTU to ensure that loss probes
835                        // can get through and enable recovery even if the path MTU has shrank
836                        // unexpectedly.
837                        std::cmp::min(segment_size, usize::from(INITIAL_MTU))
838                    }
839                };
840                buf_capacity += next_datagram_size_limit;
841                if buf.capacity() < buf_capacity {
842                    // We reserve the maximum space for sending `max_datagrams` upfront
843                    // to avoid any reallocations if more datagrams have to be appended later on.
844                    // Benchmarks have shown shown a 5-10% throughput improvement
845                    // compared to continuously resizing the datagram buffer.
846                    // While this will lead to over-allocation for small transmits
847                    // (e.g. purely containing ACKs), modern memory allocators
848                    // (e.g. mimalloc and jemalloc) will pool certain allocation sizes
849                    // and therefore this is still rather efficient.
850                    buf.reserve(max_datagrams * segment_size);
851                }
852                num_datagrams += 1;
853                coalesce = true;
854                pad_datagram = false;
855                datagram_start = buf.len();
856
857                debug_assert_eq!(
858                    datagram_start % segment_size,
859                    0,
860                    "datagrams in a GSO batch must be aligned to the segment size"
861                );
862            } else {
863                // We can append/coalesce the next packet into the current
864                // datagram.
865                // Finish current packet without adding extra padding
866                if let Some(builder) = builder_storage.take() {
867                    builder.finish_and_track(now, self, sent_frames.take(), buf);
868                }
869            }
870
871            debug_assert!(buf_capacity - buf.len() >= MIN_PACKET_SPACE);
872
873            //
874            // From here on, we've determined that a packet will definitely be sent.
875            //
876
877            if self.spaces[SpaceId::Initial].crypto.is_some()
878                && space_id == SpaceId::Handshake
879                && self.side.is_client()
880            {
881                // A client stops both sending and processing Initial packets when it
882                // sends its first Handshake packet.
883                self.discard_space(now, SpaceId::Initial);
884            }
885            if let Some(ref mut prev) = self.prev_crypto {
886                prev.update_unacked = false;
887            }
888
889            debug_assert!(
890                builder_storage.is_none() && sent_frames.is_none(),
891                "Previous packet must have been finished"
892            );
893
894            let builder = builder_storage.insert(PacketBuilder::new(
895                now,
896                space_id,
897                self.rem_cids.active(),
898                buf,
899                buf_capacity,
900                datagram_start,
901                ack_eliciting,
902                self,
903            )?);
904            coalesce = coalesce && !builder.short_header;
905
906            // https://tools.ietf.org/html/draft-ietf-quic-transport-34#section-14.1
907            pad_datagram |=
908                space_id == SpaceId::Initial && (self.side.is_client() || ack_eliciting);
909
910            if close {
911                trace!("sending CONNECTION_CLOSE");
912                // Encode ACKs before the ConnectionClose message, to give the receiver
913                // a better approximate on what data has been processed. This is
914                // especially important with ack delay, since the peer might not
915                // have gotten any other ACK for the data earlier on.
916                if !self.spaces[space_id].pending_acks.ranges().is_empty() {
917                    Self::populate_acks(
918                        now,
919                        self.receiving_ecn,
920                        &mut SentFrames::default(),
921                        &mut self.spaces[space_id],
922                        buf,
923                        &mut self.stats,
924                    );
925                }
926
927                // Since there only 64 ACK frames there will always be enough space
928                // to encode the ConnectionClose frame too. However we still have the
929                // check here to prevent crashes if something changes.
930                debug_assert!(
931                    buf.len() + frame::ConnectionClose::SIZE_BOUND < builder.max_size,
932                    "ACKs should leave space for ConnectionClose"
933                );
934                if buf.len() + frame::ConnectionClose::SIZE_BOUND < builder.max_size {
935                    let max_frame_size = builder.max_size - buf.len();
936                    match self.state {
937                        State::Closed(state::Closed { ref reason }) => {
938                            if space_id == SpaceId::Data || reason.is_transport_layer() {
939                                reason.encode(buf, max_frame_size)
940                            } else {
941                                frame::ConnectionClose {
942                                    error_code: TransportErrorCode::APPLICATION_ERROR,
943                                    frame_type: None,
944                                    reason: Bytes::new(),
945                                }
946                                .encode(buf, max_frame_size)
947                            }
948                        }
949                        State::Draining => frame::ConnectionClose {
950                            error_code: TransportErrorCode::NO_ERROR,
951                            frame_type: None,
952                            reason: Bytes::new(),
953                        }
954                        .encode(buf, max_frame_size),
955                        _ => unreachable!(
956                            "tried to make a close packet when the connection wasn't closed"
957                        ),
958                    }
959                }
960                if space_id == self.highest_space {
961                    // Don't send another close packet
962                    self.close = false;
963                    // `CONNECTION_CLOSE` is the final packet
964                    break;
965                } else {
966                    // Send a close frame in every possible space for robustness, per RFC9000
967                    // "Immediate Close during the Handshake". Don't bother trying to send anything
968                    // else.
969                    space_idx += 1;
970                    continue;
971                }
972            }
973
974            // Send an off-path PATH_RESPONSE. Prioritized over on-path data to ensure that path
975            // validation can occur while the link is saturated.
976            if space_id == SpaceId::Data && num_datagrams == 1 {
977                if let Some((token, remote)) = self.path_responses.pop_off_path(self.path.remote) {
978                    // `unwrap` guaranteed to succeed because `builder_storage` was populated just
979                    // above.
980                    let mut builder = builder_storage.take().unwrap();
981                    trace!("PATH_RESPONSE {:08x} (off-path)", token);
982                    buf.write(frame::FrameType::PATH_RESPONSE);
983                    buf.write(token);
984                    self.stats.frame_tx.path_response += 1;
985                    builder.pad_to(MIN_INITIAL_SIZE);
986                    builder.finish_and_track(
987                        now,
988                        self,
989                        Some(SentFrames {
990                            non_retransmits: true,
991                            ..SentFrames::default()
992                        }),
993                        buf,
994                    );
995                    self.stats.udp_tx.on_sent(1, buf.len());
996                    
997                    // Trace packet sent
998                    #[cfg(feature = "trace")]
999                    {
1000                        use crate::tracing::*;
1001                        use crate::trace_packet_sent;
1002                        trace_packet_sent!(
1003                            &self.event_log,
1004                            self.trace_context.trace_id(),
1005                            buf.len() as u32,
1006                            0 // Close packet doesn't have a packet number
1007                        );
1008                    }
1009                    
1010                    return Some(Transmit {
1011                        destination: remote,
1012                        size: buf.len(),
1013                        ecn: None,
1014                        segment_size: None,
1015                        src_ip: self.local_ip,
1016                    });
1017                }
1018            }
1019
1020            // Check for address observations to send
1021            if space_id == SpaceId::Data && self.address_discovery_state.is_some() {
1022                let peer_supports = self.peer_params.address_discovery.is_some() && 
1023                                   self.peer_params.address_discovery.as_ref().unwrap().enabled;
1024                
1025                if let Some(state) = &mut self.address_discovery_state {
1026                    let frames = state.check_for_address_observations(0, peer_supports, now);
1027                    self.spaces[space_id].pending.observed_addresses.extend(frames);
1028                }
1029            }
1030
1031            let sent =
1032                self.populate_packet(now, space_id, buf, builder.max_size, builder.exact_number);
1033
1034            // ACK-only packets should only be sent when explicitly allowed. If we write them due to
1035            // any other reason, there is a bug which leads to one component announcing write
1036            // readiness while not writing any data. This degrades performance. The condition is
1037            // only checked if the full MTU is available and when potentially large fixed-size
1038            // frames aren't queued, so that lack of space in the datagram isn't the reason for just
1039            // writing ACKs.
1040            debug_assert!(
1041                !(sent.is_ack_only(&self.streams)
1042                    && !can_send.acks
1043                    && can_send.other
1044                    && (buf_capacity - builder.datagram_start) == self.path.current_mtu() as usize
1045                    && self.datagrams.outgoing.is_empty()),
1046                "SendableFrames was {can_send:?}, but only ACKs have been written"
1047            );
1048            pad_datagram |= sent.requires_padding;
1049
1050            if sent.largest_acked.is_some() {
1051                self.spaces[space_id].pending_acks.acks_sent();
1052                self.timers.stop(Timer::MaxAckDelay);
1053            }
1054
1055            // Keep information about the packet around until it gets finalized
1056            sent_frames = Some(sent);
1057
1058            // Don't increment space_idx.
1059            // We stay in the current space and check if there is more data to send.
1060        }
1061
1062        // Finish the last packet
1063        if let Some(mut builder) = builder_storage {
1064            if pad_datagram {
1065                builder.pad_to(MIN_INITIAL_SIZE);
1066            }
1067
1068            // If this datagram is a loss probe and `segment_size` is larger than `INITIAL_MTU`,
1069            // then padding it to `segment_size` would risk failure to recover from a reduction in
1070            // path MTU.
1071            // Loss probes are the only packets for which we might grow `buf_capacity`
1072            // by less than `segment_size`.
1073            if pad_datagram_to_mtu && buf_capacity >= datagram_start + segment_size {
1074                builder.pad_to(segment_size as u16);
1075            }
1076
1077            let last_packet_number = builder.exact_number;
1078            builder.finish_and_track(now, self, sent_frames, buf);
1079            self.path
1080                .congestion
1081                .on_sent(now, buf.len() as u64, last_packet_number);
1082
1083            #[cfg(feature = "__qlog")]
1084            self.emit_qlog_recovery_metrics(now);
1085        }
1086
1087        self.app_limited = buf.is_empty() && !congestion_blocked;
1088
1089        // Send MTU probe if necessary
1090        if buf.is_empty() && self.state.is_established() {
1091            let space_id = SpaceId::Data;
1092            let probe_size = self
1093                .path
1094                .mtud
1095                .poll_transmit(now, self.packet_number_filter.peek(&self.spaces[space_id]))?;
1096
1097            let buf_capacity = probe_size as usize;
1098            buf.reserve(buf_capacity);
1099
1100            let mut builder = PacketBuilder::new(
1101                now,
1102                space_id,
1103                self.rem_cids.active(),
1104                buf,
1105                buf_capacity,
1106                0,
1107                true,
1108                self,
1109            )?;
1110
1111            // We implement MTU probes as ping packets padded up to the probe size
1112            buf.write(frame::FrameType::PING);
1113            self.stats.frame_tx.ping += 1;
1114
1115            // If supported by the peer, we want no delays to the probe's ACK
1116            if self.peer_supports_ack_frequency() {
1117                buf.write(frame::FrameType::IMMEDIATE_ACK);
1118                self.stats.frame_tx.immediate_ack += 1;
1119            }
1120
1121            builder.pad_to(probe_size);
1122            let sent_frames = SentFrames {
1123                non_retransmits: true,
1124                ..Default::default()
1125            };
1126            builder.finish_and_track(now, self, Some(sent_frames), buf);
1127
1128            self.stats.path.sent_plpmtud_probes += 1;
1129            num_datagrams = 1;
1130
1131            trace!(?probe_size, "writing MTUD probe");
1132        }
1133
1134        if buf.is_empty() {
1135            return None;
1136        }
1137
1138        trace!("sending {} bytes in {} datagrams", buf.len(), num_datagrams);
1139        self.path.total_sent = self.path.total_sent.saturating_add(buf.len() as u64);
1140
1141        self.stats.udp_tx.on_sent(num_datagrams as u64, buf.len());
1142        
1143        // Trace packets sent
1144        #[cfg(feature = "trace")]
1145        {
1146            use crate::tracing::*;
1147            use crate::trace_packet_sent;
1148            // Log packet transmission (use highest packet number in transmission)
1149            let packet_num = self.spaces[SpaceId::Data].next_packet_number.saturating_sub(1);
1150            trace_packet_sent!(
1151                &self.event_log,
1152                self.trace_context.trace_id(),
1153                buf.len() as u32,
1154                packet_num
1155            );
1156        }
1157
1158        Some(Transmit {
1159            destination: self.path.remote,
1160            size: buf.len(),
1161            ecn: if self.path.sending_ecn {
1162                Some(EcnCodepoint::Ect0)
1163            } else {
1164                None
1165            },
1166            segment_size: match num_datagrams {
1167                1 => None,
1168                _ => Some(segment_size),
1169            },
1170            src_ip: self.local_ip,
1171        })
1172    }
1173
1174    /// Send PUNCH_ME_NOW for coordination if necessary
1175    fn send_coordination_request(&mut self, now: Instant, buf: &mut Vec<u8>) -> Option<Transmit> {
1176        // Get coordination info without borrowing mutably
1177        let should_send = self.nat_traversal.as_ref()?.should_send_punch_request();
1178        if !should_send {
1179            return None;
1180        }
1181
1182        let (round, target_addrs, coordinator_addr) = {
1183            let nat_traversal = self.nat_traversal.as_ref()?;
1184            let coord = nat_traversal.coordination.as_ref()?;
1185            let addrs: Vec<_> = coord.punch_targets.iter().map(|t| t.remote_addr).collect();
1186            (coord.round, addrs, self.path.remote) // Placeholder - should be bootstrap node
1187        };
1188
1189        if target_addrs.is_empty() {
1190            return None;
1191        }
1192
1193        debug_assert_eq!(
1194            self.highest_space,
1195            SpaceId::Data,
1196            "PUNCH_ME_NOW queued without 1-RTT keys"
1197        );
1198
1199        buf.reserve(MIN_INITIAL_SIZE as usize);
1200        let buf_capacity = buf.capacity();
1201
1202        let mut builder = PacketBuilder::new(
1203            now,
1204            SpaceId::Data,
1205            self.rem_cids.active(),
1206            buf,
1207            buf_capacity,
1208            0,
1209            false,
1210            self,
1211        )?;
1212
1213        trace!(
1214            "sending PUNCH_ME_NOW round {} with {} targets",
1215            round,
1216            target_addrs.len()
1217        );
1218
1219        // Write PUNCH_ME_NOW frame
1220        buf.write(frame::FrameType::PUNCH_ME_NOW);
1221        buf.write(round);
1222        buf.write(target_addrs.len() as u8);
1223        for addr in target_addrs {
1224            match addr {
1225                SocketAddr::V4(v4) => {
1226                    buf.write(4u8); // IPv4
1227                    buf.write(u32::from(*v4.ip()));
1228                    buf.write(v4.port());
1229                }
1230                SocketAddr::V6(v6) => {
1231                    buf.write(6u8); // IPv6  
1232                    buf.write(*v6.ip());
1233                    buf.write(v6.port());
1234                }
1235            }
1236        }
1237
1238        self.stats.frame_tx.ping += 1; // Use ping counter for now
1239
1240        builder.pad_to(MIN_INITIAL_SIZE);
1241        builder.finish_and_track(now, self, None, buf);
1242
1243        // Mark request sent after packet is built
1244        if let Some(nat_traversal) = &mut self.nat_traversal {
1245            nat_traversal.mark_punch_request_sent();
1246        }
1247
1248        Some(Transmit {
1249            destination: coordinator_addr,
1250            size: buf.len(),
1251            ecn: if self.path.sending_ecn {
1252                Some(EcnCodepoint::Ect0)
1253            } else {
1254                None
1255            },
1256            segment_size: None,
1257            src_ip: self.local_ip,
1258        })
1259    }
1260
1261    /// Send coordinated PATH_CHALLENGE for hole punching
1262    fn send_coordinated_path_challenge(
1263        &mut self,
1264        now: Instant,
1265        buf: &mut Vec<u8>,
1266    ) -> Option<Transmit> {
1267        // Check if it's time to start synchronized hole punching
1268        if let Some(nat_traversal) = &mut self.nat_traversal {
1269            if nat_traversal.should_start_punching(now) {
1270                nat_traversal.start_punching_phase(now);
1271            }
1272        }
1273
1274        // Get punch targets if we're in punching phase
1275        let (target_addr, challenge) = {
1276            let nat_traversal = self.nat_traversal.as_ref()?;
1277            match nat_traversal.get_coordination_phase() {
1278                Some(CoordinationPhase::Punching) => {
1279                    let targets = nat_traversal.get_punch_targets_from_coordination()?;
1280                    if targets.is_empty() {
1281                        return None;
1282                    }
1283                    // Send PATH_CHALLENGE to the first target (could be round-robin in future)
1284                    let target = &targets[0];
1285                    (target.remote_addr, target.challenge)
1286                }
1287                _ => return None,
1288            }
1289        };
1290
1291        debug_assert_eq!(
1292            self.highest_space,
1293            SpaceId::Data,
1294            "PATH_CHALLENGE queued without 1-RTT keys"
1295        );
1296
1297        buf.reserve(MIN_INITIAL_SIZE as usize);
1298        let buf_capacity = buf.capacity();
1299
1300        let mut builder = PacketBuilder::new(
1301            now,
1302            SpaceId::Data,
1303            self.rem_cids.active(),
1304            buf,
1305            buf_capacity,
1306            0,
1307            false,
1308            self,
1309        )?;
1310
1311        trace!(
1312            "sending coordinated PATH_CHALLENGE {:08x} to {}",
1313            challenge, target_addr
1314        );
1315        buf.write(frame::FrameType::PATH_CHALLENGE);
1316        buf.write(challenge);
1317        self.stats.frame_tx.path_challenge += 1;
1318
1319        builder.pad_to(MIN_INITIAL_SIZE);
1320        builder.finish_and_track(now, self, None, buf);
1321
1322        // Mark coordination as validating after packet is built
1323        if let Some(nat_traversal) = &mut self.nat_traversal {
1324            nat_traversal.mark_coordination_validating();
1325        }
1326
1327        Some(Transmit {
1328            destination: target_addr,
1329            size: buf.len(),
1330            ecn: if self.path.sending_ecn {
1331                Some(EcnCodepoint::Ect0)
1332            } else {
1333                None
1334            },
1335            segment_size: None,
1336            src_ip: self.local_ip,
1337        })
1338    }
1339
1340    /// Send PATH_CHALLENGE for NAT traversal candidates if necessary
1341    fn send_nat_traversal_challenge(
1342        &mut self,
1343        now: Instant,
1344        buf: &mut Vec<u8>,
1345    ) -> Option<Transmit> {
1346        // Priority 1: Coordination protocol requests
1347        if let Some(request) = self.send_coordination_request(now, buf) {
1348            return Some(request);
1349        }
1350
1351        // Priority 2: Coordinated hole punching
1352        if let Some(punch) = self.send_coordinated_path_challenge(now, buf) {
1353            return Some(punch);
1354        }
1355
1356        // Priority 3: Regular candidate validation (fallback)
1357        let (remote_addr, remote_sequence) = {
1358            let nat_traversal = self.nat_traversal.as_ref()?;
1359            let candidates = nat_traversal.get_validation_candidates();
1360            if candidates.is_empty() {
1361                return None;
1362            }
1363            // Get the highest priority candidate
1364            let (sequence, candidate) = candidates[0];
1365            (candidate.address, sequence)
1366        };
1367
1368        let challenge = self.rng.gen::<u64>();
1369
1370        // Start validation for this candidate
1371        if let Err(e) =
1372            self.nat_traversal
1373                .as_mut()?
1374                .start_validation(remote_sequence, challenge, now)
1375        {
1376            warn!("Failed to start NAT traversal validation: {}", e);
1377            return None;
1378        }
1379
1380        debug_assert_eq!(
1381            self.highest_space,
1382            SpaceId::Data,
1383            "PATH_CHALLENGE queued without 1-RTT keys"
1384        );
1385
1386        buf.reserve(MIN_INITIAL_SIZE as usize);
1387        let buf_capacity = buf.capacity();
1388
1389        // Use current connection ID for NAT traversal PATH_CHALLENGE
1390        let mut builder = PacketBuilder::new(
1391            now,
1392            SpaceId::Data,
1393            self.rem_cids.active(),
1394            buf,
1395            buf_capacity,
1396            0,
1397            false,
1398            self,
1399        )?;
1400
1401        trace!(
1402            "sending PATH_CHALLENGE {:08x} to NAT candidate {}",
1403            challenge, remote_addr
1404        );
1405        buf.write(frame::FrameType::PATH_CHALLENGE);
1406        buf.write(challenge);
1407        self.stats.frame_tx.path_challenge += 1;
1408
1409        // PATH_CHALLENGE frames must be padded to at least 1200 bytes
1410        builder.pad_to(MIN_INITIAL_SIZE);
1411
1412        builder.finish_and_track(now, self, None, buf);
1413
1414        Some(Transmit {
1415            destination: remote_addr,
1416            size: buf.len(),
1417            ecn: if self.path.sending_ecn {
1418                Some(EcnCodepoint::Ect0)
1419            } else {
1420                None
1421            },
1422            segment_size: None,
1423            src_ip: self.local_ip,
1424        })
1425    }
1426
1427    /// Send PATH_CHALLENGE for a previous path if necessary
1428    fn send_path_challenge(&mut self, now: Instant, buf: &mut Vec<u8>) -> Option<Transmit> {
1429        let (prev_cid, prev_path) = self.prev_path.as_mut()?;
1430        if !prev_path.challenge_pending {
1431            return None;
1432        }
1433        prev_path.challenge_pending = false;
1434        let token = prev_path
1435            .challenge
1436            .expect("previous path challenge pending without token");
1437        let destination = prev_path.remote;
1438        debug_assert_eq!(
1439            self.highest_space,
1440            SpaceId::Data,
1441            "PATH_CHALLENGE queued without 1-RTT keys"
1442        );
1443        buf.reserve(MIN_INITIAL_SIZE as usize);
1444
1445        let buf_capacity = buf.capacity();
1446
1447        // Use the previous CID to avoid linking the new path with the previous path. We
1448        // don't bother accounting for possible retirement of that prev_cid because this is
1449        // sent once, immediately after migration, when the CID is known to be valid. Even
1450        // if a post-migration packet caused the CID to be retired, it's fair to pretend
1451        // this is sent first.
1452        let mut builder = PacketBuilder::new(
1453            now,
1454            SpaceId::Data,
1455            *prev_cid,
1456            buf,
1457            buf_capacity,
1458            0,
1459            false,
1460            self,
1461        )?;
1462        trace!("validating previous path with PATH_CHALLENGE {:08x}", token);
1463        buf.write(frame::FrameType::PATH_CHALLENGE);
1464        buf.write(token);
1465        self.stats.frame_tx.path_challenge += 1;
1466
1467        // An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame
1468        // to at least the smallest allowed maximum datagram size of 1200 bytes,
1469        // unless the anti-amplification limit for the path does not permit
1470        // sending a datagram of this size
1471        builder.pad_to(MIN_INITIAL_SIZE);
1472
1473        builder.finish(self, buf);
1474        self.stats.udp_tx.on_sent(1, buf.len());
1475
1476        Some(Transmit {
1477            destination,
1478            size: buf.len(),
1479            ecn: None,
1480            segment_size: None,
1481            src_ip: self.local_ip,
1482        })
1483    }
1484
1485    /// Indicate what types of frames are ready to send for the given space
1486    fn space_can_send(&self, space_id: SpaceId, frame_space_1rtt: usize) -> SendableFrames {
1487        if self.spaces[space_id].crypto.is_none()
1488            && (space_id != SpaceId::Data
1489                || self.zero_rtt_crypto.is_none()
1490                || self.side.is_server())
1491        {
1492            // No keys available for this space
1493            return SendableFrames::empty();
1494        }
1495        let mut can_send = self.spaces[space_id].can_send(&self.streams);
1496        if space_id == SpaceId::Data {
1497            can_send.other |= self.can_send_1rtt(frame_space_1rtt);
1498        }
1499        can_send
1500    }
1501
1502    /// Process `ConnectionEvent`s generated by the associated `Endpoint`
1503    ///
1504    /// Will execute protocol logic upon receipt of a connection event, in turn preparing signals
1505    /// (including application `Event`s, `EndpointEvent`s and outgoing datagrams) that should be
1506    /// extracted through the relevant methods.
1507    pub fn handle_event(&mut self, event: ConnectionEvent) {
1508        use ConnectionEventInner::*;
1509        match event.0 {
1510            Datagram(DatagramConnectionEvent {
1511                now,
1512                remote,
1513                ecn,
1514                first_decode,
1515                remaining,
1516            }) => {
1517                // If this packet could initiate a migration and we're a client or a server that
1518                // forbids migration, drop the datagram. This could be relaxed to heuristically
1519                // permit NAT-rebinding-like migration.
1520                if remote != self.path.remote && !self.side.remote_may_migrate() {
1521                    trace!("discarding packet from unrecognized peer {}", remote);
1522                    return;
1523                }
1524
1525                let was_anti_amplification_blocked = self.path.anti_amplification_blocked(1);
1526
1527                self.stats.udp_rx.datagrams += 1;
1528                self.stats.udp_rx.bytes += first_decode.len() as u64;
1529                let data_len = first_decode.len();
1530
1531                self.handle_decode(now, remote, ecn, first_decode);
1532                // The current `path` might have changed inside `handle_decode`,
1533                // since the packet could have triggered a migration. Make sure
1534                // the data received is accounted for the most recent path by accessing
1535                // `path` after `handle_decode`.
1536                self.path.total_recvd = self.path.total_recvd.saturating_add(data_len as u64);
1537
1538                if let Some(data) = remaining {
1539                    self.stats.udp_rx.bytes += data.len() as u64;
1540                    self.handle_coalesced(now, remote, ecn, data);
1541                }
1542
1543                #[cfg(feature = "__qlog")]
1544                self.emit_qlog_recovery_metrics(now);
1545
1546                if was_anti_amplification_blocked {
1547                    // A prior attempt to set the loss detection timer may have failed due to
1548                    // anti-amplification, so ensure it's set now. Prevents a handshake deadlock if
1549                    // the server's first flight is lost.
1550                    self.set_loss_detection_timer(now);
1551                }
1552            }
1553            NewIdentifiers(ids, now) => {
1554                self.local_cid_state.new_cids(&ids, now);
1555                ids.into_iter().rev().for_each(|frame| {
1556                    self.spaces[SpaceId::Data].pending.new_cids.push(frame);
1557                });
1558                // Update Timer::PushNewCid
1559                if self
1560                    .timers
1561                    .get(Timer::PushNewCid)
1562                    .map_or(true, |x| x <= now)
1563                {
1564                    self.reset_cid_retirement();
1565                }
1566            }
1567        }
1568    }
1569
1570    /// Process timer expirations
1571    ///
1572    /// Executes protocol logic, potentially preparing signals (including application `Event`s,
1573    /// `EndpointEvent`s and outgoing datagrams) that should be extracted through the relevant
1574    /// methods.
1575    ///
1576    /// It is most efficient to call this immediately after the system clock reaches the latest
1577    /// `Instant` that was output by `poll_timeout`; however spurious extra calls will simply
1578    /// no-op and therefore are safe.
1579    pub fn handle_timeout(&mut self, now: Instant) {
1580        for &timer in &Timer::VALUES {
1581            if !self.timers.is_expired(timer, now) {
1582                continue;
1583            }
1584            self.timers.stop(timer);
1585            trace!(timer = ?timer, "timeout");
1586            match timer {
1587                Timer::Close => {
1588                    self.state = State::Drained;
1589                    self.endpoint_events.push_back(EndpointEventInner::Drained);
1590                }
1591                Timer::Idle => {
1592                    self.kill(ConnectionError::TimedOut);
1593                }
1594                Timer::KeepAlive => {
1595                    trace!("sending keep-alive");
1596                    self.ping();
1597                }
1598                Timer::LossDetection => {
1599                    self.on_loss_detection_timeout(now);
1600
1601                    #[cfg(feature = "__qlog")]
1602                    self.emit_qlog_recovery_metrics(now);
1603                }
1604                Timer::KeyDiscard => {
1605                    self.zero_rtt_crypto = None;
1606                    self.prev_crypto = None;
1607                }
1608                Timer::PathValidation => {
1609                    debug!("path validation failed");
1610                    if let Some((_, prev)) = self.prev_path.take() {
1611                        self.path = prev;
1612                    }
1613                    self.path.challenge = None;
1614                    self.path.challenge_pending = false;
1615                }
1616                Timer::Pacing => trace!("pacing timer expired"),
1617                Timer::NatTraversal => {
1618                    self.handle_nat_traversal_timeout(now);
1619                }
1620                Timer::PushNewCid => {
1621                    // Update `retire_prior_to` field in NEW_CONNECTION_ID frame
1622                    let num_new_cid = self.local_cid_state.on_cid_timeout().into();
1623                    if !self.state.is_closed() {
1624                        trace!(
1625                            "push a new cid to peer RETIRE_PRIOR_TO field {}",
1626                            self.local_cid_state.retire_prior_to()
1627                        );
1628                        self.endpoint_events
1629                            .push_back(EndpointEventInner::NeedIdentifiers(now, num_new_cid));
1630                    }
1631                }
1632                Timer::MaxAckDelay => {
1633                    trace!("max ack delay reached");
1634                    // This timer is only armed in the Data space
1635                    self.spaces[SpaceId::Data]
1636                        .pending_acks
1637                        .on_max_ack_delay_timeout()
1638                }
1639            }
1640        }
1641    }
1642
1643    /// Close a connection immediately
1644    ///
1645    /// This does not ensure delivery of outstanding data. It is the application's responsibility to
1646    /// call this only when all important communications have been completed, e.g. by calling
1647    /// [`SendStream::finish`] on outstanding streams and waiting for the corresponding
1648    /// [`StreamEvent::Finished`] event.
1649    ///
1650    /// If [`Streams::send_streams`] returns 0, all outstanding stream data has been
1651    /// delivered. There may still be data from the peer that has not been received.
1652    ///
1653    /// [`StreamEvent::Finished`]: crate::StreamEvent::Finished
1654    pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) {
1655        self.close_inner(
1656            now,
1657            Close::Application(frame::ApplicationClose { error_code, reason }),
1658        )
1659    }
1660
1661    fn close_inner(&mut self, now: Instant, reason: Close) {
1662        let was_closed = self.state.is_closed();
1663        if !was_closed {
1664            self.close_common();
1665            self.set_close_timer(now);
1666            self.close = true;
1667            self.state = State::Closed(state::Closed { reason });
1668        }
1669    }
1670
1671    /// Control datagrams
1672    pub fn datagrams(&mut self) -> Datagrams<'_> {
1673        Datagrams { conn: self }
1674    }
1675
1676    /// Returns connection statistics
1677    pub fn stats(&self) -> ConnectionStats {
1678        let mut stats = self.stats;
1679        stats.path.rtt = self.path.rtt.get();
1680        stats.path.cwnd = self.path.congestion.window();
1681        stats.path.current_mtu = self.path.mtud.current_mtu();
1682
1683        stats
1684    }
1685
1686    /// Ping the remote endpoint
1687    ///
1688    /// Causes an ACK-eliciting packet to be transmitted.
1689    pub fn ping(&mut self) {
1690        self.spaces[self.highest_space].ping_pending = true;
1691    }
1692
1693    /// Update traffic keys spontaneously
1694    ///
1695    /// This can be useful for testing key updates, as they otherwise only happen infrequently.
1696    pub fn force_key_update(&mut self) {
1697        if !self.state.is_established() {
1698            debug!("ignoring forced key update in illegal state");
1699            return;
1700        }
1701        if self.prev_crypto.is_some() {
1702            // We already just updated, or are currently updating, the keys. Concurrent key updates
1703            // are illegal.
1704            debug!("ignoring redundant forced key update");
1705            return;
1706        }
1707        self.update_keys(None, false);
1708    }
1709
1710    // Compatibility wrapper for quinn < 0.11.7. Remove for 0.12.
1711    #[doc(hidden)]
1712    #[deprecated]
1713    pub fn initiate_key_update(&mut self) {
1714        self.force_key_update();
1715    }
1716
1717    /// Get a session reference
1718    pub fn crypto_session(&self) -> &dyn crypto::Session {
1719        &*self.crypto
1720    }
1721
1722    /// Whether the connection is in the process of being established
1723    ///
1724    /// If this returns `false`, the connection may be either established or closed, signaled by the
1725    /// emission of a `Connected` or `ConnectionLost` message respectively.
1726    pub fn is_handshaking(&self) -> bool {
1727        self.state.is_handshake()
1728    }
1729
1730    /// Whether the connection is closed
1731    ///
1732    /// Closed connections cannot transport any further data. A connection becomes closed when
1733    /// either peer application intentionally closes it, or when either transport layer detects an
1734    /// error such as a time-out or certificate validation failure.
1735    ///
1736    /// A `ConnectionLost` event is emitted with details when the connection becomes closed.
1737    pub fn is_closed(&self) -> bool {
1738        self.state.is_closed()
1739    }
1740
1741    /// Whether there is no longer any need to keep the connection around
1742    ///
1743    /// Closed connections become drained after a brief timeout to absorb any remaining in-flight
1744    /// packets from the peer. All drained connections have been closed.
1745    pub fn is_drained(&self) -> bool {
1746        self.state.is_drained()
1747    }
1748
1749    /// For clients, if the peer accepted the 0-RTT data packets
1750    ///
1751    /// The value is meaningless until after the handshake completes.
1752    pub fn accepted_0rtt(&self) -> bool {
1753        self.accepted_0rtt
1754    }
1755
1756    /// Whether 0-RTT is/was possible during the handshake
1757    pub fn has_0rtt(&self) -> bool {
1758        self.zero_rtt_enabled
1759    }
1760
1761    /// Whether there are any pending retransmits
1762    pub fn has_pending_retransmits(&self) -> bool {
1763        !self.spaces[SpaceId::Data].pending.is_empty(&self.streams)
1764    }
1765
1766    /// Look up whether we're the client or server of this Connection
1767    pub fn side(&self) -> Side {
1768        self.side.side()
1769    }
1770
1771    /// The latest socket address for this connection's peer
1772    pub fn remote_address(&self) -> SocketAddr {
1773        self.path.remote
1774    }
1775
1776    /// The local IP address which was used when the peer established
1777    /// the connection
1778    ///
1779    /// This can be different from the address the endpoint is bound to, in case
1780    /// the endpoint is bound to a wildcard address like `0.0.0.0` or `::`.
1781    ///
1782    /// This will return `None` for clients, or when no `local_ip` was passed to
1783    /// [`Endpoint::handle()`](crate::Endpoint::handle) for the datagrams establishing this
1784    /// connection.
1785    pub fn local_ip(&self) -> Option<IpAddr> {
1786        self.local_ip
1787    }
1788
1789    /// Current best estimate of this connection's latency (round-trip-time)
1790    pub fn rtt(&self) -> Duration {
1791        self.path.rtt.get()
1792    }
1793
1794    /// Current state of this connection's congestion controller, for debugging purposes
1795    pub fn congestion_state(&self) -> &dyn Controller {
1796        self.path.congestion.as_ref()
1797    }
1798
1799    /// Resets path-specific settings.
1800    ///
1801    /// This will force-reset several subsystems related to a specific network path.
1802    /// Currently this is the congestion controller, round-trip estimator, and the MTU
1803    /// discovery.
1804    ///
1805    /// This is useful when it is known the underlying network path has changed and the old
1806    /// state of these subsystems is no longer valid or optimal. In this case it might be
1807    /// faster or reduce loss to settle on optimal values by restarting from the initial
1808    /// configuration in the [`TransportConfig`].
1809    pub fn path_changed(&mut self, now: Instant) {
1810        self.path.reset(now, &self.config);
1811    }
1812
1813    /// Modify the number of remotely initiated streams that may be concurrently open
1814    ///
1815    /// No streams may be opened by the peer unless fewer than `count` are already open. Large
1816    /// `count`s increase both minimum and worst-case memory consumption.
1817    pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) {
1818        self.streams.set_max_concurrent(dir, count);
1819        // If the limit was reduced, then a flow control update previously deemed insignificant may
1820        // now be significant.
1821        let pending = &mut self.spaces[SpaceId::Data].pending;
1822        self.streams.queue_max_stream_id(pending);
1823    }
1824
1825    /// Current number of remotely initiated streams that may be concurrently open
1826    ///
1827    /// If the target for this limit is reduced using [`set_max_concurrent_streams`](Self::set_max_concurrent_streams),
1828    /// it will not change immediately, even if fewer streams are open. Instead, it will
1829    /// decrement by one for each time a remotely initiated stream of matching directionality is closed.
1830    pub fn max_concurrent_streams(&self, dir: Dir) -> u64 {
1831        self.streams.max_concurrent(dir)
1832    }
1833
1834    /// See [`TransportConfig::receive_window()`]
1835    pub fn set_receive_window(&mut self, receive_window: VarInt) {
1836        if self.streams.set_receive_window(receive_window) {
1837            self.spaces[SpaceId::Data].pending.max_data = true;
1838        }
1839    }
1840    
1841    /// Enable or disable address discovery for this connection
1842    pub fn set_address_discovery_enabled(&mut self, enabled: bool) {
1843        if let Some(ref mut state) = self.address_discovery_state {
1844            state.enabled = enabled;
1845        }
1846    }
1847    
1848    /// Check if address discovery is enabled for this connection
1849    pub fn address_discovery_enabled(&self) -> bool {
1850        self.address_discovery_state
1851            .as_ref()
1852            .map_or(false, |state| state.enabled)
1853    }
1854    
1855    /// Get the observed address for this connection
1856    /// 
1857    /// Returns the address that the remote peer has observed for this connection,
1858    /// or None if no OBSERVED_ADDRESS frame has been received yet.
1859    pub fn observed_address(&self) -> Option<SocketAddr> {
1860        self.address_discovery_state
1861            .as_ref()
1862            .and_then(|state| state.get_observed_address(0)) // Use path ID 0 for primary path
1863    }
1864    
1865    /// Get the address discovery state (internal use)
1866    pub(crate) fn address_discovery_state(&self) -> Option<&AddressDiscoveryState> {
1867        self.address_discovery_state.as_ref()
1868    }
1869
1870    fn on_ack_received(
1871        &mut self,
1872        now: Instant,
1873        space: SpaceId,
1874        ack: frame::Ack,
1875    ) -> Result<(), TransportError> {
1876        if ack.largest >= self.spaces[space].next_packet_number {
1877            return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked"));
1878        }
1879        let new_largest = {
1880            let space = &mut self.spaces[space];
1881            if space
1882                .largest_acked_packet
1883                .map_or(true, |pn| ack.largest > pn)
1884            {
1885                space.largest_acked_packet = Some(ack.largest);
1886                if let Some(info) = space.sent_packets.get(&ack.largest) {
1887                    // This should always succeed, but a misbehaving peer might ACK a packet we
1888                    // haven't sent. At worst, that will result in us spuriously reducing the
1889                    // congestion window.
1890                    space.largest_acked_packet_sent = info.time_sent;
1891                }
1892                true
1893            } else {
1894                false
1895            }
1896        };
1897
1898        // Avoid DoS from unreasonably huge ack ranges by filtering out just the new acks.
1899        let mut newly_acked = ArrayRangeSet::new();
1900        for range in ack.iter() {
1901            self.packet_number_filter.check_ack(space, range.clone())?;
1902            for (&pn, _) in self.spaces[space].sent_packets.range(range) {
1903                newly_acked.insert_one(pn);
1904            }
1905        }
1906
1907        if newly_acked.is_empty() {
1908            return Ok(());
1909        }
1910
1911        let mut ack_eliciting_acked = false;
1912        for packet in newly_acked.elts() {
1913            if let Some(info) = self.spaces[space].take(packet) {
1914                if let Some(acked) = info.largest_acked {
1915                    // Assume ACKs for all packets below the largest acknowledged in `packet` have
1916                    // been received. This can cause the peer to spuriously retransmit if some of
1917                    // our earlier ACKs were lost, but allows for simpler state tracking. See
1918                    // discussion at
1919                    // https://www.rfc-editor.org/rfc/rfc9000.html#name-limiting-ranges-by-tracking
1920                    self.spaces[space].pending_acks.subtract_below(acked);
1921                }
1922                ack_eliciting_acked |= info.ack_eliciting;
1923
1924                // Notify MTU discovery that a packet was acked, because it might be an MTU probe
1925                let mtu_updated = self.path.mtud.on_acked(space, packet, info.size);
1926                if mtu_updated {
1927                    self.path
1928                        .congestion
1929                        .on_mtu_update(self.path.mtud.current_mtu());
1930                }
1931
1932                // Notify ack frequency that a packet was acked, because it might contain an ACK_FREQUENCY frame
1933                self.ack_frequency.on_acked(packet);
1934
1935                self.on_packet_acked(now, packet, info);
1936            }
1937        }
1938
1939        self.path.congestion.on_end_acks(
1940            now,
1941            self.path.in_flight.bytes,
1942            self.app_limited,
1943            self.spaces[space].largest_acked_packet,
1944        );
1945
1946        if new_largest && ack_eliciting_acked {
1947            let ack_delay = if space != SpaceId::Data {
1948                Duration::from_micros(0)
1949            } else {
1950                cmp::min(
1951                    self.ack_frequency.peer_max_ack_delay,
1952                    Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0),
1953                )
1954            };
1955            let rtt = instant_saturating_sub(now, self.spaces[space].largest_acked_packet_sent);
1956            self.path.rtt.update(ack_delay, rtt);
1957            if self.path.first_packet_after_rtt_sample.is_none() {
1958                self.path.first_packet_after_rtt_sample =
1959                    Some((space, self.spaces[space].next_packet_number));
1960            }
1961        }
1962
1963        // Must be called before crypto/pto_count are clobbered
1964        self.detect_lost_packets(now, space, true);
1965
1966        if self.peer_completed_address_validation() {
1967            self.pto_count = 0;
1968        }
1969
1970        // Explicit congestion notification
1971        if self.path.sending_ecn {
1972            if let Some(ecn) = ack.ecn {
1973                // We only examine ECN counters from ACKs that we are certain we received in transmit
1974                // order, allowing us to compute an increase in ECN counts to compare against the number
1975                // of newly acked packets that remains well-defined in the presence of arbitrary packet
1976                // reordering.
1977                if new_largest {
1978                    let sent = self.spaces[space].largest_acked_packet_sent;
1979                    self.process_ecn(now, space, newly_acked.len() as u64, ecn, sent);
1980                }
1981            } else {
1982                // We always start out sending ECN, so any ack that doesn't acknowledge it disables it.
1983                debug!("ECN not acknowledged by peer");
1984                self.path.sending_ecn = false;
1985            }
1986        }
1987
1988        self.set_loss_detection_timer(now);
1989        Ok(())
1990    }
1991
1992    /// Process a new ECN block from an in-order ACK
1993    fn process_ecn(
1994        &mut self,
1995        now: Instant,
1996        space: SpaceId,
1997        newly_acked: u64,
1998        ecn: frame::EcnCounts,
1999        largest_sent_time: Instant,
2000    ) {
2001        match self.spaces[space].detect_ecn(newly_acked, ecn) {
2002            Err(e) => {
2003                debug!("halting ECN due to verification failure: {}", e);
2004                self.path.sending_ecn = false;
2005                // Wipe out the existing value because it might be garbage and could interfere with
2006                // future attempts to use ECN on new paths.
2007                self.spaces[space].ecn_feedback = frame::EcnCounts::ZERO;
2008            }
2009            Ok(false) => {}
2010            Ok(true) => {
2011                self.stats.path.congestion_events += 1;
2012                self.path
2013                    .congestion
2014                    .on_congestion_event(now, largest_sent_time, false, 0);
2015            }
2016        }
2017    }
2018
2019    // Not timing-aware, so it's safe to call this for inferred acks, such as arise from
2020    // high-latency handshakes
2021    fn on_packet_acked(&mut self, now: Instant, pn: u64, info: SentPacket) {
2022        self.remove_in_flight(pn, &info);
2023        if info.ack_eliciting && self.path.challenge.is_none() {
2024            // Only pass ACKs to the congestion controller if we are not validating the current
2025            // path, so as to ignore any ACKs from older paths still coming in.
2026            self.path.congestion.on_ack(
2027                now,
2028                info.time_sent,
2029                info.size.into(),
2030                self.app_limited,
2031                &self.path.rtt,
2032            );
2033        }
2034
2035        // Update state for confirmed delivery of frames
2036        if let Some(retransmits) = info.retransmits.get() {
2037            for (id, _) in retransmits.reset_stream.iter() {
2038                self.streams.reset_acked(*id);
2039            }
2040        }
2041
2042        for frame in info.stream_frames {
2043            self.streams.received_ack_of(frame);
2044        }
2045    }
2046
2047    fn set_key_discard_timer(&mut self, now: Instant, space: SpaceId) {
2048        let start = if self.zero_rtt_crypto.is_some() {
2049            now
2050        } else {
2051            self.prev_crypto
2052                .as_ref()
2053                .expect("no previous keys")
2054                .end_packet
2055                .as_ref()
2056                .expect("update not acknowledged yet")
2057                .1
2058        };
2059        self.timers
2060            .set(Timer::KeyDiscard, start + self.pto(space) * 3);
2061    }
2062
2063    fn on_loss_detection_timeout(&mut self, now: Instant) {
2064        if let Some((_, pn_space)) = self.loss_time_and_space() {
2065            // Time threshold loss Detection
2066            self.detect_lost_packets(now, pn_space, false);
2067            self.set_loss_detection_timer(now);
2068            return;
2069        }
2070
2071        let (_, space) = match self.pto_time_and_space(now) {
2072            Some(x) => x,
2073            None => {
2074                error!("PTO expired while unset");
2075                return;
2076            }
2077        };
2078        trace!(
2079            in_flight = self.path.in_flight.bytes,
2080            count = self.pto_count,
2081            ?space,
2082            "PTO fired"
2083        );
2084
2085        let count = match self.path.in_flight.ack_eliciting {
2086            // A PTO when we're not expecting any ACKs must be due to handshake anti-amplification
2087            // deadlock preventions
2088            0 => {
2089                debug_assert!(!self.peer_completed_address_validation());
2090                1
2091            }
2092            // Conventional loss probe
2093            _ => 2,
2094        };
2095        self.spaces[space].loss_probes = self.spaces[space].loss_probes.saturating_add(count);
2096        self.pto_count = self.pto_count.saturating_add(1);
2097        self.set_loss_detection_timer(now);
2098    }
2099
2100    fn detect_lost_packets(&mut self, now: Instant, pn_space: SpaceId, due_to_ack: bool) {
2101        let mut lost_packets = Vec::<u64>::new();
2102        let mut lost_mtu_probe = None;
2103        let in_flight_mtu_probe = self.path.mtud.in_flight_mtu_probe();
2104        let rtt = self.path.rtt.conservative();
2105        let loss_delay = cmp::max(rtt.mul_f32(self.config.time_threshold), TIMER_GRANULARITY);
2106
2107        // Packets sent before this time are deemed lost.
2108        let lost_send_time = now.checked_sub(loss_delay).unwrap();
2109        let largest_acked_packet = self.spaces[pn_space].largest_acked_packet.unwrap();
2110        let packet_threshold = self.config.packet_threshold as u64;
2111        let mut size_of_lost_packets = 0u64;
2112
2113        // InPersistentCongestion: Determine if all packets in the time period before the newest
2114        // lost packet, including the edges, are marked lost. PTO computation must always
2115        // include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1).
2116        let congestion_period =
2117            self.pto(SpaceId::Data) * self.config.persistent_congestion_threshold;
2118        let mut persistent_congestion_start: Option<Instant> = None;
2119        let mut prev_packet = None;
2120        let mut in_persistent_congestion = false;
2121
2122        let space = &mut self.spaces[pn_space];
2123        space.loss_time = None;
2124
2125        for (&packet, info) in space.sent_packets.range(0..largest_acked_packet) {
2126            if prev_packet != Some(packet.wrapping_sub(1)) {
2127                // An intervening packet was acknowledged
2128                persistent_congestion_start = None;
2129            }
2130
2131            if info.time_sent <= lost_send_time || largest_acked_packet >= packet + packet_threshold
2132            {
2133                if Some(packet) == in_flight_mtu_probe {
2134                    // Lost MTU probes are not included in `lost_packets`, because they should not
2135                    // trigger a congestion control response
2136                    lost_mtu_probe = in_flight_mtu_probe;
2137                } else {
2138                    lost_packets.push(packet);
2139                    size_of_lost_packets += info.size as u64;
2140                    if info.ack_eliciting && due_to_ack {
2141                        match persistent_congestion_start {
2142                            // Two ACK-eliciting packets lost more than congestion_period apart, with no
2143                            // ACKed packets in between
2144                            Some(start) if info.time_sent - start > congestion_period => {
2145                                in_persistent_congestion = true;
2146                            }
2147                            // Persistent congestion must start after the first RTT sample
2148                            None if self
2149                                .path
2150                                .first_packet_after_rtt_sample
2151                                .is_some_and(|x| x < (pn_space, packet)) =>
2152                            {
2153                                persistent_congestion_start = Some(info.time_sent);
2154                            }
2155                            _ => {}
2156                        }
2157                    }
2158                }
2159            } else {
2160                let next_loss_time = info.time_sent + loss_delay;
2161                space.loss_time = Some(
2162                    space
2163                        .loss_time
2164                        .map_or(next_loss_time, |x| cmp::min(x, next_loss_time)),
2165                );
2166                persistent_congestion_start = None;
2167            }
2168
2169            prev_packet = Some(packet);
2170        }
2171
2172        // OnPacketsLost
2173        if let Some(largest_lost) = lost_packets.last().cloned() {
2174            let old_bytes_in_flight = self.path.in_flight.bytes;
2175            let largest_lost_sent = self.spaces[pn_space].sent_packets[&largest_lost].time_sent;
2176            self.lost_packets += lost_packets.len() as u64;
2177            self.stats.path.lost_packets += lost_packets.len() as u64;
2178            self.stats.path.lost_bytes += size_of_lost_packets;
2179            trace!(
2180                "packets lost: {:?}, bytes lost: {}",
2181                lost_packets, size_of_lost_packets
2182            );
2183
2184            for &packet in &lost_packets {
2185                let info = self.spaces[pn_space].take(packet).unwrap(); // safe: lost_packets is populated just above
2186                self.remove_in_flight(packet, &info);
2187                for frame in info.stream_frames {
2188                    self.streams.retransmit(frame);
2189                }
2190                self.spaces[pn_space].pending |= info.retransmits;
2191                self.path.mtud.on_non_probe_lost(packet, info.size);
2192            }
2193
2194            if self.path.mtud.black_hole_detected(now) {
2195                self.stats.path.black_holes_detected += 1;
2196                self.path
2197                    .congestion
2198                    .on_mtu_update(self.path.mtud.current_mtu());
2199                if let Some(max_datagram_size) = self.datagrams().max_size() {
2200                    self.datagrams.drop_oversized(max_datagram_size);
2201                }
2202            }
2203
2204            // Don't apply congestion penalty for lost ack-only packets
2205            let lost_ack_eliciting = old_bytes_in_flight != self.path.in_flight.bytes;
2206
2207            if lost_ack_eliciting {
2208                self.stats.path.congestion_events += 1;
2209                self.path.congestion.on_congestion_event(
2210                    now,
2211                    largest_lost_sent,
2212                    in_persistent_congestion,
2213                    size_of_lost_packets,
2214                );
2215            }
2216        }
2217
2218        // Handle a lost MTU probe
2219        if let Some(packet) = lost_mtu_probe {
2220            let info = self.spaces[SpaceId::Data].take(packet).unwrap(); // safe: lost_mtu_probe is omitted from lost_packets, and therefore must not have been removed yet
2221            self.remove_in_flight(packet, &info);
2222            self.path.mtud.on_probe_lost();
2223            self.stats.path.lost_plpmtud_probes += 1;
2224        }
2225    }
2226
2227    fn loss_time_and_space(&self) -> Option<(Instant, SpaceId)> {
2228        SpaceId::iter()
2229            .filter_map(|id| Some((self.spaces[id].loss_time?, id)))
2230            .min_by_key(|&(time, _)| time)
2231    }
2232
2233    fn pto_time_and_space(&self, now: Instant) -> Option<(Instant, SpaceId)> {
2234        let backoff = 2u32.pow(self.pto_count.min(MAX_BACKOFF_EXPONENT));
2235        let mut duration = self.path.rtt.pto_base() * backoff;
2236
2237        if self.path.in_flight.ack_eliciting == 0 {
2238            debug_assert!(!self.peer_completed_address_validation());
2239            let space = match self.highest_space {
2240                SpaceId::Handshake => SpaceId::Handshake,
2241                _ => SpaceId::Initial,
2242            };
2243            return Some((now + duration, space));
2244        }
2245
2246        let mut result = None;
2247        for space in SpaceId::iter() {
2248            if self.spaces[space].in_flight == 0 {
2249                continue;
2250            }
2251            if space == SpaceId::Data {
2252                // Skip ApplicationData until handshake completes.
2253                if self.is_handshaking() {
2254                    return result;
2255                }
2256                // Include max_ack_delay and backoff for ApplicationData.
2257                duration += self.ack_frequency.max_ack_delay_for_pto() * backoff;
2258            }
2259            let last_ack_eliciting = match self.spaces[space].time_of_last_ack_eliciting_packet {
2260                Some(time) => time,
2261                None => continue,
2262            };
2263            let pto = last_ack_eliciting + duration;
2264            if result.map_or(true, |(earliest_pto, _)| pto < earliest_pto) {
2265                result = Some((pto, space));
2266            }
2267        }
2268        result
2269    }
2270
2271    fn peer_completed_address_validation(&self) -> bool {
2272        if self.side.is_server() || self.state.is_closed() {
2273            return true;
2274        }
2275        // The server is guaranteed to have validated our address if any of our handshake or 1-RTT
2276        // packets are acknowledged or we've seen HANDSHAKE_DONE and discarded handshake keys.
2277        self.spaces[SpaceId::Handshake]
2278            .largest_acked_packet
2279            .is_some()
2280            || self.spaces[SpaceId::Data].largest_acked_packet.is_some()
2281            || (self.spaces[SpaceId::Data].crypto.is_some()
2282                && self.spaces[SpaceId::Handshake].crypto.is_none())
2283    }
2284
2285    fn set_loss_detection_timer(&mut self, now: Instant) {
2286        if self.state.is_closed() {
2287            // No loss detection takes place on closed connections, and `close_common` already
2288            // stopped time timer. Ensure we don't restart it inadvertently, e.g. in response to a
2289            // reordered packet being handled by state-insensitive code.
2290            return;
2291        }
2292
2293        if let Some((loss_time, _)) = self.loss_time_and_space() {
2294            // Time threshold loss detection.
2295            self.timers.set(Timer::LossDetection, loss_time);
2296            return;
2297        }
2298
2299        if self.path.anti_amplification_blocked(1) {
2300            // We wouldn't be able to send anything, so don't bother.
2301            self.timers.stop(Timer::LossDetection);
2302            return;
2303        }
2304
2305        if self.path.in_flight.ack_eliciting == 0 && self.peer_completed_address_validation() {
2306            // There is nothing to detect lost, so no timer is set. However, the client needs to arm
2307            // the timer if the server might be blocked by the anti-amplification limit.
2308            self.timers.stop(Timer::LossDetection);
2309            return;
2310        }
2311
2312        // Determine which PN space to arm PTO for.
2313        // Calculate PTO duration
2314        if let Some((timeout, _)) = self.pto_time_and_space(now) {
2315            self.timers.set(Timer::LossDetection, timeout);
2316        } else {
2317            self.timers.stop(Timer::LossDetection);
2318        }
2319    }
2320
2321    /// Probe Timeout
2322    fn pto(&self, space: SpaceId) -> Duration {
2323        let max_ack_delay = match space {
2324            SpaceId::Initial | SpaceId::Handshake => Duration::ZERO,
2325            SpaceId::Data => self.ack_frequency.max_ack_delay_for_pto(),
2326        };
2327        self.path.rtt.pto_base() + max_ack_delay
2328    }
2329
2330    fn on_packet_authenticated(
2331        &mut self,
2332        now: Instant,
2333        space_id: SpaceId,
2334        ecn: Option<EcnCodepoint>,
2335        packet: Option<u64>,
2336        spin: bool,
2337        is_1rtt: bool,
2338    ) {
2339        self.total_authed_packets += 1;
2340        self.reset_keep_alive(now);
2341        self.reset_idle_timeout(now, space_id);
2342        self.permit_idle_reset = true;
2343        self.receiving_ecn |= ecn.is_some();
2344        if let Some(x) = ecn {
2345            let space = &mut self.spaces[space_id];
2346            space.ecn_counters += x;
2347
2348            if x.is_ce() {
2349                space.pending_acks.set_immediate_ack_required();
2350            }
2351        }
2352
2353        let packet = match packet {
2354            Some(x) => x,
2355            None => return,
2356        };
2357        if self.side.is_server() {
2358            if self.spaces[SpaceId::Initial].crypto.is_some() && space_id == SpaceId::Handshake {
2359                // A server stops sending and processing Initial packets when it receives its first Handshake packet.
2360                self.discard_space(now, SpaceId::Initial);
2361            }
2362            if self.zero_rtt_crypto.is_some() && is_1rtt {
2363                // Discard 0-RTT keys soon after receiving a 1-RTT packet
2364                self.set_key_discard_timer(now, space_id)
2365            }
2366        }
2367        let space = &mut self.spaces[space_id];
2368        space.pending_acks.insert_one(packet, now);
2369        if packet >= space.rx_packet {
2370            space.rx_packet = packet;
2371            // Update outgoing spin bit, inverting iff we're the client
2372            self.spin = self.side.is_client() ^ spin;
2373        }
2374    }
2375
2376    fn reset_idle_timeout(&mut self, now: Instant, space: SpaceId) {
2377        let timeout = match self.idle_timeout {
2378            None => return,
2379            Some(dur) => dur,
2380        };
2381        if self.state.is_closed() {
2382            self.timers.stop(Timer::Idle);
2383            return;
2384        }
2385        let dt = cmp::max(timeout, 3 * self.pto(space));
2386        self.timers.set(Timer::Idle, now + dt);
2387    }
2388
2389    fn reset_keep_alive(&mut self, now: Instant) {
2390        let interval = match self.config.keep_alive_interval {
2391            Some(x) if self.state.is_established() => x,
2392            _ => return,
2393        };
2394        self.timers.set(Timer::KeepAlive, now + interval);
2395    }
2396
2397    fn reset_cid_retirement(&mut self) {
2398        if let Some(t) = self.local_cid_state.next_timeout() {
2399            self.timers.set(Timer::PushNewCid, t);
2400        }
2401    }
2402
2403    /// Handle the already-decrypted first packet from the client
2404    ///
2405    /// Decrypting the first packet in the `Endpoint` allows stateless packet handling to be more
2406    /// efficient.
2407    pub(crate) fn handle_first_packet(
2408        &mut self,
2409        now: Instant,
2410        remote: SocketAddr,
2411        ecn: Option<EcnCodepoint>,
2412        packet_number: u64,
2413        packet: InitialPacket,
2414        remaining: Option<BytesMut>,
2415    ) -> Result<(), ConnectionError> {
2416        let span = trace_span!("first recv");
2417        let _guard = span.enter();
2418        debug_assert!(self.side.is_server());
2419        let len = packet.header_data.len() + packet.payload.len();
2420        self.path.total_recvd = len as u64;
2421
2422        match self.state {
2423            State::Handshake(ref mut state) => {
2424                state.expected_token = packet.header.token.clone();
2425            }
2426            _ => unreachable!("first packet must be delivered in Handshake state"),
2427        }
2428
2429        self.on_packet_authenticated(
2430            now,
2431            SpaceId::Initial,
2432            ecn,
2433            Some(packet_number),
2434            false,
2435            false,
2436        );
2437
2438        self.process_decrypted_packet(now, remote, Some(packet_number), packet.into())?;
2439        if let Some(data) = remaining {
2440            self.handle_coalesced(now, remote, ecn, data);
2441        }
2442
2443        #[cfg(feature = "__qlog")]
2444        self.emit_qlog_recovery_metrics(now);
2445
2446        Ok(())
2447    }
2448
2449    fn init_0rtt(&mut self) {
2450        let (header, packet) = match self.crypto.early_crypto() {
2451            Some(x) => x,
2452            None => return,
2453        };
2454        if self.side.is_client() {
2455            match self.crypto.transport_parameters() {
2456                Ok(params) => {
2457                    let params = params
2458                        .expect("crypto layer didn't supply transport parameters with ticket");
2459                    // Certain values must not be cached
2460                    let params = TransportParameters {
2461                        initial_src_cid: None,
2462                        original_dst_cid: None,
2463                        preferred_address: None,
2464                        retry_src_cid: None,
2465                        stateless_reset_token: None,
2466                        min_ack_delay: None,
2467                        ack_delay_exponent: TransportParameters::default().ack_delay_exponent,
2468                        max_ack_delay: TransportParameters::default().max_ack_delay,
2469                        ..params
2470                    };
2471                    self.set_peer_params(params);
2472                }
2473                Err(e) => {
2474                    error!("session ticket has malformed transport parameters: {}", e);
2475                    return;
2476                }
2477            }
2478        }
2479        trace!("0-RTT enabled");
2480        self.zero_rtt_enabled = true;
2481        self.zero_rtt_crypto = Some(ZeroRttCrypto { header, packet });
2482    }
2483
2484    fn read_crypto(
2485        &mut self,
2486        space: SpaceId,
2487        crypto: &frame::Crypto,
2488        payload_len: usize,
2489    ) -> Result<(), TransportError> {
2490        let expected = if !self.state.is_handshake() {
2491            SpaceId::Data
2492        } else if self.highest_space == SpaceId::Initial {
2493            SpaceId::Initial
2494        } else {
2495            // On the server, self.highest_space can be Data after receiving the client's first
2496            // flight, but we expect Handshake CRYPTO until the handshake is complete.
2497            SpaceId::Handshake
2498        };
2499        // We can't decrypt Handshake packets when highest_space is Initial, CRYPTO frames in 0-RTT
2500        // packets are illegal, and we don't process 1-RTT packets until the handshake is
2501        // complete. Therefore, we will never see CRYPTO data from a later-than-expected space.
2502        debug_assert!(space <= expected, "received out-of-order CRYPTO data");
2503
2504        let end = crypto.offset + crypto.data.len() as u64;
2505        if space < expected && end > self.spaces[space].crypto_stream.bytes_read() {
2506            warn!(
2507                "received new {:?} CRYPTO data when expecting {:?}",
2508                space, expected
2509            );
2510            return Err(TransportError::PROTOCOL_VIOLATION(
2511                "new data at unexpected encryption level",
2512            ));
2513        }
2514
2515        let space = &mut self.spaces[space];
2516        let max = end.saturating_sub(space.crypto_stream.bytes_read());
2517        if max > self.config.crypto_buffer_size as u64 {
2518            return Err(TransportError::CRYPTO_BUFFER_EXCEEDED(""));
2519        }
2520
2521        space
2522            .crypto_stream
2523            .insert(crypto.offset, crypto.data.clone(), payload_len);
2524        while let Some(chunk) = space.crypto_stream.read(usize::MAX, true) {
2525            trace!("consumed {} CRYPTO bytes", chunk.bytes.len());
2526            if self.crypto.read_handshake(&chunk.bytes)? {
2527                self.events.push_back(Event::HandshakeDataReady);
2528            }
2529        }
2530
2531        Ok(())
2532    }
2533
2534    fn write_crypto(&mut self) {
2535        loop {
2536            let space = self.highest_space;
2537            let mut outgoing = Vec::new();
2538            if let Some(crypto) = self.crypto.write_handshake(&mut outgoing) {
2539                match space {
2540                    SpaceId::Initial => {
2541                        self.upgrade_crypto(SpaceId::Handshake, crypto);
2542                    }
2543                    SpaceId::Handshake => {
2544                        self.upgrade_crypto(SpaceId::Data, crypto);
2545                    }
2546                    _ => unreachable!("got updated secrets during 1-RTT"),
2547                }
2548            }
2549            if outgoing.is_empty() {
2550                if space == self.highest_space {
2551                    break;
2552                } else {
2553                    // Keys updated, check for more data to send
2554                    continue;
2555                }
2556            }
2557            let offset = self.spaces[space].crypto_offset;
2558            let outgoing = Bytes::from(outgoing);
2559            if let State::Handshake(ref mut state) = self.state {
2560                if space == SpaceId::Initial && offset == 0 && self.side.is_client() {
2561                    state.client_hello = Some(outgoing.clone());
2562                }
2563            }
2564            self.spaces[space].crypto_offset += outgoing.len() as u64;
2565            trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space);
2566            self.spaces[space].pending.crypto.push_back(frame::Crypto {
2567                offset,
2568                data: outgoing,
2569            });
2570        }
2571    }
2572
2573    /// Switch to stronger cryptography during handshake
2574    fn upgrade_crypto(&mut self, space: SpaceId, crypto: Keys) {
2575        debug_assert!(
2576            self.spaces[space].crypto.is_none(),
2577            "already reached packet space {space:?}"
2578        );
2579        trace!("{:?} keys ready", space);
2580        if space == SpaceId::Data {
2581            // Precompute the first key update
2582            self.next_crypto = Some(
2583                self.crypto
2584                    .next_1rtt_keys()
2585                    .expect("handshake should be complete"),
2586            );
2587        }
2588
2589        self.spaces[space].crypto = Some(crypto);
2590        debug_assert!(space as usize > self.highest_space as usize);
2591        self.highest_space = space;
2592        if space == SpaceId::Data && self.side.is_client() {
2593            // Discard 0-RTT keys because 1-RTT keys are available.
2594            self.zero_rtt_crypto = None;
2595        }
2596    }
2597
2598    fn discard_space(&mut self, now: Instant, space_id: SpaceId) {
2599        debug_assert!(space_id != SpaceId::Data);
2600        trace!("discarding {:?} keys", space_id);
2601        if space_id == SpaceId::Initial {
2602            // No longer needed
2603            if let ConnectionSide::Client { token, .. } = &mut self.side {
2604                *token = Bytes::new();
2605            }
2606        }
2607        let space = &mut self.spaces[space_id];
2608        space.crypto = None;
2609        space.time_of_last_ack_eliciting_packet = None;
2610        space.loss_time = None;
2611        space.in_flight = 0;
2612        let sent_packets = mem::take(&mut space.sent_packets);
2613        for (pn, packet) in sent_packets.into_iter() {
2614            self.remove_in_flight(pn, &packet);
2615        }
2616        self.set_loss_detection_timer(now)
2617    }
2618
2619    fn handle_coalesced(
2620        &mut self,
2621        now: Instant,
2622        remote: SocketAddr,
2623        ecn: Option<EcnCodepoint>,
2624        data: BytesMut,
2625    ) {
2626        self.path.total_recvd = self.path.total_recvd.saturating_add(data.len() as u64);
2627        let mut remaining = Some(data);
2628        while let Some(data) = remaining {
2629            match PartialDecode::new(
2630                data,
2631                &FixedLengthConnectionIdParser::new(self.local_cid_state.cid_len()),
2632                &[self.version],
2633                self.endpoint_config.grease_quic_bit,
2634            ) {
2635                Ok((partial_decode, rest)) => {
2636                    remaining = rest;
2637                    self.handle_decode(now, remote, ecn, partial_decode);
2638                }
2639                Err(e) => {
2640                    trace!("malformed header: {}", e);
2641                    return;
2642                }
2643            }
2644        }
2645    }
2646
2647    fn handle_decode(
2648        &mut self,
2649        now: Instant,
2650        remote: SocketAddr,
2651        ecn: Option<EcnCodepoint>,
2652        partial_decode: PartialDecode,
2653    ) {
2654        if let Some(decoded) = packet_crypto::unprotect_header(
2655            partial_decode,
2656            &self.spaces,
2657            self.zero_rtt_crypto.as_ref(),
2658            self.peer_params.stateless_reset_token,
2659        ) {
2660            self.handle_packet(now, remote, ecn, decoded.packet, decoded.stateless_reset);
2661        }
2662    }
2663
2664    fn handle_packet(
2665        &mut self,
2666        now: Instant,
2667        remote: SocketAddr,
2668        ecn: Option<EcnCodepoint>,
2669        packet: Option<Packet>,
2670        stateless_reset: bool,
2671    ) {
2672        self.stats.udp_rx.ios += 1;
2673        if let Some(ref packet) = packet {
2674            trace!(
2675                "got {:?} packet ({} bytes) from {} using id {}",
2676                packet.header.space(),
2677                packet.payload.len() + packet.header_data.len(),
2678                remote,
2679                packet.header.dst_cid(),
2680            );
2681            
2682            // Trace packet received
2683            #[cfg(feature = "trace")]
2684            {
2685                use crate::tracing::*;
2686                use crate::trace_packet_received;
2687                let packet_size = packet.payload.len() + packet.header_data.len();
2688                trace_packet_received!(
2689                    &self.event_log,
2690                    self.trace_context.trace_id(),
2691                    packet_size as u32,
2692                    0 // Will be updated when packet number is decoded
2693                );
2694            }
2695        }
2696
2697        if self.is_handshaking() && remote != self.path.remote {
2698            debug!("discarding packet with unexpected remote during handshake");
2699            return;
2700        }
2701
2702        let was_closed = self.state.is_closed();
2703        let was_drained = self.state.is_drained();
2704
2705        let decrypted = match packet {
2706            None => Err(None),
2707            Some(mut packet) => self
2708                .decrypt_packet(now, &mut packet)
2709                .map(move |number| (packet, number)),
2710        };
2711        let result = match decrypted {
2712            _ if stateless_reset => {
2713                debug!("got stateless reset");
2714                Err(ConnectionError::Reset)
2715            }
2716            Err(Some(e)) => {
2717                warn!("illegal packet: {}", e);
2718                Err(e.into())
2719            }
2720            Err(None) => {
2721                debug!("failed to authenticate packet");
2722                self.authentication_failures += 1;
2723                let integrity_limit = self.spaces[self.highest_space]
2724                    .crypto
2725                    .as_ref()
2726                    .unwrap()
2727                    .packet
2728                    .local
2729                    .integrity_limit();
2730                if self.authentication_failures > integrity_limit {
2731                    Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into())
2732                } else {
2733                    return;
2734                }
2735            }
2736            Ok((packet, number)) => {
2737                let span = match number {
2738                    Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn),
2739                    None => trace_span!("recv", space = ?packet.header.space()),
2740                };
2741                let _guard = span.enter();
2742
2743                let is_duplicate = |n| self.spaces[packet.header.space()].dedup.insert(n);
2744                if number.is_some_and(is_duplicate) {
2745                    debug!("discarding possible duplicate packet");
2746                    return;
2747                } else if self.state.is_handshake() && packet.header.is_short() {
2748                    // TODO: SHOULD buffer these to improve reordering tolerance.
2749                    trace!("dropping short packet during handshake");
2750                    return;
2751                } else {
2752                    if let Header::Initial(InitialHeader { ref token, .. }) = packet.header {
2753                        if let State::Handshake(ref hs) = self.state {
2754                            if self.side.is_server() && token != &hs.expected_token {
2755                                // Clients must send the same retry token in every Initial. Initial
2756                                // packets can be spoofed, so we discard rather than killing the
2757                                // connection.
2758                                warn!("discarding Initial with invalid retry token");
2759                                return;
2760                            }
2761                        }
2762                    }
2763
2764                    if !self.state.is_closed() {
2765                        let spin = match packet.header {
2766                            Header::Short { spin, .. } => spin,
2767                            _ => false,
2768                        };
2769                        self.on_packet_authenticated(
2770                            now,
2771                            packet.header.space(),
2772                            ecn,
2773                            number,
2774                            spin,
2775                            packet.header.is_1rtt(),
2776                        );
2777                    }
2778
2779                    self.process_decrypted_packet(now, remote, number, packet)
2780                }
2781            }
2782        };
2783
2784        // State transitions for error cases
2785        if let Err(conn_err) = result {
2786            self.error = Some(conn_err.clone());
2787            self.state = match conn_err {
2788                ConnectionError::ApplicationClosed(reason) => State::closed(reason),
2789                ConnectionError::ConnectionClosed(reason) => State::closed(reason),
2790                ConnectionError::Reset
2791                | ConnectionError::TransportError(TransportError {
2792                    code: TransportErrorCode::AEAD_LIMIT_REACHED,
2793                    ..
2794                }) => State::Drained,
2795                ConnectionError::TimedOut => {
2796                    unreachable!("timeouts aren't generated by packet processing");
2797                }
2798                ConnectionError::TransportError(err) => {
2799                    debug!("closing connection due to transport error: {}", err);
2800                    State::closed(err)
2801                }
2802                ConnectionError::VersionMismatch => State::Draining,
2803                ConnectionError::LocallyClosed => {
2804                    unreachable!("LocallyClosed isn't generated by packet processing");
2805                }
2806                ConnectionError::CidsExhausted => {
2807                    unreachable!("CidsExhausted isn't generated by packet processing");
2808                }
2809            };
2810        }
2811
2812        if !was_closed && self.state.is_closed() {
2813            self.close_common();
2814            if !self.state.is_drained() {
2815                self.set_close_timer(now);
2816            }
2817        }
2818        if !was_drained && self.state.is_drained() {
2819            self.endpoint_events.push_back(EndpointEventInner::Drained);
2820            // Close timer may have been started previously, e.g. if we sent a close and got a
2821            // stateless reset in response
2822            self.timers.stop(Timer::Close);
2823        }
2824
2825        // Transmit CONNECTION_CLOSE if necessary
2826        if let State::Closed(_) = self.state {
2827            self.close = remote == self.path.remote;
2828        }
2829    }
2830
2831    fn process_decrypted_packet(
2832        &mut self,
2833        now: Instant,
2834        remote: SocketAddr,
2835        number: Option<u64>,
2836        packet: Packet,
2837    ) -> Result<(), ConnectionError> {
2838        let state = match self.state {
2839            State::Established => {
2840                match packet.header.space() {
2841                    SpaceId::Data => self.process_payload(now, remote, number.unwrap(), packet)?,
2842                    _ if packet.header.has_frames() => self.process_early_payload(now, packet)?,
2843                    _ => {
2844                        trace!("discarding unexpected pre-handshake packet");
2845                    }
2846                }
2847                return Ok(());
2848            }
2849            State::Closed(_) => {
2850                for result in frame::Iter::new(packet.payload.freeze())? {
2851                    let frame = match result {
2852                        Ok(frame) => frame,
2853                        Err(err) => {
2854                            debug!("frame decoding error: {err:?}");
2855                            continue;
2856                        }
2857                    };
2858
2859                    if let Frame::Padding = frame {
2860                        continue;
2861                    };
2862
2863                    self.stats.frame_rx.record(&frame);
2864
2865                    if let Frame::Close(_) = frame {
2866                        trace!("draining");
2867                        self.state = State::Draining;
2868                        break;
2869                    }
2870                }
2871                return Ok(());
2872            }
2873            State::Draining | State::Drained => return Ok(()),
2874            State::Handshake(ref mut state) => state,
2875        };
2876
2877        match packet.header {
2878            Header::Retry {
2879                src_cid: rem_cid, ..
2880            } => {
2881                if self.side.is_server() {
2882                    return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into());
2883                }
2884
2885                if self.total_authed_packets > 1
2886                            || packet.payload.len() <= 16 // token + 16 byte tag
2887                            || !self.crypto.is_valid_retry(
2888                                &self.rem_cids.active(),
2889                                &packet.header_data,
2890                                &packet.payload,
2891                            )
2892                {
2893                    trace!("discarding invalid Retry");
2894                    // - After the client has received and processed an Initial or Retry
2895                    //   packet from the server, it MUST discard any subsequent Retry
2896                    //   packets that it receives.
2897                    // - A client MUST discard a Retry packet with a zero-length Retry Token
2898                    //   field.
2899                    // - Clients MUST discard Retry packets that have a Retry Integrity Tag
2900                    //   that cannot be validated
2901                    return Ok(());
2902                }
2903
2904                trace!("retrying with CID {}", rem_cid);
2905                let client_hello = state.client_hello.take().unwrap();
2906                self.retry_src_cid = Some(rem_cid);
2907                self.rem_cids.update_initial_cid(rem_cid);
2908                self.rem_handshake_cid = rem_cid;
2909
2910                let space = &mut self.spaces[SpaceId::Initial];
2911                if let Some(info) = space.take(0) {
2912                    self.on_packet_acked(now, 0, info);
2913                };
2914
2915                self.discard_space(now, SpaceId::Initial); // Make sure we clean up after any retransmitted Initials
2916                self.spaces[SpaceId::Initial] = PacketSpace {
2917                    crypto: Some(self.crypto.initial_keys(&rem_cid, self.side.side())),
2918                    next_packet_number: self.spaces[SpaceId::Initial].next_packet_number,
2919                    crypto_offset: client_hello.len() as u64,
2920                    ..PacketSpace::new(now)
2921                };
2922                self.spaces[SpaceId::Initial]
2923                    .pending
2924                    .crypto
2925                    .push_back(frame::Crypto {
2926                        offset: 0,
2927                        data: client_hello,
2928                    });
2929
2930                // Retransmit all 0-RTT data
2931                let zero_rtt = mem::take(&mut self.spaces[SpaceId::Data].sent_packets);
2932                for (pn, info) in zero_rtt {
2933                    self.remove_in_flight(pn, &info);
2934                    self.spaces[SpaceId::Data].pending |= info.retransmits;
2935                }
2936                self.streams.retransmit_all_for_0rtt();
2937
2938                let token_len = packet.payload.len() - 16;
2939                let ConnectionSide::Client { ref mut token, .. } = self.side else {
2940                    unreachable!("we already short-circuited if we're server");
2941                };
2942                *token = packet.payload.freeze().split_to(token_len);
2943                self.state = State::Handshake(state::Handshake {
2944                    expected_token: Bytes::new(),
2945                    rem_cid_set: false,
2946                    client_hello: None,
2947                });
2948                Ok(())
2949            }
2950            Header::Long {
2951                ty: LongType::Handshake,
2952                src_cid: rem_cid,
2953                ..
2954            } => {
2955                if rem_cid != self.rem_handshake_cid {
2956                    debug!(
2957                        "discarding packet with mismatched remote CID: {} != {}",
2958                        self.rem_handshake_cid, rem_cid
2959                    );
2960                    return Ok(());
2961                }
2962                self.on_path_validated();
2963
2964                self.process_early_payload(now, packet)?;
2965                if self.state.is_closed() {
2966                    return Ok(());
2967                }
2968
2969                if self.crypto.is_handshaking() {
2970                    trace!("handshake ongoing");
2971                    return Ok(());
2972                }
2973
2974                if self.side.is_client() {
2975                    // Client-only because server params were set from the client's Initial
2976                    let params =
2977                        self.crypto
2978                            .transport_parameters()?
2979                            .ok_or_else(|| TransportError {
2980                                code: TransportErrorCode::crypto(0x6d),
2981                                frame: None,
2982                                reason: "transport parameters missing".into(),
2983                            })?;
2984
2985                    if self.has_0rtt() {
2986                        if !self.crypto.early_data_accepted().unwrap() {
2987                            debug_assert!(self.side.is_client());
2988                            debug!("0-RTT rejected");
2989                            self.accepted_0rtt = false;
2990                            self.streams.zero_rtt_rejected();
2991
2992                            // Discard already-queued frames
2993                            self.spaces[SpaceId::Data].pending = Retransmits::default();
2994
2995                            // Discard 0-RTT packets
2996                            let sent_packets =
2997                                mem::take(&mut self.spaces[SpaceId::Data].sent_packets);
2998                            for (pn, packet) in sent_packets {
2999                                self.remove_in_flight(pn, &packet);
3000                            }
3001                        } else {
3002                            self.accepted_0rtt = true;
3003                            params.validate_resumption_from(&self.peer_params)?;
3004                        }
3005                    }
3006                    if let Some(token) = params.stateless_reset_token {
3007                        self.endpoint_events
3008                            .push_back(EndpointEventInner::ResetToken(self.path.remote, token));
3009                    }
3010                    self.handle_peer_params(params)?;
3011                    self.issue_first_cids(now);
3012                } else {
3013                    // Server-only
3014                    self.spaces[SpaceId::Data].pending.handshake_done = true;
3015                    self.discard_space(now, SpaceId::Handshake);
3016                }
3017
3018                self.events.push_back(Event::Connected);
3019                self.state = State::Established;
3020                trace!("established");
3021                Ok(())
3022            }
3023            Header::Initial(InitialHeader {
3024                src_cid: rem_cid, ..
3025            }) => {
3026                if !state.rem_cid_set {
3027                    trace!("switching remote CID to {}", rem_cid);
3028                    let mut state = state.clone();
3029                    self.rem_cids.update_initial_cid(rem_cid);
3030                    self.rem_handshake_cid = rem_cid;
3031                    self.orig_rem_cid = rem_cid;
3032                    state.rem_cid_set = true;
3033                    self.state = State::Handshake(state);
3034                } else if rem_cid != self.rem_handshake_cid {
3035                    debug!(
3036                        "discarding packet with mismatched remote CID: {} != {}",
3037                        self.rem_handshake_cid, rem_cid
3038                    );
3039                    return Ok(());
3040                }
3041
3042                let starting_space = self.highest_space;
3043                self.process_early_payload(now, packet)?;
3044
3045                if self.side.is_server()
3046                    && starting_space == SpaceId::Initial
3047                    && self.highest_space != SpaceId::Initial
3048                {
3049                    let params =
3050                        self.crypto
3051                            .transport_parameters()?
3052                            .ok_or_else(|| TransportError {
3053                                code: TransportErrorCode::crypto(0x6d),
3054                                frame: None,
3055                                reason: "transport parameters missing".into(),
3056                            })?;
3057                    self.handle_peer_params(params)?;
3058                    self.issue_first_cids(now);
3059                    self.init_0rtt();
3060                }
3061                Ok(())
3062            }
3063            Header::Long {
3064                ty: LongType::ZeroRtt,
3065                ..
3066            } => {
3067                self.process_payload(now, remote, number.unwrap(), packet)?;
3068                Ok(())
3069            }
3070            Header::VersionNegotiate { .. } => {
3071                if self.total_authed_packets > 1 {
3072                    return Ok(());
3073                }
3074                let supported = packet
3075                    .payload
3076                    .chunks(4)
3077                    .any(|x| match <[u8; 4]>::try_from(x) {
3078                        Ok(version) => self.version == u32::from_be_bytes(version),
3079                        Err(_) => false,
3080                    });
3081                if supported {
3082                    return Ok(());
3083                }
3084                debug!("remote doesn't support our version");
3085                Err(ConnectionError::VersionMismatch)
3086            }
3087            Header::Short { .. } => unreachable!(
3088                "short packets received during handshake are discarded in handle_packet"
3089            ),
3090        }
3091    }
3092
3093    /// Process an Initial or Handshake packet payload
3094    fn process_early_payload(
3095        &mut self,
3096        now: Instant,
3097        packet: Packet,
3098    ) -> Result<(), TransportError> {
3099        debug_assert_ne!(packet.header.space(), SpaceId::Data);
3100        let payload_len = packet.payload.len();
3101        let mut ack_eliciting = false;
3102        for result in frame::Iter::new(packet.payload.freeze())? {
3103            let frame = result?;
3104            let span = match frame {
3105                Frame::Padding => continue,
3106                _ => Some(trace_span!("frame", ty = %frame.ty())),
3107            };
3108
3109            self.stats.frame_rx.record(&frame);
3110
3111            let _guard = span.as_ref().map(|x| x.enter());
3112            ack_eliciting |= frame.is_ack_eliciting();
3113
3114            // Process frames
3115            match frame {
3116                Frame::Padding | Frame::Ping => {}
3117                Frame::Crypto(frame) => {
3118                    self.read_crypto(packet.header.space(), &frame, payload_len)?;
3119                }
3120                Frame::Ack(ack) => {
3121                    self.on_ack_received(now, packet.header.space(), ack)?;
3122                }
3123                Frame::Close(reason) => {
3124                    self.error = Some(reason.into());
3125                    self.state = State::Draining;
3126                    return Ok(());
3127                }
3128                _ => {
3129                    let mut err =
3130                        TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake");
3131                    err.frame = Some(frame.ty());
3132                    return Err(err);
3133                }
3134            }
3135        }
3136
3137        if ack_eliciting {
3138            // In the initial and handshake spaces, ACKs must be sent immediately
3139            self.spaces[packet.header.space()]
3140                .pending_acks
3141                .set_immediate_ack_required();
3142        }
3143
3144        self.write_crypto();
3145        Ok(())
3146    }
3147
3148    fn process_payload(
3149        &mut self,
3150        now: Instant,
3151        remote: SocketAddr,
3152        number: u64,
3153        packet: Packet,
3154    ) -> Result<(), TransportError> {
3155        let payload = packet.payload.freeze();
3156        let mut is_probing_packet = true;
3157        let mut close = None;
3158        let payload_len = payload.len();
3159        let mut ack_eliciting = false;
3160        for result in frame::Iter::new(payload)? {
3161            let frame = result?;
3162            let span = match frame {
3163                Frame::Padding => continue,
3164                _ => Some(trace_span!("frame", ty = %frame.ty())),
3165            };
3166
3167            self.stats.frame_rx.record(&frame);
3168            // Crypto, Stream and Datagram frames are special cased in order no pollute
3169            // the log with payload data
3170            match &frame {
3171                Frame::Crypto(f) => {
3172                    trace!(offset = f.offset, len = f.data.len(), "got crypto frame");
3173                }
3174                Frame::Stream(f) => {
3175                    trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got stream frame");
3176                }
3177                Frame::Datagram(f) => {
3178                    trace!(len = f.data.len(), "got datagram frame");
3179                }
3180                f => {
3181                    trace!("got frame {:?}", f);
3182                }
3183            }
3184
3185            let _guard = span.as_ref().map(|x| x.enter());
3186            if packet.header.is_0rtt() {
3187                match frame {
3188                    Frame::Crypto(_) | Frame::Close(Close::Application(_)) => {
3189                        return Err(TransportError::PROTOCOL_VIOLATION(
3190                            "illegal frame type in 0-RTT",
3191                        ));
3192                    }
3193                    _ => {}
3194                }
3195            }
3196            ack_eliciting |= frame.is_ack_eliciting();
3197
3198            // Check whether this could be a probing packet
3199            match frame {
3200                Frame::Padding
3201                | Frame::PathChallenge(_)
3202                | Frame::PathResponse(_)
3203                | Frame::NewConnectionId(_) => {}
3204                _ => {
3205                    is_probing_packet = false;
3206                }
3207            }
3208            match frame {
3209                Frame::Crypto(frame) => {
3210                    self.read_crypto(SpaceId::Data, &frame, payload_len)?;
3211                }
3212                Frame::Stream(frame) => {
3213                    if self.streams.received(frame, payload_len)?.should_transmit() {
3214                        self.spaces[SpaceId::Data].pending.max_data = true;
3215                    }
3216                }
3217                Frame::Ack(ack) => {
3218                    self.on_ack_received(now, SpaceId::Data, ack)?;
3219                }
3220                Frame::Padding | Frame::Ping => {}
3221                Frame::Close(reason) => {
3222                    close = Some(reason);
3223                }
3224                Frame::PathChallenge(token) => {
3225                    self.path_responses.push(number, token, remote);
3226                    if remote == self.path.remote {
3227                        // PATH_CHALLENGE on active path, possible off-path packet forwarding
3228                        // attack. Send a non-probing packet to recover the active path.
3229                        match self.peer_supports_ack_frequency() {
3230                            true => self.immediate_ack(),
3231                            false => self.ping(),
3232                        }
3233                    }
3234                }
3235                Frame::PathResponse(token) => {
3236                    if self.path.challenge == Some(token) && remote == self.path.remote {
3237                        trace!("new path validated");
3238                        self.timers.stop(Timer::PathValidation);
3239                        self.path.challenge = None;
3240                        self.path.validated = true;
3241                        if let Some((_, ref mut prev_path)) = self.prev_path {
3242                            prev_path.challenge = None;
3243                            prev_path.challenge_pending = false;
3244                        }
3245                        self.on_path_validated();
3246                    } else if let Some(nat_traversal) = &mut self.nat_traversal {
3247                        // Check if this is a response to NAT traversal PATH_CHALLENGE
3248                        match nat_traversal.handle_validation_success(remote, token, now) {
3249                            Ok(sequence) => {
3250                                trace!(
3251                                    "NAT traversal candidate {} validated for sequence {}",
3252                                    remote, sequence
3253                                );
3254
3255                                // Check if this was part of a coordination round
3256                                if nat_traversal.handle_coordination_success(remote, now) {
3257                                    trace!("Coordination succeeded via {}", remote);
3258
3259                                    // Check if we should migrate to this better path
3260                                    let can_migrate = match &self.side {
3261                                        ConnectionSide::Client { .. } => true, // Clients can always migrate
3262                                        ConnectionSide::Server { server_config } => {
3263                                            server_config.migration
3264                                        }
3265                                    };
3266
3267                                    if can_migrate {
3268                                        // Get the best paths to see if this new one is better
3269                                        let best_pairs = nat_traversal.get_best_succeeded_pairs();
3270                                        if let Some(best) = best_pairs.first() {
3271                                            if best.remote_addr == remote
3272                                                && best.remote_addr != self.path.remote
3273                                            {
3274                                                debug!(
3275                                                    "NAT traversal found better path, initiating migration"
3276                                                );
3277                                                // Trigger migration to the better NAT-traversed path
3278                                                if let Err(e) =
3279                                                    self.migrate_to_nat_traversal_path(now)
3280                                                {
3281                                                    warn!(
3282                                                        "Failed to migrate to NAT traversal path: {:?}",
3283                                                        e
3284                                                    );
3285                                                }
3286                                            }
3287                                        }
3288                                    }
3289                                } else {
3290                                    // Mark the candidate pair as succeeded for regular validation
3291                                    if nat_traversal.mark_pair_succeeded(remote) {
3292                                        trace!("NAT traversal pair succeeded for {}", remote);
3293                                    }
3294                                }
3295                            }
3296                            Err(NatTraversalError::ChallengeMismatch) => {
3297                                debug!(
3298                                    "PATH_RESPONSE challenge mismatch for NAT candidate {}",
3299                                    remote
3300                                );
3301                            }
3302                            Err(e) => {
3303                                debug!("NAT traversal validation error: {}", e);
3304                            }
3305                        }
3306                    } else {
3307                        debug!(token, "ignoring invalid PATH_RESPONSE");
3308                    }
3309                }
3310                Frame::MaxData(bytes) => {
3311                    self.streams.received_max_data(bytes);
3312                }
3313                Frame::MaxStreamData { id, offset } => {
3314                    self.streams.received_max_stream_data(id, offset)?;
3315                }
3316                Frame::MaxStreams { dir, count } => {
3317                    self.streams.received_max_streams(dir, count)?;
3318                }
3319                Frame::ResetStream(frame) => {
3320                    if self.streams.received_reset(frame)?.should_transmit() {
3321                        self.spaces[SpaceId::Data].pending.max_data = true;
3322                    }
3323                }
3324                Frame::DataBlocked { offset } => {
3325                    debug!(offset, "peer claims to be blocked at connection level");
3326                }
3327                Frame::StreamDataBlocked { id, offset } => {
3328                    if id.initiator() == self.side.side() && id.dir() == Dir::Uni {
3329                        debug!("got STREAM_DATA_BLOCKED on send-only {}", id);
3330                        return Err(TransportError::STREAM_STATE_ERROR(
3331                            "STREAM_DATA_BLOCKED on send-only stream",
3332                        ));
3333                    }
3334                    debug!(
3335                        stream = %id,
3336                        offset, "peer claims to be blocked at stream level"
3337                    );
3338                }
3339                Frame::StreamsBlocked { dir, limit } => {
3340                    if limit > MAX_STREAM_COUNT {
3341                        return Err(TransportError::FRAME_ENCODING_ERROR(
3342                            "unrepresentable stream limit",
3343                        ));
3344                    }
3345                    debug!(
3346                        "peer claims to be blocked opening more than {} {} streams",
3347                        limit, dir
3348                    );
3349                }
3350                Frame::StopSending(frame::StopSending { id, error_code }) => {
3351                    if id.initiator() != self.side.side() {
3352                        if id.dir() == Dir::Uni {
3353                            debug!("got STOP_SENDING on recv-only {}", id);
3354                            return Err(TransportError::STREAM_STATE_ERROR(
3355                                "STOP_SENDING on recv-only stream",
3356                            ));
3357                        }
3358                    } else if self.streams.is_local_unopened(id) {
3359                        return Err(TransportError::STREAM_STATE_ERROR(
3360                            "STOP_SENDING on unopened stream",
3361                        ));
3362                    }
3363                    self.streams.received_stop_sending(id, error_code);
3364                }
3365                Frame::RetireConnectionId { sequence } => {
3366                    let allow_more_cids = self
3367                        .local_cid_state
3368                        .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?;
3369                    self.endpoint_events
3370                        .push_back(EndpointEventInner::RetireConnectionId(
3371                            now,
3372                            sequence,
3373                            allow_more_cids,
3374                        ));
3375                }
3376                Frame::NewConnectionId(frame) => {
3377                    trace!(
3378                        sequence = frame.sequence,
3379                        id = %frame.id,
3380                        retire_prior_to = frame.retire_prior_to,
3381                    );
3382                    if self.rem_cids.active().is_empty() {
3383                        return Err(TransportError::PROTOCOL_VIOLATION(
3384                            "NEW_CONNECTION_ID when CIDs aren't in use",
3385                        ));
3386                    }
3387                    if frame.retire_prior_to > frame.sequence {
3388                        return Err(TransportError::PROTOCOL_VIOLATION(
3389                            "NEW_CONNECTION_ID retiring unissued CIDs",
3390                        ));
3391                    }
3392
3393                    use crate::cid_queue::InsertError;
3394                    match self.rem_cids.insert(frame) {
3395                        Ok(None) => {}
3396                        Ok(Some((retired, reset_token))) => {
3397                            let pending_retired =
3398                                &mut self.spaces[SpaceId::Data].pending.retire_cids;
3399                            /// Ensure `pending_retired` cannot grow without bound. Limit is
3400                            /// somewhat arbitrary but very permissive.
3401                            const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10;
3402                            // We don't bother counting in-flight frames because those are bounded
3403                            // by congestion control.
3404                            if (pending_retired.len() as u64)
3405                                .saturating_add(retired.end.saturating_sub(retired.start))
3406                                > MAX_PENDING_RETIRED_CIDS
3407                            {
3408                                return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(
3409                                    "queued too many retired CIDs",
3410                                ));
3411                            }
3412                            pending_retired.extend(retired);
3413                            self.set_reset_token(reset_token);
3414                        }
3415                        Err(InsertError::ExceedsLimit) => {
3416                            return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(""));
3417                        }
3418                        Err(InsertError::Retired) => {
3419                            trace!("discarding already-retired");
3420                            // RETIRE_CONNECTION_ID might not have been previously sent if e.g. a
3421                            // range of connection IDs larger than the active connection ID limit
3422                            // was retired all at once via retire_prior_to.
3423                            self.spaces[SpaceId::Data]
3424                                .pending
3425                                .retire_cids
3426                                .push(frame.sequence);
3427                            continue;
3428                        }
3429                    };
3430
3431                    if self.side.is_server() && self.rem_cids.active_seq() == 0 {
3432                        // We're a server still using the initial remote CID for the client, so
3433                        // let's switch immediately to enable clientside stateless resets.
3434                        self.update_rem_cid();
3435                    }
3436                }
3437                Frame::NewToken(NewToken { token }) => {
3438                    let ConnectionSide::Client {
3439                        token_store,
3440                        server_name,
3441                        ..
3442                    } = &self.side
3443                    else {
3444                        return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN"));
3445                    };
3446                    if token.is_empty() {
3447                        return Err(TransportError::FRAME_ENCODING_ERROR("empty token"));
3448                    }
3449                    trace!("got new token");
3450                    token_store.insert(server_name, token);
3451                }
3452                Frame::Datagram(datagram) => {
3453                    if self
3454                        .datagrams
3455                        .received(datagram, &self.config.datagram_receive_buffer_size)?
3456                    {
3457                        self.events.push_back(Event::DatagramReceived);
3458                    }
3459                }
3460                Frame::AckFrequency(ack_frequency) => {
3461                    // This frame can only be sent in the Data space
3462                    let space = &mut self.spaces[SpaceId::Data];
3463
3464                    if !self
3465                        .ack_frequency
3466                        .ack_frequency_received(&ack_frequency, &mut space.pending_acks)?
3467                    {
3468                        // The AckFrequency frame is stale (we have already received a more recent one)
3469                        continue;
3470                    }
3471
3472                    // Our `max_ack_delay` has been updated, so we may need to adjust its associated
3473                    // timeout
3474                    if let Some(timeout) = space
3475                        .pending_acks
3476                        .max_ack_delay_timeout(self.ack_frequency.max_ack_delay)
3477                    {
3478                        self.timers.set(Timer::MaxAckDelay, timeout);
3479                    }
3480                }
3481                Frame::ImmediateAck => {
3482                    // This frame can only be sent in the Data space
3483                    self.spaces[SpaceId::Data]
3484                        .pending_acks
3485                        .set_immediate_ack_required();
3486                }
3487                Frame::HandshakeDone => {
3488                    if self.side.is_server() {
3489                        return Err(TransportError::PROTOCOL_VIOLATION(
3490                            "client sent HANDSHAKE_DONE",
3491                        ));
3492                    }
3493                    if self.spaces[SpaceId::Handshake].crypto.is_some() {
3494                        self.discard_space(now, SpaceId::Handshake);
3495                    }
3496                }
3497                Frame::AddAddress(add_address) => {
3498                    self.handle_add_address(&add_address, now)?;
3499                }
3500                Frame::PunchMeNow(punch_me_now) => {
3501                    self.handle_punch_me_now(&punch_me_now, now)?;
3502                }
3503                Frame::RemoveAddress(remove_address) => {
3504                    self.handle_remove_address(&remove_address)?;
3505                }
3506                Frame::ObservedAddress(observed_address) => {
3507                    self.handle_observed_address_frame(&observed_address, now)?;
3508                }
3509            }
3510        }
3511
3512        let space = &mut self.spaces[SpaceId::Data];
3513        if space
3514            .pending_acks
3515            .packet_received(now, number, ack_eliciting, &space.dedup)
3516        {
3517            self.timers
3518                .set(Timer::MaxAckDelay, now + self.ack_frequency.max_ack_delay);
3519        }
3520
3521        // Issue stream ID credit due to ACKs of outgoing finish/resets and incoming finish/resets
3522        // on stopped streams. Incoming finishes/resets on open streams are not handled here as they
3523        // are only freed, and hence only issue credit, once the application has been notified
3524        // during a read on the stream.
3525        let pending = &mut self.spaces[SpaceId::Data].pending;
3526        self.streams.queue_max_stream_id(pending);
3527
3528        if let Some(reason) = close {
3529            self.error = Some(reason.into());
3530            self.state = State::Draining;
3531            self.close = true;
3532        }
3533
3534        if remote != self.path.remote
3535            && !is_probing_packet
3536            && number == self.spaces[SpaceId::Data].rx_packet
3537        {
3538            let ConnectionSide::Server { ref server_config } = self.side else {
3539                panic!("packets from unknown remote should be dropped by clients");
3540            };
3541            debug_assert!(
3542                server_config.migration,
3543                "migration-initiating packets should have been dropped immediately"
3544            );
3545            self.migrate(now, remote);
3546            // Break linkability, if possible
3547            self.update_rem_cid();
3548            self.spin = false;
3549        }
3550
3551        Ok(())
3552    }
3553
3554    fn migrate(&mut self, now: Instant, remote: SocketAddr) {
3555        trace!(%remote, "migration initiated");
3556        // Reset rtt/congestion state for new path unless it looks like a NAT rebinding.
3557        // Note that the congestion window will not grow until validation terminates. Helps mitigate
3558        // amplification attacks performed by spoofing source addresses.
3559        let mut new_path = if remote.is_ipv4() && remote.ip() == self.path.remote.ip() {
3560            PathData::from_previous(remote, &self.path, now)
3561        } else {
3562            let peer_max_udp_payload_size =
3563                u16::try_from(self.peer_params.max_udp_payload_size.into_inner())
3564                    .unwrap_or(u16::MAX);
3565            PathData::new(
3566                remote,
3567                self.allow_mtud,
3568                Some(peer_max_udp_payload_size),
3569                now,
3570                &self.config,
3571            )
3572        };
3573        new_path.challenge = Some(self.rng.gen());
3574        new_path.challenge_pending = true;
3575        let prev_pto = self.pto(SpaceId::Data);
3576
3577        let mut prev = mem::replace(&mut self.path, new_path);
3578        // Don't clobber the original path if the previous one hasn't been validated yet
3579        if prev.challenge.is_none() {
3580            prev.challenge = Some(self.rng.gen());
3581            prev.challenge_pending = true;
3582            // We haven't updated the remote CID yet, this captures the remote CID we were using on
3583            // the previous path.
3584            self.prev_path = Some((self.rem_cids.active(), prev));
3585        }
3586
3587        self.timers.set(
3588            Timer::PathValidation,
3589            now + 3 * cmp::max(self.pto(SpaceId::Data), prev_pto),
3590        );
3591    }
3592
3593    /// Handle a change in the local address, i.e. an active migration
3594    pub fn local_address_changed(&mut self) {
3595        self.update_rem_cid();
3596        self.ping();
3597    }
3598
3599    /// Migrate to a better path discovered through NAT traversal
3600    pub fn migrate_to_nat_traversal_path(&mut self, now: Instant) -> Result<(), TransportError> {
3601        // Extract necessary data before mutable operations
3602        let (remote_addr, local_addr) = {
3603            let nat_state = self
3604                .nat_traversal
3605                .as_ref()
3606                .ok_or_else(|| TransportError::PROTOCOL_VIOLATION("NAT traversal not enabled"))?;
3607
3608            // Get the best validated NAT traversal path
3609            let best_pairs = nat_state.get_best_succeeded_pairs();
3610            if best_pairs.is_empty() {
3611                return Err(TransportError::PROTOCOL_VIOLATION(
3612                    "No validated NAT traversal paths",
3613                ));
3614            }
3615
3616            // Select the best path (highest priority that's different from current)
3617            let best_path = best_pairs
3618                .iter()
3619                .find(|pair| pair.remote_addr != self.path.remote)
3620                .or_else(|| best_pairs.first());
3621
3622            let best_path = best_path.ok_or_else(|| {
3623                TransportError::PROTOCOL_VIOLATION("No suitable NAT traversal path")
3624            })?;
3625
3626            debug!(
3627                "Migrating to NAT traversal path: {} -> {} (priority: {})",
3628                self.path.remote, best_path.remote_addr, best_path.priority
3629            );
3630
3631            (best_path.remote_addr, best_path.local_addr)
3632        };
3633
3634        // Perform the migration
3635        self.migrate(now, remote_addr);
3636
3637        // Update local address if needed
3638        if local_addr != SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED), 0) {
3639            self.local_ip = Some(local_addr.ip());
3640        }
3641
3642        // Queue a PATH_CHALLENGE to confirm the new path
3643        self.path.challenge_pending = true;
3644
3645        Ok(())
3646    }
3647
3648    /// Switch to a previously unused remote connection ID, if possible
3649    fn update_rem_cid(&mut self) {
3650        let (reset_token, retired) = match self.rem_cids.next() {
3651            Some(x) => x,
3652            None => return,
3653        };
3654
3655        // Retire the current remote CID and any CIDs we had to skip.
3656        self.spaces[SpaceId::Data]
3657            .pending
3658            .retire_cids
3659            .extend(retired);
3660        self.set_reset_token(reset_token);
3661    }
3662
3663    fn set_reset_token(&mut self, reset_token: ResetToken) {
3664        self.endpoint_events
3665            .push_back(EndpointEventInner::ResetToken(
3666                self.path.remote,
3667                reset_token,
3668            ));
3669        self.peer_params.stateless_reset_token = Some(reset_token);
3670    }
3671
3672    /// Issue an initial set of connection IDs to the peer upon connection
3673    fn issue_first_cids(&mut self, now: Instant) {
3674        if self.local_cid_state.cid_len() == 0 {
3675            return;
3676        }
3677
3678        // Subtract 1 to account for the CID we supplied while handshaking
3679        let mut n = self.peer_params.issue_cids_limit() - 1;
3680        if let ConnectionSide::Server { server_config } = &self.side {
3681            if server_config.has_preferred_address() {
3682                // We also sent a CID in the transport parameters
3683                n -= 1;
3684            }
3685        }
3686        self.endpoint_events
3687            .push_back(EndpointEventInner::NeedIdentifiers(now, n));
3688    }
3689
3690    fn populate_packet(
3691        &mut self,
3692        now: Instant,
3693        space_id: SpaceId,
3694        buf: &mut Vec<u8>,
3695        max_size: usize,
3696        pn: u64,
3697    ) -> SentFrames {
3698        let mut sent = SentFrames::default();
3699        let space = &mut self.spaces[space_id];
3700        let is_0rtt = space_id == SpaceId::Data && space.crypto.is_none();
3701        space.pending_acks.maybe_ack_non_eliciting();
3702
3703        // HANDSHAKE_DONE
3704        if !is_0rtt && mem::replace(&mut space.pending.handshake_done, false) {
3705            buf.write(frame::FrameType::HANDSHAKE_DONE);
3706            sent.retransmits.get_or_create().handshake_done = true;
3707            // This is just a u8 counter and the frame is typically just sent once
3708            self.stats.frame_tx.handshake_done =
3709                self.stats.frame_tx.handshake_done.saturating_add(1);
3710        }
3711
3712        // PING
3713        if mem::replace(&mut space.ping_pending, false) {
3714            trace!("PING");
3715            buf.write(frame::FrameType::PING);
3716            sent.non_retransmits = true;
3717            self.stats.frame_tx.ping += 1;
3718        }
3719
3720        // IMMEDIATE_ACK
3721        if mem::replace(&mut space.immediate_ack_pending, false) {
3722            trace!("IMMEDIATE_ACK");
3723            buf.write(frame::FrameType::IMMEDIATE_ACK);
3724            sent.non_retransmits = true;
3725            self.stats.frame_tx.immediate_ack += 1;
3726        }
3727
3728        // ACK
3729        if space.pending_acks.can_send() {
3730            Self::populate_acks(
3731                now,
3732                self.receiving_ecn,
3733                &mut sent,
3734                space,
3735                buf,
3736                &mut self.stats,
3737            );
3738        }
3739
3740        // ACK_FREQUENCY
3741        if mem::replace(&mut space.pending.ack_frequency, false) {
3742            let sequence_number = self.ack_frequency.next_sequence_number();
3743
3744            // Safe to unwrap because this is always provided when ACK frequency is enabled
3745            let config = self.config.ack_frequency_config.as_ref().unwrap();
3746
3747            // Ensure the delay is within bounds to avoid a PROTOCOL_VIOLATION error
3748            let max_ack_delay = self.ack_frequency.candidate_max_ack_delay(
3749                self.path.rtt.get(),
3750                config,
3751                &self.peer_params,
3752            );
3753
3754            trace!(?max_ack_delay, "ACK_FREQUENCY");
3755
3756            frame::AckFrequency {
3757                sequence: sequence_number,
3758                ack_eliciting_threshold: config.ack_eliciting_threshold,
3759                request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX),
3760                reordering_threshold: config.reordering_threshold,
3761            }
3762            .encode(buf);
3763
3764            sent.retransmits.get_or_create().ack_frequency = true;
3765
3766            self.ack_frequency.ack_frequency_sent(pn, max_ack_delay);
3767            self.stats.frame_tx.ack_frequency += 1;
3768        }
3769
3770        // PATH_CHALLENGE
3771        if buf.len() + 9 < max_size && space_id == SpaceId::Data {
3772            // Transmit challenges with every outgoing frame on an unvalidated path
3773            if let Some(token) = self.path.challenge {
3774                // But only send a packet solely for that purpose at most once
3775                self.path.challenge_pending = false;
3776                sent.non_retransmits = true;
3777                sent.requires_padding = true;
3778                trace!("PATH_CHALLENGE {:08x}", token);
3779                buf.write(frame::FrameType::PATH_CHALLENGE);
3780                buf.write(token);
3781                self.stats.frame_tx.path_challenge += 1;
3782            }
3783
3784            // TODO: Send NAT traversal PATH_CHALLENGE frames
3785            // Currently, the packet sending infrastructure only supports sending to the
3786            // primary path (self.path.remote). To properly support NAT traversal, we need
3787            // to modify poll_transmit and the packet building logic to generate packets
3788            // for multiple destination addresses. For now, NAT traversal challenges are
3789            // queued in self.nat_traversal_challenges but not yet sent.
3790            // This will be implemented in a future phase when we add multi-destination
3791            // packet support to the endpoint.
3792        }
3793
3794        // PATH_RESPONSE
3795        if buf.len() + 9 < max_size && space_id == SpaceId::Data {
3796            if let Some(token) = self.path_responses.pop_on_path(self.path.remote) {
3797                sent.non_retransmits = true;
3798                sent.requires_padding = true;
3799                trace!("PATH_RESPONSE {:08x}", token);
3800                buf.write(frame::FrameType::PATH_RESPONSE);
3801                buf.write(token);
3802                self.stats.frame_tx.path_response += 1;
3803            }
3804        }
3805
3806        // CRYPTO
3807        while buf.len() + frame::Crypto::SIZE_BOUND < max_size && !is_0rtt {
3808            let mut frame = match space.pending.crypto.pop_front() {
3809                Some(x) => x,
3810                None => break,
3811            };
3812
3813            // Calculate the maximum amount of crypto data we can store in the buffer.
3814            // Since the offset is known, we can reserve the exact size required to encode it.
3815            // For length we reserve 2bytes which allows to encode up to 2^14,
3816            // which is more than what fits into normally sized QUIC frames.
3817            let max_crypto_data_size = max_size
3818                - buf.len()
3819                - 1 // Frame Type
3820                - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) })
3821                - 2; // Maximum encoded length for frame size, given we send less than 2^14 bytes
3822
3823            let len = frame
3824                .data
3825                .len()
3826                .min(2usize.pow(14) - 1)
3827                .min(max_crypto_data_size);
3828
3829            let data = frame.data.split_to(len);
3830            let truncated = frame::Crypto {
3831                offset: frame.offset,
3832                data,
3833            };
3834            trace!(
3835                "CRYPTO: off {} len {}",
3836                truncated.offset,
3837                truncated.data.len()
3838            );
3839            truncated.encode(buf);
3840            self.stats.frame_tx.crypto += 1;
3841            sent.retransmits.get_or_create().crypto.push_back(truncated);
3842            if !frame.data.is_empty() {
3843                frame.offset += len as u64;
3844                space.pending.crypto.push_front(frame);
3845            }
3846        }
3847
3848        if space_id == SpaceId::Data {
3849            self.streams.write_control_frames(
3850                buf,
3851                &mut space.pending,
3852                &mut sent.retransmits,
3853                &mut self.stats.frame_tx,
3854                max_size,
3855            );
3856        }
3857
3858        // NEW_CONNECTION_ID
3859        while buf.len() + 44 < max_size {
3860            let issued = match space.pending.new_cids.pop() {
3861                Some(x) => x,
3862                None => break,
3863            };
3864            trace!(
3865                sequence = issued.sequence,
3866                id = %issued.id,
3867                "NEW_CONNECTION_ID"
3868            );
3869            frame::NewConnectionId {
3870                sequence: issued.sequence,
3871                retire_prior_to: self.local_cid_state.retire_prior_to(),
3872                id: issued.id,
3873                reset_token: issued.reset_token,
3874            }
3875            .encode(buf);
3876            sent.retransmits.get_or_create().new_cids.push(issued);
3877            self.stats.frame_tx.new_connection_id += 1;
3878        }
3879
3880        // RETIRE_CONNECTION_ID
3881        while buf.len() + frame::RETIRE_CONNECTION_ID_SIZE_BOUND < max_size {
3882            let seq = match space.pending.retire_cids.pop() {
3883                Some(x) => x,
3884                None => break,
3885            };
3886            trace!(sequence = seq, "RETIRE_CONNECTION_ID");
3887            buf.write(frame::FrameType::RETIRE_CONNECTION_ID);
3888            buf.write_var(seq);
3889            sent.retransmits.get_or_create().retire_cids.push(seq);
3890            self.stats.frame_tx.retire_connection_id += 1;
3891        }
3892
3893        // DATAGRAM
3894        let mut sent_datagrams = false;
3895        while buf.len() + Datagram::SIZE_BOUND < max_size && space_id == SpaceId::Data {
3896            match self.datagrams.write(buf, max_size) {
3897                true => {
3898                    sent_datagrams = true;
3899                    sent.non_retransmits = true;
3900                    self.stats.frame_tx.datagram += 1;
3901                }
3902                false => break,
3903            }
3904        }
3905        if self.datagrams.send_blocked && sent_datagrams {
3906            self.events.push_back(Event::DatagramsUnblocked);
3907            self.datagrams.send_blocked = false;
3908        }
3909
3910        // NEW_TOKEN
3911        while let Some(remote_addr) = space.pending.new_tokens.pop() {
3912            debug_assert_eq!(space_id, SpaceId::Data);
3913            let ConnectionSide::Server { server_config } = &self.side else {
3914                panic!("NEW_TOKEN frames should not be enqueued by clients");
3915            };
3916
3917            if remote_addr != self.path.remote {
3918                // NEW_TOKEN frames contain tokens bound to a client's IP address, and are only
3919                // useful if used from the same IP address.  Thus, we abandon enqueued NEW_TOKEN
3920                // frames upon an path change. Instead, when the new path becomes validated,
3921                // NEW_TOKEN frames may be enqueued for the new path instead.
3922                continue;
3923            }
3924
3925            let token = Token::new(
3926                TokenPayload::Validation {
3927                    ip: remote_addr.ip(),
3928                    issued: server_config.time_source.now(),
3929                },
3930                &mut self.rng,
3931            );
3932            let new_token = NewToken {
3933                token: token.encode(&*server_config.token_key).into(),
3934            };
3935
3936            if buf.len() + new_token.size() >= max_size {
3937                space.pending.new_tokens.push(remote_addr);
3938                break;
3939            }
3940
3941            new_token.encode(buf);
3942            sent.retransmits
3943                .get_or_create()
3944                .new_tokens
3945                .push(remote_addr);
3946            self.stats.frame_tx.new_token += 1;
3947        }
3948
3949        // NAT traversal frames - AddAddress
3950        while buf.len() + frame::AddAddress::SIZE_BOUND < max_size && space_id == SpaceId::Data {
3951            let add_address = match space.pending.add_addresses.pop() {
3952                Some(x) => x,
3953                None => break,
3954            };
3955            trace!(
3956                sequence = %add_address.sequence,
3957                address = %add_address.address,
3958                "ADD_ADDRESS"
3959            );
3960            add_address.encode(buf);
3961            sent.retransmits
3962                .get_or_create()
3963                .add_addresses
3964                .push(add_address);
3965            self.stats.frame_tx.add_address += 1;
3966        }
3967
3968        // NAT traversal frames - PunchMeNow
3969        while buf.len() + frame::PunchMeNow::SIZE_BOUND < max_size && space_id == SpaceId::Data {
3970            let punch_me_now = match space.pending.punch_me_now.pop() {
3971                Some(x) => x,
3972                None => break,
3973            };
3974            trace!(
3975                round = %punch_me_now.round,
3976                target_sequence = %punch_me_now.target_sequence,
3977                "PUNCH_ME_NOW"
3978            );
3979            punch_me_now.encode(buf);
3980            sent.retransmits
3981                .get_or_create()
3982                .punch_me_now
3983                .push(punch_me_now);
3984            self.stats.frame_tx.punch_me_now += 1;
3985        }
3986
3987        // NAT traversal frames - RemoveAddress
3988        while buf.len() + frame::RemoveAddress::SIZE_BOUND < max_size && space_id == SpaceId::Data {
3989            let remove_address = match space.pending.remove_addresses.pop() {
3990                Some(x) => x,
3991                None => break,
3992            };
3993            trace!(
3994                sequence = %remove_address.sequence,
3995                "REMOVE_ADDRESS"
3996            );
3997            remove_address.encode(buf);
3998            sent.retransmits
3999                .get_or_create()
4000                .remove_addresses
4001                .push(remove_address);
4002            self.stats.frame_tx.remove_address += 1;
4003        }
4004
4005        // OBSERVED_ADDRESS frames
4006        while buf.len() + frame::ObservedAddress::SIZE_BOUND < max_size && space_id == SpaceId::Data {
4007            let observed_address = match space.pending.observed_addresses.pop() {
4008                Some(x) => x,
4009                None => break,
4010            };
4011            trace!(
4012                address = %observed_address.address,
4013                "OBSERVED_ADDRESS"
4014            );
4015            observed_address.encode(buf);
4016            sent.retransmits
4017                .get_or_create()
4018                .observed_addresses
4019                .push(observed_address);
4020            self.stats.frame_tx.observed_address += 1;
4021        }
4022
4023        // STREAM
4024        if space_id == SpaceId::Data {
4025            sent.stream_frames =
4026                self.streams
4027                    .write_stream_frames(buf, max_size, self.config.send_fairness);
4028            self.stats.frame_tx.stream += sent.stream_frames.len() as u64;
4029        }
4030
4031        sent
4032    }
4033
4034    /// Write pending ACKs into a buffer
4035    ///
4036    /// This method assumes ACKs are pending, and should only be called if
4037    /// `!PendingAcks::ranges().is_empty()` returns `true`.
4038    fn populate_acks(
4039        now: Instant,
4040        receiving_ecn: bool,
4041        sent: &mut SentFrames,
4042        space: &mut PacketSpace,
4043        buf: &mut Vec<u8>,
4044        stats: &mut ConnectionStats,
4045    ) {
4046        debug_assert!(!space.pending_acks.ranges().is_empty());
4047
4048        // 0-RTT packets must never carry acks (which would have to be of handshake packets)
4049        debug_assert!(space.crypto.is_some(), "tried to send ACK in 0-RTT");
4050        let ecn = if receiving_ecn {
4051            Some(&space.ecn_counters)
4052        } else {
4053            None
4054        };
4055        sent.largest_acked = space.pending_acks.ranges().max();
4056
4057        let delay_micros = space.pending_acks.ack_delay(now).as_micros() as u64;
4058
4059        // TODO: This should come from `TransportConfig` if that gets configurable.
4060        let ack_delay_exp = TransportParameters::default().ack_delay_exponent;
4061        let delay = delay_micros >> ack_delay_exp.into_inner();
4062
4063        trace!(
4064            "ACK {:?}, Delay = {}us",
4065            space.pending_acks.ranges(),
4066            delay_micros
4067        );
4068
4069        frame::Ack::encode(delay as _, space.pending_acks.ranges(), ecn, buf);
4070        stats.frame_tx.acks += 1;
4071    }
4072
4073    fn close_common(&mut self) {
4074        trace!("connection closed");
4075        for &timer in &Timer::VALUES {
4076            self.timers.stop(timer);
4077        }
4078    }
4079
4080    fn set_close_timer(&mut self, now: Instant) {
4081        self.timers
4082            .set(Timer::Close, now + 3 * self.pto(self.highest_space));
4083    }
4084
4085    /// Handle transport parameters received from the peer
4086    fn handle_peer_params(&mut self, params: TransportParameters) -> Result<(), TransportError> {
4087        if Some(self.orig_rem_cid) != params.initial_src_cid
4088            || (self.side.is_client()
4089                && (Some(self.initial_dst_cid) != params.original_dst_cid
4090                    || self.retry_src_cid != params.retry_src_cid))
4091        {
4092            return Err(TransportError::TRANSPORT_PARAMETER_ERROR(
4093                "CID authentication failure",
4094            ));
4095        }
4096
4097        self.set_peer_params(params);
4098
4099        Ok(())
4100    }
4101
4102    fn set_peer_params(&mut self, params: TransportParameters) {
4103        self.streams.set_params(&params);
4104        self.idle_timeout =
4105            negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout));
4106        trace!("negotiated max idle timeout {:?}", self.idle_timeout);
4107        if let Some(ref info) = params.preferred_address {
4108            self.rem_cids.insert(frame::NewConnectionId {
4109                sequence: 1,
4110                id: info.connection_id,
4111                reset_token: info.stateless_reset_token,
4112                retire_prior_to: 0,
4113            }).expect("preferred address CID is the first received, and hence is guaranteed to be legal");
4114        }
4115        self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(&params);
4116
4117        // Handle NAT traversal capability negotiation
4118        self.negotiate_nat_traversal_capability(&params);
4119
4120        // Handle address discovery negotiation
4121        self.negotiate_address_discovery(&params);
4122
4123        self.peer_params = params;
4124        self.path.mtud.on_peer_max_udp_payload_size_received(
4125            u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX),
4126        );
4127    }
4128
4129    /// Negotiate NAT traversal capability between local and peer configurations
4130    fn negotiate_nat_traversal_capability(&mut self, params: &TransportParameters) {
4131        // Check if peer supports NAT traversal
4132        let peer_nat_config = match &params.nat_traversal {
4133            Some(config) => config,
4134            None => {
4135                // Peer doesn't support NAT traversal - handle backward compatibility
4136                if self.config.nat_traversal_config.is_some() {
4137                    debug!(
4138                        "Peer does not support NAT traversal, maintaining backward compatibility"
4139                    );
4140                    self.emit_nat_traversal_capability_event(false);
4141
4142                    // Set connection state to indicate NAT traversal is not available
4143                    self.set_nat_traversal_compatibility_mode(false);
4144                }
4145                return;
4146            }
4147        };
4148
4149        // Check if we support NAT traversal locally
4150        let local_nat_config = match &self.config.nat_traversal_config {
4151            Some(config) => config,
4152            None => {
4153                debug!("NAT traversal not enabled locally, ignoring peer support");
4154                self.emit_nat_traversal_capability_event(false);
4155                self.set_nat_traversal_compatibility_mode(false);
4156                return;
4157            }
4158        };
4159
4160        // Both peers support NAT traversal - proceed with capability negotiation
4161        info!("Both peers support NAT traversal, negotiating capabilities");
4162
4163        // Validate role compatibility and negotiate parameters
4164        match self.negotiate_nat_traversal_parameters(local_nat_config, peer_nat_config) {
4165            Ok(negotiated_config) => {
4166                info!("NAT traversal capability negotiated successfully");
4167                self.emit_nat_traversal_capability_event(true);
4168
4169                // Initialize NAT traversal with negotiated parameters
4170                self.init_nat_traversal_with_negotiated_config(&negotiated_config);
4171
4172                // Set connection state to indicate NAT traversal is available
4173                self.set_nat_traversal_compatibility_mode(true);
4174
4175                // Start NAT traversal process if we're in a client role
4176                if matches!(
4177                    negotiated_config.role,
4178                    crate::transport_parameters::NatTraversalRole::Client
4179                ) {
4180                    self.initiate_nat_traversal_process();
4181                }
4182            }
4183            Err(e) => {
4184                warn!("NAT traversal capability negotiation failed: {}", e);
4185                self.emit_nat_traversal_capability_event(false);
4186                self.set_nat_traversal_compatibility_mode(false);
4187            }
4188        }
4189    }
4190
4191    /// Validate that NAT traversal roles are compatible
4192    fn validate_nat_traversal_roles(
4193        &self,
4194        local_config: &crate::transport_parameters::NatTraversalConfig,
4195        peer_config: &crate::transport_parameters::NatTraversalConfig,
4196    ) -> Result<(), String> {
4197        // Check for invalid role combinations
4198        match (&local_config.role, &peer_config.role) {
4199            // Both bootstrap nodes - this is unusual but allowed
4200            (
4201                crate::transport_parameters::NatTraversalRole::Bootstrap,
4202                crate::transport_parameters::NatTraversalRole::Bootstrap,
4203            ) => {
4204                debug!("Both endpoints are bootstrap nodes - unusual but allowed");
4205            }
4206            // Client-Server combinations are ideal
4207            (
4208                crate::transport_parameters::NatTraversalRole::Client,
4209                crate::transport_parameters::NatTraversalRole::Server { .. },
4210            )
4211            | (
4212                crate::transport_parameters::NatTraversalRole::Server { .. },
4213                crate::transport_parameters::NatTraversalRole::Client,
4214            ) => {
4215                debug!("Client-Server NAT traversal role combination");
4216            }
4217            // Bootstrap can coordinate with anyone
4218            (crate::transport_parameters::NatTraversalRole::Bootstrap, _)
4219            | (_, crate::transport_parameters::NatTraversalRole::Bootstrap) => {
4220                debug!("Bootstrap node coordination");
4221            }
4222            // Client-Client requires bootstrap coordination
4223            (
4224                crate::transport_parameters::NatTraversalRole::Client,
4225                crate::transport_parameters::NatTraversalRole::Client,
4226            ) => {
4227                debug!("Client-Client connection requires bootstrap coordination");
4228            }
4229            // Server-Server is allowed but may need coordination
4230            (
4231                crate::transport_parameters::NatTraversalRole::Server { .. },
4232                crate::transport_parameters::NatTraversalRole::Server { .. },
4233            ) => {
4234                debug!("Server-Server connection");
4235            }
4236        }
4237
4238        Ok(())
4239    }
4240
4241    /// Emit NAT traversal capability negotiation event
4242    fn emit_nat_traversal_capability_event(&mut self, negotiated: bool) {
4243        // For now, we'll just log the event
4244        // In a full implementation, this could emit an event that applications can listen to
4245        if negotiated {
4246            info!("NAT traversal capability successfully negotiated");
4247        } else {
4248            info!("NAT traversal capability not available (peer or local support missing)");
4249        }
4250
4251        // Could add to events queue if needed:
4252        // self.events.push_back(Event::NatTraversalCapability { negotiated });
4253    }
4254
4255    /// Set NAT traversal compatibility mode for backward compatibility
4256    fn set_nat_traversal_compatibility_mode(&mut self, enabled: bool) {
4257        if enabled {
4258            debug!("NAT traversal enabled for this connection");
4259            // Connection supports NAT traversal - no special handling needed
4260        } else {
4261            debug!("NAT traversal disabled for this connection (backward compatibility mode)");
4262            // Ensure NAT traversal state is cleared if it was partially initialized
4263            if self.nat_traversal.is_some() {
4264                warn!("Clearing NAT traversal state due to compatibility mode");
4265                self.nat_traversal = None;
4266            }
4267        }
4268    }
4269
4270    /// Negotiate NAT traversal parameters between local and peer configurations
4271    fn negotiate_nat_traversal_parameters(
4272        &self,
4273        local_config: &crate::transport_parameters::NatTraversalConfig,
4274        peer_config: &crate::transport_parameters::NatTraversalConfig,
4275    ) -> Result<crate::transport_parameters::NatTraversalConfig, String> {
4276        // Validate role compatibility first
4277        self.validate_nat_traversal_roles(local_config, peer_config)?;
4278
4279        // Use local role as the basis for negotiation
4280        let negotiated_role = local_config.role;
4281
4282        // Negotiate parameters using the more restrictive values
4283        let max_candidates = local_config
4284            .max_candidates
4285            .into_inner()
4286            .min(peer_config.max_candidates.into_inner())
4287            .min(50); // Cap at reasonable limit
4288
4289        let coordination_timeout = local_config
4290            .coordination_timeout
4291            .into_inner()
4292            .min(peer_config.coordination_timeout.into_inner())
4293            .min(30000); // Cap at 30 seconds
4294
4295        let max_concurrent_attempts = local_config
4296            .max_concurrent_attempts
4297            .into_inner()
4298            .min(peer_config.max_concurrent_attempts.into_inner())
4299            .min(10); // Cap at reasonable limit
4300
4301        // Use local peer ID if available, otherwise use peer's
4302        let peer_id = local_config.peer_id.or(peer_config.peer_id);
4303
4304        let negotiated_config = crate::transport_parameters::NatTraversalConfig {
4305            role: negotiated_role,
4306            max_candidates: VarInt::from_u64(max_candidates).unwrap(),
4307            coordination_timeout: VarInt::from_u64(coordination_timeout).unwrap(),
4308            max_concurrent_attempts: VarInt::from_u64(max_concurrent_attempts).unwrap(),
4309            peer_id,
4310        };
4311
4312        // Validate the negotiated configuration
4313        negotiated_config
4314            .validate()
4315            .map_err(|e| format!("Negotiated configuration validation failed: {:?}", e))?;
4316
4317        debug!(
4318            "NAT traversal parameters negotiated: role={:?}, max_candidates={}, timeout={}ms, max_attempts={}",
4319            negotiated_role, max_candidates, coordination_timeout, max_concurrent_attempts
4320        );
4321
4322        Ok(negotiated_config)
4323    }
4324
4325    /// Initialize NAT traversal with negotiated configuration
4326    fn init_nat_traversal_with_negotiated_config(
4327        &mut self,
4328        config: &crate::transport_parameters::NatTraversalConfig,
4329    ) {
4330        // Convert transport parameter role to internal role
4331        let role = match config.role {
4332            crate::transport_parameters::NatTraversalRole::Client => NatTraversalRole::Client,
4333            crate::transport_parameters::NatTraversalRole::Server { can_relay } => {
4334                NatTraversalRole::Server { can_relay }
4335            }
4336            crate::transport_parameters::NatTraversalRole::Bootstrap => NatTraversalRole::Bootstrap,
4337        };
4338
4339        let max_candidates = config.max_candidates.into_inner().min(50) as u32;
4340        let coordination_timeout =
4341            Duration::from_millis(config.coordination_timeout.into_inner().min(30000));
4342
4343        // Initialize NAT traversal state
4344        self.nat_traversal = Some(NatTraversalState::new(
4345            role,
4346            max_candidates,
4347            coordination_timeout,
4348        ));
4349
4350        trace!(
4351            "NAT traversal initialized with negotiated config: role={:?}",
4352            role
4353        );
4354
4355        // Perform role-specific initialization
4356        match role {
4357            NatTraversalRole::Bootstrap => {
4358                // Bootstrap nodes should be ready to observe addresses
4359                self.prepare_address_observation();
4360            }
4361            NatTraversalRole::Client => {
4362                // Clients should start candidate discovery
4363                self.schedule_candidate_discovery();
4364            }
4365            NatTraversalRole::Server { .. } => {
4366                // Servers should be ready to accept coordination requests
4367                self.prepare_coordination_handling();
4368            }
4369        }
4370    }
4371
4372    /// Initiate NAT traversal process for client endpoints
4373    fn initiate_nat_traversal_process(&mut self) {
4374        if let Some(nat_state) = &mut self.nat_traversal {
4375            match nat_state.start_candidate_discovery() {
4376                Ok(()) => {
4377                    debug!("NAT traversal process initiated - candidate discovery started");
4378                    // Schedule the first coordination attempt
4379                    self.timers.set(
4380                        Timer::NatTraversal,
4381                        Instant::now() + Duration::from_millis(100),
4382                    );
4383                }
4384                Err(e) => {
4385                    warn!("Failed to initiate NAT traversal process: {}", e);
4386                }
4387            }
4388        }
4389    }
4390
4391    /// Prepare for address observation (bootstrap nodes)
4392    fn prepare_address_observation(&mut self) {
4393        debug!("Preparing for address observation as bootstrap node");
4394        // Bootstrap nodes are ready to observe peer addresses immediately
4395        // No additional setup needed - observation happens during connection establishment
4396    }
4397
4398    /// Schedule candidate discovery for later execution
4399    fn schedule_candidate_discovery(&mut self) {
4400        debug!("Scheduling candidate discovery for client endpoint");
4401        // Set a timer to start candidate discovery after connection establishment
4402        self.timers.set(
4403            Timer::NatTraversal,
4404            Instant::now() + Duration::from_millis(50),
4405        );
4406    }
4407
4408    /// Prepare to handle coordination requests (server nodes)
4409    fn prepare_coordination_handling(&mut self) {
4410        debug!("Preparing to handle coordination requests as server endpoint");
4411        // Server nodes are ready to handle coordination requests immediately
4412        // No additional setup needed - coordination happens via frame processing
4413    }
4414
4415    /// Handle NAT traversal timeout events
4416    fn handle_nat_traversal_timeout(&mut self, now: Instant) {
4417        // First get the actions from nat_state
4418        let timeout_result = if let Some(nat_state) = &mut self.nat_traversal {
4419            nat_state.handle_timeout(now)
4420        } else {
4421            return;
4422        };
4423
4424        // Then handle the actions without holding a mutable borrow to nat_state
4425        match timeout_result {
4426            Ok(actions) => {
4427                for action in actions {
4428                    match action {
4429                        nat_traversal::TimeoutAction::RetryDiscovery => {
4430                            debug!("NAT traversal timeout: retrying candidate discovery");
4431                            if let Some(nat_state) = &mut self.nat_traversal {
4432                                if let Err(e) = nat_state.start_candidate_discovery() {
4433                                    warn!("Failed to retry candidate discovery: {}", e);
4434                                }
4435                            }
4436                        }
4437                        nat_traversal::TimeoutAction::RetryCoordination => {
4438                            debug!("NAT traversal timeout: retrying coordination");
4439                            // Schedule next coordination attempt
4440                            self.timers
4441                                .set(Timer::NatTraversal, now + Duration::from_secs(2));
4442                        }
4443                        nat_traversal::TimeoutAction::StartValidation => {
4444                            debug!("NAT traversal timeout: starting path validation");
4445                            self.start_nat_traversal_validation(now);
4446                        }
4447                        nat_traversal::TimeoutAction::Complete => {
4448                            debug!("NAT traversal completed successfully");
4449                            // NAT traversal is complete, no more timeouts needed
4450                            self.timers.stop(Timer::NatTraversal);
4451                        }
4452                        nat_traversal::TimeoutAction::Failed => {
4453                            warn!("NAT traversal failed after timeout");
4454                            // Consider fallback options or connection failure
4455                            self.handle_nat_traversal_failure();
4456                        }
4457                    }
4458                }
4459            }
4460            Err(e) => {
4461                warn!("NAT traversal timeout handling failed: {}", e);
4462                self.handle_nat_traversal_failure();
4463            }
4464        }
4465    }
4466
4467    /// Start NAT traversal path validation
4468    fn start_nat_traversal_validation(&mut self, now: Instant) {
4469        if let Some(nat_state) = &mut self.nat_traversal {
4470            // Get candidate pairs that need validation
4471            let pairs = nat_state.get_next_validation_pairs(3);
4472
4473            for pair in pairs {
4474                // Send PATH_CHALLENGE to validate the path
4475                let challenge = self.rng.gen();
4476                self.path.challenge = Some(challenge);
4477                self.path.challenge_pending = true;
4478
4479                debug!(
4480                    "Starting path validation for NAT traversal candidate: {}",
4481                    pair.remote_addr
4482                );
4483            }
4484
4485            // Set validation timeout
4486            self.timers
4487                .set(Timer::PathValidation, now + Duration::from_secs(3));
4488        }
4489    }
4490
4491    /// Handle NAT traversal failure
4492    fn handle_nat_traversal_failure(&mut self) {
4493        warn!("NAT traversal failed, considering fallback options");
4494
4495        // Clear NAT traversal state
4496        self.nat_traversal = None;
4497        self.timers.stop(Timer::NatTraversal);
4498
4499        // In a full implementation, this could:
4500        // 1. Try relay connections
4501        // 2. Emit failure events to the application
4502        // 3. Attempt direct connection as fallback
4503
4504        // For now, we'll just log the failure
4505        debug!("NAT traversal disabled for this connection due to failure");
4506    }
4507
4508    /// Check if NAT traversal is supported and enabled for this connection
4509    pub fn nat_traversal_supported(&self) -> bool {
4510        self.nat_traversal.is_some()
4511            && self.config.nat_traversal_config.is_some()
4512            && self.peer_params.nat_traversal.is_some()
4513    }
4514
4515    /// Get the negotiated NAT traversal configuration
4516    pub fn nat_traversal_config(&self) -> Option<&crate::transport_parameters::NatTraversalConfig> {
4517        self.peer_params.nat_traversal.as_ref()
4518    }
4519
4520    /// Check if the connection is ready for NAT traversal operations
4521    pub fn nat_traversal_ready(&self) -> bool {
4522        self.nat_traversal_supported() && matches!(self.state, State::Established)
4523    }
4524
4525    /// Get NAT traversal statistics for this connection
4526    ///
4527    /// This method is preserved for debugging and monitoring purposes.
4528    /// It may be used in future telemetry or diagnostic features.
4529    #[allow(dead_code)]
4530    pub(crate) fn nat_traversal_stats(&self) -> Option<nat_traversal::NatTraversalStats> {
4531        self.nat_traversal.as_ref().map(|state| state.stats.clone())
4532    }
4533
4534    /// Force enable NAT traversal for testing purposes
4535    #[cfg(test)]
4536    pub(crate) fn force_enable_nat_traversal(&mut self, role: NatTraversalRole) {
4537        use crate::transport_parameters::{NatTraversalConfig, NatTraversalRole as TPRole};
4538
4539        let tp_role = match role {
4540            NatTraversalRole::Client => TPRole::Client,
4541            NatTraversalRole::Server { can_relay } => TPRole::Server { can_relay },
4542            NatTraversalRole::Bootstrap => TPRole::Bootstrap,
4543        };
4544
4545        let config = NatTraversalConfig {
4546            role: tp_role,
4547            max_candidates: VarInt::from_u32(8),
4548            coordination_timeout: VarInt::from_u32(10000),
4549            max_concurrent_attempts: VarInt::from_u32(3),
4550            peer_id: None,
4551        };
4552
4553        self.peer_params.nat_traversal = Some(config.clone());
4554        self.config = Arc::new({
4555            let mut transport_config = (*self.config).clone();
4556            transport_config.nat_traversal_config = Some(config);
4557            transport_config
4558        });
4559
4560        self.nat_traversal = Some(NatTraversalState::new(role, 8, Duration::from_secs(10)));
4561    }
4562
4563    /// Queue an ADD_ADDRESS frame to be sent to the peer
4564    /// Derive peer ID from connection context
4565    fn derive_peer_id_from_connection(&self) -> [u8; 32] {
4566        // Generate a peer ID based on connection IDs
4567        let mut hasher = std::collections::hash_map::DefaultHasher::new();
4568        use std::hash::Hasher;
4569        hasher.write(&self.rem_handshake_cid);
4570        hasher.write(&self.handshake_cid);
4571        hasher.write(&self.path.remote.to_string().into_bytes());
4572        let hash = hasher.finish();
4573        let mut peer_id = [0u8; 32];
4574        peer_id[..8].copy_from_slice(&hash.to_be_bytes());
4575        // Fill remaining bytes with connection ID data
4576        let cid_bytes = self.rem_handshake_cid.as_ref();
4577        let copy_len = (cid_bytes.len()).min(24);
4578        peer_id[8..8 + copy_len].copy_from_slice(&cid_bytes[..copy_len]);
4579        peer_id
4580    }
4581
4582    /// Handle AddAddress frame from peer
4583    fn handle_add_address(
4584        &mut self,
4585        add_address: &crate::frame::AddAddress,
4586        now: Instant,
4587    ) -> Result<(), TransportError> {
4588        let nat_state = self.nat_traversal.as_mut().ok_or_else(|| {
4589            TransportError::PROTOCOL_VIOLATION("AddAddress frame without NAT traversal negotiation")
4590        })?;
4591
4592        match nat_state.add_remote_candidate(
4593            add_address.sequence,
4594            add_address.address,
4595            add_address.priority,
4596            now,
4597        ) {
4598            Ok(()) => {
4599                trace!(
4600                    "Added remote candidate: {} (seq={}, priority={})",
4601                    add_address.address, add_address.sequence, add_address.priority
4602                );
4603
4604                // Trigger validation of this new candidate
4605                self.trigger_candidate_validation(add_address.address, now)?;
4606                Ok(())
4607            }
4608            Err(NatTraversalError::TooManyCandidates) => Err(TransportError::PROTOCOL_VIOLATION(
4609                "too many NAT traversal candidates",
4610            )),
4611            Err(NatTraversalError::DuplicateAddress) => {
4612                // Silently ignore duplicates (peer may resend)
4613                Ok(())
4614            }
4615            Err(e) => {
4616                warn!("Failed to add remote candidate: {}", e);
4617                Ok(()) // Don't terminate connection for non-critical errors
4618            }
4619        }
4620    }
4621
4622    /// Handle PunchMeNow frame from peer (via coordinator)
4623    fn handle_punch_me_now(
4624        &mut self,
4625        punch_me_now: &crate::frame::PunchMeNow,
4626        now: Instant,
4627    ) -> Result<(), TransportError> {
4628        trace!(
4629            "Received PunchMeNow: round={}, target_seq={}, local_addr={}",
4630            punch_me_now.round, punch_me_now.target_sequence, punch_me_now.local_address
4631        );
4632
4633        // Check if we're a bootstrap node that should coordinate this
4634        if let Some(nat_state) = &self.nat_traversal {
4635            if matches!(nat_state.role, NatTraversalRole::Bootstrap) {
4636                // We're a bootstrap node - process coordination request
4637                let from_peer_id = self.derive_peer_id_from_connection();
4638
4639                // Clone the frame to avoid borrow checker issues
4640                let punch_me_now_clone = punch_me_now.clone();
4641                drop(nat_state); // Release the borrow
4642
4643                match self
4644                    .nat_traversal
4645                    .as_mut()
4646                    .unwrap()
4647                    .handle_punch_me_now_frame(
4648                        from_peer_id,
4649                        self.path.remote,
4650                        &punch_me_now_clone,
4651                        now,
4652                    ) {
4653                    Ok(Some(coordination_frame)) => {
4654                        trace!("Bootstrap node coordinating PUNCH_ME_NOW between peers");
4655
4656                        // Send coordination frame to target peer via endpoint
4657                        if let Some(target_peer_id) = punch_me_now.target_peer_id {
4658                            self.endpoint_events.push_back(
4659                                crate::shared::EndpointEventInner::RelayPunchMeNow(
4660                                    target_peer_id,
4661                                    coordination_frame,
4662                                ),
4663                            );
4664                        }
4665
4666                        return Ok(());
4667                    }
4668                    Ok(None) => {
4669                        trace!("Bootstrap coordination completed or no action needed");
4670                        return Ok(());
4671                    }
4672                    Err(e) => {
4673                        warn!("Bootstrap coordination failed: {}", e);
4674                        return Ok(());
4675                    }
4676                }
4677            }
4678        }
4679
4680        // We're a regular peer receiving coordination from bootstrap
4681        let nat_state = self.nat_traversal.as_mut().ok_or_else(|| {
4682            TransportError::PROTOCOL_VIOLATION("PunchMeNow frame without NAT traversal negotiation")
4683        })?;
4684
4685        // Handle peer's coordination request
4686        if nat_state
4687            .handle_peer_punch_request(punch_me_now.round, now)
4688            .map_err(|_e| {
4689                TransportError::PROTOCOL_VIOLATION("Failed to handle peer punch request")
4690            })?
4691        {
4692            trace!("Coordination synchronized for round {}", punch_me_now.round);
4693
4694            // Create punch targets based on the received information
4695            // The peer's local_address tells us where they'll be listening
4696            let _local_addr = self
4697                .local_ip
4698                .map(|ip| SocketAddr::new(ip, 0))
4699                .unwrap_or_else(|| {
4700                    SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED), 0)
4701                });
4702
4703            let target = nat_traversal::PunchTarget {
4704                remote_addr: punch_me_now.local_address,
4705                remote_sequence: punch_me_now.target_sequence,
4706                challenge: self.rng.gen(),
4707            };
4708
4709            // Start coordination with this target
4710            nat_state.start_coordination_round(vec![target], now);
4711        } else {
4712            debug!(
4713                "Failed to synchronize coordination for round {}",
4714                punch_me_now.round
4715            );
4716        }
4717
4718        Ok(())
4719    }
4720
4721    /// Handle RemoveAddress frame from peer
4722    fn handle_remove_address(
4723        &mut self,
4724        remove_address: &crate::frame::RemoveAddress,
4725    ) -> Result<(), TransportError> {
4726        let nat_state = self.nat_traversal.as_mut().ok_or_else(|| {
4727            TransportError::PROTOCOL_VIOLATION(
4728                "RemoveAddress frame without NAT traversal negotiation",
4729            )
4730        })?;
4731
4732        if nat_state.remove_candidate(remove_address.sequence) {
4733            trace!(
4734                "Removed candidate with sequence {}",
4735                remove_address.sequence
4736            );
4737        } else {
4738            trace!(
4739                "Attempted to remove unknown candidate sequence {}",
4740                remove_address.sequence
4741            );
4742        }
4743
4744        Ok(())
4745    }
4746    
4747    /// Handle ObservedAddress frame from peer
4748    fn handle_observed_address_frame(
4749        &mut self,
4750        observed_address: &crate::frame::ObservedAddress,
4751        now: Instant,
4752    ) -> Result<(), TransportError> {
4753        // Get the address discovery state
4754        let state = self.address_discovery_state.as_mut().ok_or_else(|| {
4755            TransportError::PROTOCOL_VIOLATION(
4756                "ObservedAddress frame without address discovery negotiation",
4757            )
4758        })?;
4759        
4760        // Check if address discovery is enabled
4761        if !state.enabled {
4762            return Err(TransportError::PROTOCOL_VIOLATION(
4763                "ObservedAddress frame received when address discovery is disabled",
4764            ));
4765        }
4766        
4767        // Trace observed address received
4768        #[cfg(feature = "trace")]
4769        {
4770            use crate::tracing::*;
4771            use crate::trace_observed_address_received;
4772            trace_observed_address_received!(
4773                &self.event_log,
4774                self.trace_context.trace_id(),
4775                observed_address.address,
4776                0u64  // path_id not part of the frame yet
4777            );
4778        }
4779        
4780        // Get the current path ID (0 for primary path in single-path connections)
4781        let path_id = 0u64; // TODO: Support multi-path scenarios
4782        
4783        // Process the observed address
4784        state.handle_observed_address(observed_address.address, path_id, now);
4785        
4786        // Update the path's address info
4787        self.path.update_observed_address(observed_address.address, now);
4788        
4789        // Log the observation
4790        trace!(
4791            "Received ObservedAddress frame: address={} for path={}",
4792            observed_address.address,
4793            path_id
4794        );
4795        
4796        Ok(())
4797    }
4798
4799    /// Queue an AddAddress frame to advertise a new candidate address
4800    pub fn queue_add_address(&mut self, sequence: VarInt, address: SocketAddr, priority: VarInt) {
4801        // Queue the AddAddress frame
4802        let add_address = frame::AddAddress {
4803            sequence,
4804            address,
4805            priority,
4806        };
4807
4808        self.spaces[SpaceId::Data]
4809            .pending
4810            .add_addresses
4811            .push(add_address);
4812        trace!(
4813            "Queued AddAddress frame: seq={}, addr={}, priority={}",
4814            sequence, address, priority
4815        );
4816    }
4817
4818    /// Queue a PunchMeNow frame to coordinate NAT traversal
4819    pub fn queue_punch_me_now(
4820        &mut self,
4821        round: VarInt,
4822        target_sequence: VarInt,
4823        local_address: SocketAddr,
4824    ) {
4825        let punch_me_now = frame::PunchMeNow {
4826            round,
4827            target_sequence,
4828            local_address,
4829            target_peer_id: None, // Direct peer-to-peer communication
4830        };
4831
4832        self.spaces[SpaceId::Data]
4833            .pending
4834            .punch_me_now
4835            .push(punch_me_now);
4836        trace!(
4837            "Queued PunchMeNow frame: round={}, target={}",
4838            round, target_sequence
4839        );
4840    }
4841
4842    /// Queue a RemoveAddress frame to remove a candidate
4843    pub fn queue_remove_address(&mut self, sequence: VarInt) {
4844        let remove_address = frame::RemoveAddress { sequence };
4845
4846        self.spaces[SpaceId::Data]
4847            .pending
4848            .remove_addresses
4849            .push(remove_address);
4850        trace!("Queued RemoveAddress frame: seq={}", sequence);
4851    }
4852    
4853    /// Queue an ObservedAddress frame to send to peer
4854    pub fn queue_observed_address(&mut self, address: SocketAddr) {
4855        let observed_address = frame::ObservedAddress { address };
4856        self.spaces[SpaceId::Data]
4857            .pending
4858            .observed_addresses
4859            .push(observed_address);
4860        trace!("Queued ObservedAddress frame: addr={}", address);
4861    }
4862    
4863    /// Check if we should send OBSERVED_ADDRESS frames and queue them
4864    pub fn check_for_address_observations(&mut self, now: Instant) {
4865        // Only check if we have address discovery state
4866        let Some(state) = &mut self.address_discovery_state else {
4867            return;
4868        };
4869        
4870        // Check if address discovery is enabled
4871        if !state.enabled {
4872            return;
4873        }
4874        
4875        // Get the current path ID (0 for primary path)
4876        let path_id = 0u64; // TODO: Support multi-path scenarios
4877        
4878        // Get the remote address for this path
4879        let remote_address = self.path.remote;
4880        
4881        // Check if we should send an observation for this path
4882        if state.should_send_observation(path_id, now) {
4883            // Try to queue the observation frame
4884            if let Some(frame) = state.queue_observed_address_frame(path_id, remote_address) {
4885                // Queue the frame for sending
4886                self.spaces[SpaceId::Data]
4887                    .pending
4888                    .observed_addresses
4889                    .push(frame);
4890                
4891                // Record that we sent the observation
4892                state.record_observation_sent(path_id);
4893                
4894                // Trace observed address sent
4895                #[cfg(feature = "trace")]
4896                {
4897                    use crate::tracing::*;
4898                    use crate::trace_observed_address_sent;
4899                    trace_observed_address_sent!(
4900                        &self.event_log,
4901                        self.trace_context.trace_id(),
4902                        remote_address,
4903                        path_id
4904                    );
4905                }
4906                
4907                trace!("Queued OBSERVED_ADDRESS frame for path {} with address {}", path_id, remote_address);
4908            }
4909        }
4910    }
4911
4912    /// Trigger validation of a candidate address using PATH_CHALLENGE
4913    fn trigger_candidate_validation(
4914        &mut self,
4915        candidate_address: SocketAddr,
4916        now: Instant,
4917    ) -> Result<(), TransportError> {
4918        let nat_state = self
4919            .nat_traversal
4920            .as_mut()
4921            .ok_or_else(|| TransportError::PROTOCOL_VIOLATION("NAT traversal not enabled"))?;
4922
4923        // Check if we already have an active validation for this address
4924        if nat_state
4925            .active_validations
4926            .contains_key(&candidate_address)
4927        {
4928            trace!("Validation already in progress for {}", candidate_address);
4929            return Ok(());
4930        }
4931
4932        // Generate a random challenge value
4933        let challenge = self.rng.gen::<u64>();
4934
4935        // Create path validation state
4936        let validation_state = nat_traversal::PathValidationState {
4937            challenge,
4938            sent_at: now,
4939            retry_count: 0,
4940            max_retries: 3,
4941            coordination_round: None,
4942            timeout_state: nat_traversal::AdaptiveTimeoutState::new(),
4943            last_retry_at: None,
4944        };
4945
4946        // Store the validation attempt
4947        nat_state
4948            .active_validations
4949            .insert(candidate_address, validation_state);
4950
4951        // Queue PATH_CHALLENGE frame to be sent to the candidate address
4952        self.nat_traversal_challenges
4953            .push(candidate_address, challenge);
4954
4955        // Update statistics
4956        nat_state.stats.validations_succeeded += 1; // Will be decremented if validation fails
4957
4958        trace!(
4959            "Triggered PATH_CHALLENGE validation for {} with challenge {:016x}",
4960            candidate_address, challenge
4961        );
4962
4963        Ok(())
4964    }
4965
4966    /// Get current NAT traversal state information
4967    pub fn nat_traversal_state(&self) -> Option<(NatTraversalRole, usize, usize)> {
4968        self.nat_traversal.as_ref().map(|state| {
4969            (
4970                state.role,
4971                state.local_candidates.len(),
4972                state.remote_candidates.len(),
4973            )
4974        })
4975    }
4976
4977    /// Initiate NAT traversal coordination through a bootstrap node
4978    pub fn initiate_nat_traversal_coordination(
4979        &mut self,
4980        now: Instant,
4981    ) -> Result<(), TransportError> {
4982        let nat_state = self
4983            .nat_traversal
4984            .as_mut()
4985            .ok_or_else(|| TransportError::PROTOCOL_VIOLATION("NAT traversal not enabled"))?;
4986
4987        // Check if we should send PUNCH_ME_NOW to coordinator
4988        if nat_state.should_send_punch_request() {
4989            // Generate candidate pairs for coordination
4990            nat_state.generate_candidate_pairs(now);
4991
4992            // Get the best candidate pairs to try
4993            let pairs = nat_state.get_next_validation_pairs(3);
4994            if pairs.is_empty() {
4995                return Err(TransportError::PROTOCOL_VIOLATION(
4996                    "No candidate pairs for coordination",
4997                ));
4998            }
4999
5000            // Create punch targets from the pairs
5001            let targets: Vec<_> = pairs
5002                .into_iter()
5003                .map(|pair| nat_traversal::PunchTarget {
5004                    remote_addr: pair.remote_addr,
5005                    remote_sequence: pair.remote_sequence,
5006                    challenge: self.rng.gen(),
5007                })
5008                .collect();
5009
5010            // Start coordination round
5011            let round = nat_state
5012                .start_coordination_round(targets, now)
5013                .map_err(|_e| {
5014                    TransportError::PROTOCOL_VIOLATION("Failed to start coordination round")
5015                })?;
5016
5017            // Queue PUNCH_ME_NOW frame to be sent to bootstrap node
5018            // Include our best local address for the peer to target
5019            let local_addr = self
5020                .local_ip
5021                .map(|ip| SocketAddr::new(ip, self.local_ip.map(|_| 0).unwrap_or(0)))
5022                .unwrap_or_else(|| {
5023                    SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED), 0)
5024                });
5025
5026            let punch_me_now = frame::PunchMeNow {
5027                round,
5028                target_sequence: VarInt::from_u32(0), // Will be filled by bootstrap
5029                local_address: local_addr,
5030                target_peer_id: None, // Direct peer-to-peer communication
5031            };
5032
5033            self.spaces[SpaceId::Data]
5034                .pending
5035                .punch_me_now
5036                .push(punch_me_now);
5037            nat_state.mark_punch_request_sent();
5038
5039            trace!("Initiated NAT traversal coordination round {}", round);
5040        }
5041
5042        Ok(())
5043    }
5044
5045    /// Trigger validation of NAT traversal candidates using PATH_CHALLENGE
5046    pub fn validate_nat_candidates(&mut self, now: Instant) {
5047        self.generate_nat_traversal_challenges(now);
5048    }
5049
5050    // === PUBLIC NAT TRAVERSAL FRAME TRANSMISSION API ===
5051
5052    /// Send an ADD_ADDRESS frame to advertise a candidate address to the peer
5053    ///
5054    /// This is the primary method for sending NAT traversal address advertisements.
5055    /// The frame will be transmitted in the next outgoing QUIC packet.
5056    ///
5057    /// # Arguments
5058    /// * `address` - The candidate address to advertise
5059    /// * `priority` - ICE-style priority for this candidate (higher = better)
5060    ///
5061    /// # Returns
5062    /// * `Ok(sequence)` - The sequence number assigned to this candidate
5063    /// * `Err(ConnectionError)` - If NAT traversal is not enabled or other error
5064    pub fn send_nat_address_advertisement(
5065        &mut self,
5066        address: SocketAddr,
5067        priority: u32,
5068    ) -> Result<u64, ConnectionError> {
5069        // Verify NAT traversal is enabled
5070        let nat_state = self.nat_traversal.as_mut().ok_or_else(|| {
5071            ConnectionError::TransportError(TransportError::PROTOCOL_VIOLATION(
5072                "NAT traversal not enabled on this connection",
5073            ))
5074        })?;
5075
5076        // Generate sequence number and add to local candidates
5077        let sequence = nat_state.next_sequence;
5078        nat_state.next_sequence =
5079            VarInt::from_u64(nat_state.next_sequence.into_inner() + 1).unwrap();
5080
5081        // Add to local candidates
5082        let now = Instant::now();
5083        nat_state.local_candidates.insert(
5084            sequence,
5085            nat_traversal::AddressCandidate {
5086                address,
5087                priority,
5088                source: nat_traversal::CandidateSource::Local,
5089                discovered_at: now,
5090                state: nat_traversal::CandidateState::New,
5091                attempt_count: 0,
5092                last_attempt: None,
5093            },
5094        );
5095
5096        // Update statistics
5097        nat_state.stats.local_candidates_sent += 1;
5098
5099        // Queue the frame for transmission (must be done after releasing nat_state borrow)
5100        self.queue_add_address(sequence, address, VarInt::from_u32(priority));
5101
5102        debug!(
5103            "Queued ADD_ADDRESS frame: addr={}, priority={}, seq={}",
5104            address, priority, sequence
5105        );
5106        Ok(sequence.into_inner())
5107    }
5108
5109    /// Send a PUNCH_ME_NOW frame to coordinate hole punching with a peer
5110    ///
5111    /// This triggers synchronized hole punching for NAT traversal.
5112    ///
5113    /// # Arguments
5114    /// * `target_sequence` - Sequence number of the target candidate address
5115    /// * `local_address` - Our local address for the hole punching attempt
5116    /// * `round` - Coordination round number for synchronization
5117    ///
5118    /// # Returns
5119    /// * `Ok(())` - Frame queued for transmission
5120    /// * `Err(ConnectionError)` - If NAT traversal is not enabled
5121    pub fn send_nat_punch_coordination(
5122        &mut self,
5123        target_sequence: u64,
5124        local_address: SocketAddr,
5125        round: u32,
5126    ) -> Result<(), ConnectionError> {
5127        // Verify NAT traversal is enabled
5128        let _nat_state = self.nat_traversal.as_ref().ok_or_else(|| {
5129            ConnectionError::TransportError(TransportError::PROTOCOL_VIOLATION(
5130                "NAT traversal not enabled on this connection",
5131            ))
5132        })?;
5133
5134        // Queue the frame for transmission
5135        self.queue_punch_me_now(
5136            VarInt::from_u32(round),
5137            VarInt::from_u64(target_sequence).map_err(|_| {
5138                ConnectionError::TransportError(TransportError::PROTOCOL_VIOLATION(
5139                    "Invalid target sequence number",
5140                ))
5141            })?,
5142            local_address,
5143        );
5144
5145        debug!(
5146            "Queued PUNCH_ME_NOW frame: target_seq={}, local_addr={}, round={}",
5147            target_sequence, local_address, round
5148        );
5149        Ok(())
5150    }
5151
5152    /// Send a REMOVE_ADDRESS frame to remove a previously advertised candidate
5153    ///
5154    /// This removes a candidate address that is no longer valid or available.
5155    ///
5156    /// # Arguments
5157    /// * `sequence` - Sequence number of the candidate to remove
5158    ///
5159    /// # Returns
5160    /// * `Ok(())` - Frame queued for transmission
5161    /// * `Err(ConnectionError)` - If NAT traversal is not enabled
5162    pub fn send_nat_address_removal(&mut self, sequence: u64) -> Result<(), ConnectionError> {
5163        // Verify NAT traversal is enabled
5164        let nat_state = self.nat_traversal.as_mut().ok_or_else(|| {
5165            ConnectionError::TransportError(TransportError::PROTOCOL_VIOLATION(
5166                "NAT traversal not enabled on this connection",
5167            ))
5168        })?;
5169
5170        let sequence_varint = VarInt::from_u64(sequence).map_err(|_| {
5171            ConnectionError::TransportError(TransportError::PROTOCOL_VIOLATION(
5172                "Invalid sequence number",
5173            ))
5174        })?;
5175
5176        // Remove from local candidates
5177        nat_state.local_candidates.remove(&sequence_varint);
5178
5179        // Queue the frame for transmission
5180        self.queue_remove_address(sequence_varint);
5181
5182        debug!("Queued REMOVE_ADDRESS frame: seq={}", sequence);
5183        Ok(())
5184    }
5185
5186    /// Get statistics about NAT traversal activity on this connection
5187    ///
5188    /// # Returns
5189    /// * `Some(stats)` - Current NAT traversal statistics
5190    /// * `None` - If NAT traversal is not enabled
5191    ///
5192    /// This method is preserved for debugging and monitoring purposes.
5193    /// It may be used in future telemetry or diagnostic features.
5194    #[allow(dead_code)]
5195    pub(crate) fn get_nat_traversal_stats(&self) -> Option<&nat_traversal::NatTraversalStats> {
5196        self.nat_traversal.as_ref().map(|state| &state.stats)
5197    }
5198
5199    /// Check if NAT traversal is enabled and active on this connection
5200    pub fn is_nat_traversal_enabled(&self) -> bool {
5201        self.nat_traversal.is_some()
5202    }
5203
5204    /// Get the current NAT traversal role for this connection
5205    pub fn get_nat_traversal_role(&self) -> Option<NatTraversalRole> {
5206        self.nat_traversal.as_ref().map(|state| state.role)
5207    }
5208
5209    /// Negotiate address discovery parameters with peer
5210    fn negotiate_address_discovery(&mut self, peer_params: &TransportParameters) {
5211        let now = Instant::now();
5212        
5213        // Check if peer supports address discovery
5214        match &peer_params.address_discovery {
5215            Some(peer_config) if peer_config.enabled => {
5216                // Peer supports address discovery
5217                if let Some(state) = &mut self.address_discovery_state {
5218                    if state.enabled {
5219                        // Both support - negotiate parameters
5220                        // Use minimum of the two rates for safety
5221                        let negotiated_rate = state.max_observation_rate.min(peer_config.max_observation_rate);
5222                        state.update_rate_limit(negotiated_rate as f64);
5223                        
5224                        // Update observe_all_paths based on peer's preference
5225                        // Conservative approach: both must support all paths
5226                        state.observe_all_paths = state.observe_all_paths && peer_config.observe_all_paths;
5227                        
5228                        debug!(
5229                            "Address discovery negotiated: rate={}, all_paths={}", 
5230                            negotiated_rate, 
5231                            state.observe_all_paths
5232                        );
5233                    } else {
5234                        // We don't support it but peer does
5235                        debug!("Address discovery disabled locally, ignoring peer support");
5236                    }
5237                } else {
5238                    // Initialize state based on peer config if we don't have one
5239                    self.address_discovery_state = Some(AddressDiscoveryState::new(peer_config, now));
5240                    debug!("Address discovery initialized from peer config");
5241                }
5242            }
5243            _ => {
5244                // Peer doesn't support address discovery
5245                if let Some(state) = &mut self.address_discovery_state {
5246                    state.enabled = false;
5247                    debug!("Address discovery disabled - peer doesn't support it");
5248                }
5249            }
5250        }
5251        
5252        // Update paths with negotiated observation rate if enabled
5253        if let Some(state) = &self.address_discovery_state {
5254            if state.enabled {
5255                self.path.set_observation_rate(state.max_observation_rate);
5256            }
5257        }
5258    }
5259
5260    fn decrypt_packet(
5261        &mut self,
5262        now: Instant,
5263        packet: &mut Packet,
5264    ) -> Result<Option<u64>, Option<TransportError>> {
5265        let result = packet_crypto::decrypt_packet_body(
5266            packet,
5267            &self.spaces,
5268            self.zero_rtt_crypto.as_ref(),
5269            self.key_phase,
5270            self.prev_crypto.as_ref(),
5271            self.next_crypto.as_ref(),
5272        )?;
5273
5274        let result = match result {
5275            Some(r) => r,
5276            None => return Ok(None),
5277        };
5278
5279        if result.outgoing_key_update_acked {
5280            if let Some(prev) = self.prev_crypto.as_mut() {
5281                prev.end_packet = Some((result.number, now));
5282                self.set_key_discard_timer(now, packet.header.space());
5283            }
5284        }
5285
5286        if result.incoming_key_update {
5287            trace!("key update authenticated");
5288            self.update_keys(Some((result.number, now)), true);
5289            self.set_key_discard_timer(now, packet.header.space());
5290        }
5291
5292        Ok(Some(result.number))
5293    }
5294
5295    fn update_keys(&mut self, end_packet: Option<(u64, Instant)>, remote: bool) {
5296        trace!("executing key update");
5297        // Generate keys for the key phase after the one we're switching to, store them in
5298        // `next_crypto`, make the contents of `next_crypto` current, and move the current keys into
5299        // `prev_crypto`.
5300        let new = self
5301            .crypto
5302            .next_1rtt_keys()
5303            .expect("only called for `Data` packets");
5304        self.key_phase_size = new
5305            .local
5306            .confidentiality_limit()
5307            .saturating_sub(KEY_UPDATE_MARGIN);
5308        let old = mem::replace(
5309            &mut self.spaces[SpaceId::Data]
5310                .crypto
5311                .as_mut()
5312                .unwrap() // safe because update_keys() can only be triggered by short packets
5313                .packet,
5314            mem::replace(self.next_crypto.as_mut().unwrap(), new),
5315        );
5316        self.spaces[SpaceId::Data].sent_with_keys = 0;
5317        self.prev_crypto = Some(PrevCrypto {
5318            crypto: old,
5319            end_packet,
5320            update_unacked: remote,
5321        });
5322        self.key_phase = !self.key_phase;
5323    }
5324
5325    fn peer_supports_ack_frequency(&self) -> bool {
5326        self.peer_params.min_ack_delay.is_some()
5327    }
5328
5329    /// Send an IMMEDIATE_ACK frame to the remote endpoint
5330    ///
5331    /// According to the spec, this will result in an error if the remote endpoint does not support
5332    /// the Acknowledgement Frequency extension
5333    pub(crate) fn immediate_ack(&mut self) {
5334        self.spaces[self.highest_space].immediate_ack_pending = true;
5335    }
5336
5337    /// Decodes a packet, returning its decrypted payload, so it can be inspected in tests
5338    #[cfg(test)]
5339    pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> {
5340        let (first_decode, remaining) = match &event.0 {
5341            ConnectionEventInner::Datagram(DatagramConnectionEvent {
5342                first_decode,
5343                remaining,
5344                ..
5345            }) => (first_decode, remaining),
5346            _ => return None,
5347        };
5348
5349        if remaining.is_some() {
5350            panic!("Packets should never be coalesced in tests");
5351        }
5352
5353        let decrypted_header = packet_crypto::unprotect_header(
5354            first_decode.clone(),
5355            &self.spaces,
5356            self.zero_rtt_crypto.as_ref(),
5357            self.peer_params.stateless_reset_token,
5358        )?;
5359
5360        let mut packet = decrypted_header.packet?;
5361        packet_crypto::decrypt_packet_body(
5362            &mut packet,
5363            &self.spaces,
5364            self.zero_rtt_crypto.as_ref(),
5365            self.key_phase,
5366            self.prev_crypto.as_ref(),
5367            self.next_crypto.as_ref(),
5368        )
5369        .ok()?;
5370
5371        Some(packet.payload.to_vec())
5372    }
5373
5374    /// The number of bytes of packets containing retransmittable frames that have not been
5375    /// acknowledged or declared lost.
5376    #[cfg(test)]
5377    pub(crate) fn bytes_in_flight(&self) -> u64 {
5378        self.path.in_flight.bytes
5379    }
5380
5381    /// Number of bytes worth of non-ack-only packets that may be sent
5382    #[cfg(test)]
5383    pub(crate) fn congestion_window(&self) -> u64 {
5384        self.path
5385            .congestion
5386            .window()
5387            .saturating_sub(self.path.in_flight.bytes)
5388    }
5389
5390    /// Whether no timers but keepalive, idle, rtt, pushnewcid, and key discard are running
5391    #[cfg(test)]
5392    pub(crate) fn is_idle(&self) -> bool {
5393        Timer::VALUES
5394            .iter()
5395            .filter(|&&t| !matches!(t, Timer::KeepAlive | Timer::PushNewCid | Timer::KeyDiscard))
5396            .filter_map(|&t| Some((t, self.timers.get(t)?)))
5397            .min_by_key(|&(_, time)| time)
5398            .map_or(true, |(timer, _)| timer == Timer::Idle)
5399    }
5400
5401    /// Total number of outgoing packets that have been deemed lost
5402    #[cfg(test)]
5403    pub(crate) fn lost_packets(&self) -> u64 {
5404        self.lost_packets
5405    }
5406
5407    /// Whether explicit congestion notification is in use on outgoing packets.
5408    #[cfg(test)]
5409    pub(crate) fn using_ecn(&self) -> bool {
5410        self.path.sending_ecn
5411    }
5412
5413    /// The number of received bytes in the current path
5414    #[cfg(test)]
5415    pub(crate) fn total_recvd(&self) -> u64 {
5416        self.path.total_recvd
5417    }
5418
5419    #[cfg(test)]
5420    pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) {
5421        self.local_cid_state.active_seq()
5422    }
5423
5424    /// Instruct the peer to replace previously issued CIDs by sending a NEW_CONNECTION_ID frame
5425    /// with updated `retire_prior_to` field set to `v`
5426    #[cfg(test)]
5427    pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) {
5428        let n = self.local_cid_state.assign_retire_seq(v);
5429        self.endpoint_events
5430            .push_back(EndpointEventInner::NeedIdentifiers(now, n));
5431    }
5432
5433    /// Check the current active remote CID sequence
5434    #[cfg(test)]
5435    pub(crate) fn active_rem_cid_seq(&self) -> u64 {
5436        self.rem_cids.active_seq()
5437    }
5438
5439    /// Returns the detected maximum udp payload size for the current path
5440    #[cfg(test)]
5441    pub(crate) fn path_mtu(&self) -> u16 {
5442        self.path.current_mtu()
5443    }
5444
5445    /// Whether we have 1-RTT data to send
5446    ///
5447    /// See also `self.space(SpaceId::Data).can_send()`
5448    fn can_send_1rtt(&self, max_size: usize) -> bool {
5449        self.streams.can_send_stream_data()
5450            || self.path.challenge_pending
5451            || self
5452                .prev_path
5453                .as_ref()
5454                .is_some_and(|(_, x)| x.challenge_pending)
5455            || !self.path_responses.is_empty()
5456            || !self.nat_traversal_challenges.is_empty()
5457            || self
5458                .datagrams
5459                .outgoing
5460                .front()
5461                .is_some_and(|x| x.size(true) <= max_size)
5462    }
5463
5464    /// Update counters to account for a packet becoming acknowledged, lost, or abandoned
5465    fn remove_in_flight(&mut self, pn: u64, packet: &SentPacket) {
5466        // Visit known paths from newest to oldest to find the one `pn` was sent on
5467        for path in [&mut self.path]
5468            .into_iter()
5469            .chain(self.prev_path.as_mut().map(|(_, data)| data))
5470        {
5471            if path.remove_in_flight(pn, packet) {
5472                return;
5473            }
5474        }
5475    }
5476
5477    /// Terminate the connection instantly, without sending a close packet
5478    fn kill(&mut self, reason: ConnectionError) {
5479        self.close_common();
5480        self.error = Some(reason);
5481        self.state = State::Drained;
5482        self.endpoint_events.push_back(EndpointEventInner::Drained);
5483    }
5484
5485    /// Generate PATH_CHALLENGE frames for NAT traversal candidate validation
5486    fn generate_nat_traversal_challenges(&mut self, now: Instant) {
5487        // Get candidates ready for validation first
5488        let candidates: Vec<(VarInt, SocketAddr)> = if let Some(nat_state) = &self.nat_traversal {
5489            nat_state
5490                .get_validation_candidates()
5491                .into_iter()
5492                .take(3) // Validate up to 3 candidates in parallel
5493                .map(|(seq, candidate)| (seq, candidate.address))
5494                .collect()
5495        } else {
5496            return;
5497        };
5498
5499        if candidates.is_empty() {
5500            return;
5501        }
5502
5503        // Now process candidates with mutable access
5504        if let Some(nat_state) = &mut self.nat_traversal {
5505            for (seq, address) in candidates {
5506                // Generate a random challenge token
5507                let challenge: u64 = self.rng.gen();
5508
5509                // Start validation for this candidate
5510                if let Err(e) = nat_state.start_validation(seq, challenge, now) {
5511                    debug!("Failed to start validation for candidate {}: {}", seq, e);
5512                    continue;
5513                }
5514
5515                // Queue the challenge
5516                self.nat_traversal_challenges.push(address, challenge);
5517                trace!(
5518                    "Queuing NAT validation PATH_CHALLENGE for {} with token {:08x}",
5519                    address, challenge
5520                );
5521            }
5522        }
5523    }
5524
5525    /// Storage size required for the largest packet known to be supported by the current path
5526    ///
5527    /// Buffers passed to [`Connection::poll_transmit`] should be at least this large.
5528    pub fn current_mtu(&self) -> u16 {
5529        self.path.current_mtu()
5530    }
5531
5532    /// Size of non-frame data for a 1-RTT packet
5533    ///
5534    /// Quantifies space consumed by the QUIC header and AEAD tag. All other bytes in a packet are
5535    /// frames. Changes if the length of the remote connection ID changes, which is expected to be
5536    /// rare. If `pn` is specified, may additionally change unpredictably due to variations in
5537    /// latency and packet loss.
5538    fn predict_1rtt_overhead(&self, pn: Option<u64>) -> usize {
5539        let pn_len = match pn {
5540            Some(pn) => PacketNumber::new(
5541                pn,
5542                self.spaces[SpaceId::Data].largest_acked_packet.unwrap_or(0),
5543            )
5544            .len(),
5545            // Upper bound
5546            None => 4,
5547        };
5548
5549        // 1 byte for flags
5550        1 + self.rem_cids.active().len() + pn_len + self.tag_len_1rtt()
5551    }
5552
5553    fn tag_len_1rtt(&self) -> usize {
5554        let key = match self.spaces[SpaceId::Data].crypto.as_ref() {
5555            Some(crypto) => Some(&*crypto.packet.local),
5556            None => self.zero_rtt_crypto.as_ref().map(|x| &*x.packet),
5557        };
5558        // If neither Data nor 0-RTT keys are available, make a reasonable tag length guess. As of
5559        // this writing, all QUIC cipher suites use 16-byte tags. We could return `None` instead,
5560        // but that would needlessly prevent sending datagrams during 0-RTT.
5561        key.map_or(16, |x| x.tag_len())
5562    }
5563
5564    /// Mark the path as validated, and enqueue NEW_TOKEN frames to be sent as appropriate
5565    fn on_path_validated(&mut self) {
5566        self.path.validated = true;
5567        let ConnectionSide::Server { server_config } = &self.side else {
5568            return;
5569        };
5570        let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens;
5571        new_tokens.clear();
5572        for _ in 0..server_config.validation_token.sent {
5573            new_tokens.push(self.path.remote);
5574        }
5575    }
5576}
5577
5578impl fmt::Debug for Connection {
5579    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5580        f.debug_struct("Connection")
5581            .field("handshake_cid", &self.handshake_cid)
5582            .finish()
5583    }
5584}
5585
5586/// Fields of `Connection` specific to it being client-side or server-side
5587enum ConnectionSide {
5588    Client {
5589        /// Sent in every outgoing Initial packet. Always empty after Initial keys are discarded
5590        token: Bytes,
5591        token_store: Arc<dyn TokenStore>,
5592        server_name: String,
5593    },
5594    Server {
5595        server_config: Arc<ServerConfig>,
5596    },
5597}
5598
5599impl ConnectionSide {
5600    fn remote_may_migrate(&self) -> bool {
5601        match self {
5602            Self::Server { server_config } => server_config.migration,
5603            Self::Client { .. } => false,
5604        }
5605    }
5606
5607    fn is_client(&self) -> bool {
5608        self.side().is_client()
5609    }
5610
5611    fn is_server(&self) -> bool {
5612        self.side().is_server()
5613    }
5614
5615    fn side(&self) -> Side {
5616        match *self {
5617            Self::Client { .. } => Side::Client,
5618            Self::Server { .. } => Side::Server,
5619        }
5620    }
5621}
5622
5623impl From<SideArgs> for ConnectionSide {
5624    fn from(side: SideArgs) -> Self {
5625        match side {
5626            SideArgs::Client {
5627                token_store,
5628                server_name,
5629            } => Self::Client {
5630                token: token_store.take(&server_name).unwrap_or_default(),
5631                token_store,
5632                server_name,
5633            },
5634            SideArgs::Server {
5635                server_config,
5636                pref_addr_cid: _,
5637                path_validated: _,
5638            } => Self::Server { server_config },
5639        }
5640    }
5641}
5642
5643/// Parameters to `Connection::new` specific to it being client-side or server-side
5644pub(crate) enum SideArgs {
5645    Client {
5646        token_store: Arc<dyn TokenStore>,
5647        server_name: String,
5648    },
5649    Server {
5650        server_config: Arc<ServerConfig>,
5651        pref_addr_cid: Option<ConnectionId>,
5652        path_validated: bool,
5653    },
5654}
5655
5656impl SideArgs {
5657    pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> {
5658        match *self {
5659            Self::Client { .. } => None,
5660            Self::Server { pref_addr_cid, .. } => pref_addr_cid,
5661        }
5662    }
5663
5664    pub(crate) fn path_validated(&self) -> bool {
5665        match *self {
5666            Self::Client { .. } => true,
5667            Self::Server { path_validated, .. } => path_validated,
5668        }
5669    }
5670
5671    pub(crate) fn side(&self) -> Side {
5672        match *self {
5673            Self::Client { .. } => Side::Client,
5674            Self::Server { .. } => Side::Server,
5675        }
5676    }
5677}
5678
5679/// Reasons why a connection might be lost
5680#[derive(Debug, Error, Clone, PartialEq, Eq)]
5681pub enum ConnectionError {
5682    /// The peer doesn't implement any supported version
5683    #[error("peer doesn't implement any supported version")]
5684    VersionMismatch,
5685    /// The peer violated the QUIC specification as understood by this implementation
5686    #[error(transparent)]
5687    TransportError(#[from] TransportError),
5688    /// The peer's QUIC stack aborted the connection automatically
5689    #[error("aborted by peer: {0}")]
5690    ConnectionClosed(frame::ConnectionClose),
5691    /// The peer closed the connection
5692    #[error("closed by peer: {0}")]
5693    ApplicationClosed(frame::ApplicationClose),
5694    /// The peer is unable to continue processing this connection, usually due to having restarted
5695    #[error("reset by peer")]
5696    Reset,
5697    /// Communication with the peer has lapsed for longer than the negotiated idle timeout
5698    ///
5699    /// If neither side is sending keep-alives, a connection will time out after a long enough idle
5700    /// period even if the peer is still reachable. See also [`TransportConfig::max_idle_timeout()`]
5701    /// and [`TransportConfig::keep_alive_interval()`].
5702    #[error("timed out")]
5703    TimedOut,
5704    /// The local application closed the connection
5705    #[error("closed")]
5706    LocallyClosed,
5707    /// The connection could not be created because not enough of the CID space is available
5708    ///
5709    /// Try using longer connection IDs.
5710    #[error("CIDs exhausted")]
5711    CidsExhausted,
5712}
5713
5714impl From<Close> for ConnectionError {
5715    fn from(x: Close) -> Self {
5716        match x {
5717            Close::Connection(reason) => Self::ConnectionClosed(reason),
5718            Close::Application(reason) => Self::ApplicationClosed(reason),
5719        }
5720    }
5721}
5722
5723// For compatibility with API consumers
5724impl From<ConnectionError> for io::Error {
5725    fn from(x: ConnectionError) -> Self {
5726        use ConnectionError::*;
5727        let kind = match x {
5728            TimedOut => io::ErrorKind::TimedOut,
5729            Reset => io::ErrorKind::ConnectionReset,
5730            ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted,
5731            TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => {
5732                io::ErrorKind::Other
5733            }
5734        };
5735        Self::new(kind, x)
5736    }
5737}
5738
5739#[allow(unreachable_pub)] // fuzzing only
5740#[derive(Clone)]
5741pub enum State {
5742    Handshake(state::Handshake),
5743    Established,
5744    Closed(state::Closed),
5745    Draining,
5746    /// Waiting for application to call close so we can dispose of the resources
5747    Drained,
5748}
5749
5750impl State {
5751    fn closed<R: Into<Close>>(reason: R) -> Self {
5752        Self::Closed(state::Closed {
5753            reason: reason.into(),
5754        })
5755    }
5756
5757    fn is_handshake(&self) -> bool {
5758        matches!(*self, Self::Handshake(_))
5759    }
5760
5761    fn is_established(&self) -> bool {
5762        matches!(*self, Self::Established)
5763    }
5764
5765    fn is_closed(&self) -> bool {
5766        matches!(*self, Self::Closed(_) | Self::Draining | Self::Drained)
5767    }
5768
5769    fn is_drained(&self) -> bool {
5770        matches!(*self, Self::Drained)
5771    }
5772}
5773
5774mod state {
5775    use super::*;
5776
5777    #[allow(unreachable_pub)] // fuzzing only
5778    #[derive(Clone)]
5779    pub struct Handshake {
5780        /// Whether the remote CID has been set by the peer yet
5781        ///
5782        /// Always set for servers
5783        pub(super) rem_cid_set: bool,
5784        /// Stateless retry token received in the first Initial by a server.
5785        ///
5786        /// Must be present in every Initial. Always empty for clients.
5787        pub(super) expected_token: Bytes,
5788        /// First cryptographic message
5789        ///
5790        /// Only set for clients
5791        pub(super) client_hello: Option<Bytes>,
5792    }
5793
5794    #[allow(unreachable_pub)] // fuzzing only
5795    #[derive(Clone)]
5796    pub struct Closed {
5797        pub(super) reason: Close,
5798    }
5799}
5800
5801/// Events of interest to the application
5802#[derive(Debug)]
5803pub enum Event {
5804    /// The connection's handshake data is ready
5805    HandshakeDataReady,
5806    /// The connection was successfully established
5807    Connected,
5808    /// The connection was lost
5809    ///
5810    /// Emitted if the peer closes the connection or an error is encountered.
5811    ConnectionLost {
5812        /// Reason that the connection was closed
5813        reason: ConnectionError,
5814    },
5815    /// Stream events
5816    Stream(StreamEvent),
5817    /// One or more application datagrams have been received
5818    DatagramReceived,
5819    /// One or more application datagrams have been sent after blocking
5820    DatagramsUnblocked,
5821}
5822
5823fn instant_saturating_sub(x: Instant, y: Instant) -> Duration {
5824    if x > y { x - y } else { Duration::ZERO }
5825}
5826
5827fn get_max_ack_delay(params: &TransportParameters) -> Duration {
5828    Duration::from_micros(params.max_ack_delay.0 * 1000)
5829}
5830
5831// Prevents overflow and improves behavior in extreme circumstances
5832const MAX_BACKOFF_EXPONENT: u32 = 16;
5833
5834/// Minimal remaining size to allow packet coalescing, excluding cryptographic tag
5835///
5836/// This must be at least as large as the header for a well-formed empty packet to be coalesced,
5837/// plus some space for frames. We only care about handshake headers because short header packets
5838/// necessarily have smaller headers, and initial packets are only ever the first packet in a
5839/// datagram (because we coalesce in ascending packet space order and the only reason to split a
5840/// packet is when packet space changes).
5841const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32;
5842
5843/// Largest amount of space that could be occupied by a Handshake or 0-RTT packet's header
5844///
5845/// Excludes packet-type-specific fields such as packet number or Initial token
5846// https://www.rfc-editor.org/rfc/rfc9000.html#name-0-rtt: flags + version + dcid len + dcid +
5847// scid len + scid + length + pn
5848const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize =
5849    1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4;
5850
5851/// Perform key updates this many packets before the AEAD confidentiality limit.
5852///
5853/// Chosen arbitrarily, intended to be large enough to prevent spurious connection loss.
5854const KEY_UPDATE_MARGIN: u64 = 10_000;
5855
5856#[derive(Default)]
5857struct SentFrames {
5858    retransmits: ThinRetransmits,
5859    largest_acked: Option<u64>,
5860    stream_frames: StreamMetaVec,
5861    /// Whether the packet contains non-retransmittable frames (like datagrams)
5862    non_retransmits: bool,
5863    requires_padding: bool,
5864}
5865
5866impl SentFrames {
5867    /// Returns whether the packet contains only ACKs
5868    fn is_ack_only(&self, streams: &StreamsState) -> bool {
5869        self.largest_acked.is_some()
5870            && !self.non_retransmits
5871            && self.stream_frames.is_empty()
5872            && self.retransmits.is_empty(streams)
5873    }
5874}
5875
5876/// Compute the negotiated idle timeout based on local and remote max_idle_timeout transport parameters.
5877///
5878/// 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.>
5879///
5880/// 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.>
5881///
5882/// Returns the negotiated idle timeout as a `Duration`, or `None` when both endpoints have opted out of idle timeout.
5883fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> {
5884    match (x, y) {
5885        (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None,
5886        (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)),
5887        (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)),
5888        (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)),
5889    }
5890}
5891
5892/// State for tracking address discovery via OBSERVED_ADDRESS frames
5893#[derive(Debug, Clone)]
5894struct AddressDiscoveryState {
5895    /// Whether address discovery is enabled for this connection
5896    enabled: bool,
5897    /// Maximum rate of OBSERVED_ADDRESS frames per path (per second)
5898    max_observation_rate: u8,
5899    /// Whether to observe addresses for all paths or just primary
5900    observe_all_paths: bool,
5901    /// Per-path address information
5902    path_addresses: std::collections::HashMap<u64, paths::PathAddressInfo>,
5903    /// Rate limiter for sending observations
5904    rate_limiter: AddressObservationRateLimiter,
5905    /// Addresses we've been told about by peers
5906    observed_addresses: Vec<ObservedAddressEvent>,
5907    /// Whether this connection is in bootstrap mode (aggressive observation)
5908    bootstrap_mode: bool,
5909}
5910
5911/// Event for when we receive an OBSERVED_ADDRESS frame
5912#[derive(Debug, Clone, PartialEq, Eq)]
5913struct ObservedAddressEvent {
5914    /// The address the peer observed
5915    address: SocketAddr,
5916    /// When we received this observation
5917    received_at: Instant,
5918    /// Which path this was received on
5919    path_id: u64,
5920}
5921
5922/// Rate limiter for address observations
5923#[derive(Debug, Clone)]
5924struct AddressObservationRateLimiter {
5925    /// Tokens available for sending observations
5926    tokens: f64,
5927    /// Maximum tokens (burst capacity)
5928    max_tokens: f64,
5929    /// Rate of token replenishment (tokens per second)
5930    rate: f64,
5931    /// Last time tokens were updated
5932    last_update: Instant,
5933}
5934
5935impl AddressDiscoveryState {
5936    /// Create a new address discovery state
5937    fn new(config: &crate::transport_parameters::AddressDiscoveryConfig, now: Instant) -> Self {
5938        Self {
5939            enabled: config.enabled,
5940            max_observation_rate: config.max_observation_rate,
5941            observe_all_paths: config.observe_all_paths,
5942            path_addresses: std::collections::HashMap::new(),
5943            rate_limiter: AddressObservationRateLimiter::new(config.max_observation_rate, now),
5944            observed_addresses: Vec::new(),
5945            bootstrap_mode: false,
5946        }
5947    }
5948
5949    /// Check if we should send an observation for the given path
5950    fn should_send_observation(&mut self, path_id: u64, now: Instant) -> bool {
5951        // Use the new should_observe_path method which considers bootstrap mode
5952        if !self.should_observe_path(path_id) {
5953            return false;
5954        }
5955
5956        // Check if this is a new path or if the address has changed
5957        let needs_observation = match self.path_addresses.get(&path_id) {
5958            Some(info) => info.observed_address.is_none() || !info.notified,
5959            None => true,
5960        };
5961
5962        if !needs_observation {
5963            return false;
5964        }
5965
5966        // Check rate limit
5967        self.rate_limiter.try_consume(1.0, now)
5968    }
5969
5970    /// Record that we sent an observation for a path
5971    fn record_observation_sent(&mut self, path_id: u64) {
5972        if let Some(info) = self.path_addresses.get_mut(&path_id) {
5973            info.mark_notified();
5974        }
5975    }
5976
5977    /// Handle receiving an OBSERVED_ADDRESS frame
5978    fn handle_observed_address(&mut self, address: SocketAddr, path_id: u64, now: Instant) {
5979        if !self.enabled {
5980            return;
5981        }
5982
5983        self.observed_addresses.push(ObservedAddressEvent {
5984            address,
5985            received_at: now,
5986            path_id,
5987        });
5988
5989        // Update or create path info
5990        let info = self.path_addresses.entry(path_id).or_insert_with(|| {
5991            paths::PathAddressInfo::new()
5992        });
5993        info.update_observed_address(address, now);
5994    }
5995
5996    /// Get the most recently observed address for a path
5997    pub(crate) fn get_observed_address(&self, path_id: u64) -> Option<SocketAddr> {
5998        self.path_addresses.get(&path_id)
5999            .and_then(|info| info.observed_address)
6000    }
6001    
6002    /// Get all observed addresses across all paths
6003    pub(crate) fn get_all_observed_addresses(&self) -> Vec<SocketAddr> {
6004        self.path_addresses
6005            .values()
6006            .filter_map(|info| info.observed_address)
6007            .collect()
6008    }
6009    
6010    /// Get statistics for address discovery
6011    pub(crate) fn stats(&self) -> AddressDiscoveryStats {
6012        AddressDiscoveryStats {
6013            frames_sent: self.observed_addresses.len() as u64, // Using observed_addresses as a proxy
6014            frames_received: self.observed_addresses.len() as u64,
6015            addresses_discovered: self.path_addresses
6016                .values()
6017                .filter(|info| info.observed_address.is_some())
6018                .count() as u64,
6019            address_changes_detected: 0, // TODO: Track address changes properly
6020        }
6021    }
6022
6023    /// Check if we have any unnotified address changes
6024    fn has_unnotified_changes(&self) -> bool {
6025        self.path_addresses.values()
6026            .any(|info| info.observed_address.is_some() && !info.notified)
6027    }
6028
6029    /// Queue an OBSERVED_ADDRESS frame for sending if conditions are met
6030    fn queue_observed_address_frame(&mut self, path_id: u64, address: SocketAddr) -> Option<frame::ObservedAddress> {
6031        // Check if address discovery is enabled
6032        if !self.enabled {
6033            return None;
6034        }
6035
6036        // Check path restrictions
6037        if !self.observe_all_paths && path_id != 0 {
6038            return None;
6039        }
6040
6041        // Check if this path has already been notified
6042        if let Some(info) = self.path_addresses.get(&path_id) {
6043            if info.notified {
6044                return None;
6045            }
6046        }
6047
6048        // Check rate limiting
6049        if self.rate_limiter.tokens < 1.0 {
6050            return None;
6051        }
6052
6053        // Consume a token and update path info
6054        self.rate_limiter.tokens -= 1.0;
6055        
6056        // Update or create path info
6057        let info = self.path_addresses.entry(path_id).or_insert_with(|| {
6058            paths::PathAddressInfo::new()
6059        });
6060        info.observed_address = Some(address);
6061        info.notified = true;
6062
6063        // Create and return the frame
6064        Some(frame::ObservedAddress { address })
6065    }
6066
6067    /// Check for address observations that need to be sent
6068    fn check_for_address_observations(
6069        &mut self, 
6070        _current_path: u64,  
6071        peer_supports_address_discovery: bool, 
6072        now: Instant
6073    ) -> Vec<frame::ObservedAddress> {
6074        let mut frames = Vec::new();
6075
6076        // Check if we should send observations
6077        if !self.enabled || !peer_supports_address_discovery {
6078            return frames;
6079        }
6080
6081        // Update rate limiter tokens
6082        self.rate_limiter.update_tokens(now);
6083
6084        // Collect all paths that need observation frames
6085        let paths_to_notify: Vec<u64> = self.path_addresses.iter()
6086            .filter_map(|(&path_id, info)| {
6087                if info.observed_address.is_some() && !info.notified {
6088                    Some(path_id)
6089                } else {
6090                    None
6091                }
6092            })
6093            .collect();
6094
6095        // Send frames for each path that needs notification
6096        for path_id in paths_to_notify {
6097            // Check path restrictions (considers bootstrap mode)
6098            if !self.should_observe_path(path_id) {
6099                continue;
6100            }
6101
6102            // Check rate limiting (bootstrap nodes get more lenient limits)
6103            if !self.bootstrap_mode && self.rate_limiter.tokens < 1.0 {
6104                break; // No more tokens available for non-bootstrap nodes
6105            }
6106
6107            // Get the address
6108            if let Some(info) = self.path_addresses.get_mut(&path_id) {
6109                if let Some(address) = info.observed_address {
6110                    // Consume a token (bootstrap nodes consume at reduced rate)
6111                    if self.bootstrap_mode {
6112                        self.rate_limiter.tokens -= 0.2; // Bootstrap nodes consume 1/5th token
6113                    } else {
6114                        self.rate_limiter.tokens -= 1.0;
6115                    }
6116                    
6117                    // Mark as notified
6118                    info.notified = true;
6119                    
6120                    // Create frame
6121                    frames.push(frame::ObservedAddress { address });
6122                }
6123            }
6124        }
6125
6126        frames
6127    }
6128
6129    /// Update the rate limit configuration
6130    fn update_rate_limit(&mut self, new_rate: f64) {
6131        self.max_observation_rate = new_rate as u8;
6132        self.rate_limiter.set_rate(new_rate as u8);
6133    }
6134
6135    /// Create from transport parameters
6136    fn from_transport_params(params: &TransportParameters) -> Option<Self> {
6137        params.address_discovery.as_ref().map(|config| {
6138            Self::new(config, Instant::now())
6139        })
6140    }
6141
6142    /// Alternative constructor for tests - creates with simplified parameters
6143    #[cfg(test)]
6144    fn new_with_params(enabled: bool, max_rate: f64, observe_all_paths: bool) -> Self {
6145        let config = crate::transport_parameters::AddressDiscoveryConfig {
6146            enabled,
6147            max_observation_rate: max_rate as u8,
6148            observe_all_paths,
6149        };
6150        Self::new(&config, Instant::now())
6151    }
6152    
6153    /// Enable or disable bootstrap mode (aggressive observation)
6154    fn set_bootstrap_mode(&mut self, enabled: bool) {
6155        self.bootstrap_mode = enabled;
6156        // If enabling bootstrap mode, update rate limiter to allow higher rates
6157        if enabled {
6158            let bootstrap_rate = self.get_effective_rate_limit();
6159            self.rate_limiter.rate = bootstrap_rate;
6160            self.rate_limiter.max_tokens = bootstrap_rate * 2.0; // Allow burst of 2 seconds
6161            // Also fill tokens to max for immediate use
6162            self.rate_limiter.tokens = self.rate_limiter.max_tokens;
6163        }
6164    }
6165    
6166    /// Check if bootstrap mode is enabled
6167    fn is_bootstrap_mode(&self) -> bool {
6168        self.bootstrap_mode
6169    }
6170    
6171    /// Get the effective rate limit (considering bootstrap mode)
6172    fn get_effective_rate_limit(&self) -> f64 {
6173        if self.bootstrap_mode {
6174            // Bootstrap nodes get 5x the configured rate
6175            (self.max_observation_rate as f64) * 5.0
6176        } else {
6177            self.max_observation_rate as f64
6178        }
6179    }
6180    
6181    /// Check if we should observe this path (considering bootstrap mode)
6182    fn should_observe_path(&self, path_id: u64) -> bool {
6183        if !self.enabled {
6184            return false;
6185        }
6186        
6187        // Bootstrap nodes observe all paths regardless of configuration
6188        if self.bootstrap_mode {
6189            return true;
6190        }
6191        
6192        // Normal mode respects the configuration
6193        self.observe_all_paths || path_id == 0
6194    }
6195    
6196    /// Check if we should send observation immediately (for bootstrap nodes)
6197    fn should_send_observation_immediately(&self, is_new_connection: bool) -> bool {
6198        self.bootstrap_mode && is_new_connection
6199    }
6200}
6201
6202impl AddressObservationRateLimiter {
6203    /// Create a new rate limiter
6204    fn new(rate: u8, now: Instant) -> Self {
6205        let rate_f64 = rate as f64;
6206        Self {
6207            tokens: rate_f64,
6208            max_tokens: rate_f64,
6209            rate: rate_f64,
6210            last_update: now,
6211        }
6212    }
6213
6214    /// Try to consume tokens, returns true if successful
6215    fn try_consume(&mut self, tokens: f64, now: Instant) -> bool {
6216        self.update_tokens(now);
6217        
6218        if self.tokens >= tokens {
6219            self.tokens -= tokens;
6220            true
6221        } else {
6222            false
6223        }
6224    }
6225
6226    /// Update available tokens based on elapsed time
6227    fn update_tokens(&mut self, now: Instant) {
6228        let elapsed = now.saturating_duration_since(self.last_update);
6229        let new_tokens = elapsed.as_secs_f64() * self.rate;
6230        self.tokens = (self.tokens + new_tokens).min(self.max_tokens);
6231        self.last_update = now;
6232    }
6233
6234    /// Update the rate
6235    fn set_rate(&mut self, rate: u8) {
6236        let rate_f64 = rate as f64;
6237        self.rate = rate_f64;
6238        self.max_tokens = rate_f64;
6239        // Don't change current tokens, just cap at new max
6240        if self.tokens > self.max_tokens {
6241            self.tokens = self.max_tokens;
6242        }
6243    }
6244}
6245
6246#[cfg(test)]
6247mod tests {
6248    use super::*;
6249    use crate::transport_parameters::AddressDiscoveryConfig;
6250    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
6251
6252    #[test]
6253    fn address_discovery_state_new() {
6254        let config = crate::transport_parameters::AddressDiscoveryConfig {
6255            enabled: true,
6256            max_observation_rate: 10,
6257            observe_all_paths: false,
6258        };
6259        let now = Instant::now();
6260        let state = AddressDiscoveryState::new(&config, now);
6261        
6262        assert!(state.enabled);
6263        assert_eq!(state.max_observation_rate, 10);
6264        assert!(!state.observe_all_paths);
6265        assert!(state.path_addresses.is_empty());
6266        assert!(state.observed_addresses.is_empty());
6267        assert_eq!(state.rate_limiter.tokens, 10.0);
6268    }
6269
6270    #[test]
6271    fn address_discovery_state_disabled() {
6272        let config = crate::transport_parameters::AddressDiscoveryConfig {
6273            enabled: false,
6274            max_observation_rate: 10,
6275            observe_all_paths: false,
6276        };
6277        let now = Instant::now();
6278        let mut state = AddressDiscoveryState::new(&config, now);
6279        
6280        // Should not send observations when disabled
6281        assert!(!state.should_send_observation(0, now));
6282    }
6283
6284    #[test]
6285    fn address_discovery_state_should_send_observation() {
6286        let config = crate::transport_parameters::AddressDiscoveryConfig {
6287            enabled: true,
6288            max_observation_rate: 10,
6289            observe_all_paths: true,
6290        };
6291        let now = Instant::now();
6292        let mut state = AddressDiscoveryState::new(&config, now);
6293        
6294        // Should send for new path
6295        assert!(state.should_send_observation(0, now));
6296        
6297        // Add path info
6298        let mut path_info = paths::PathAddressInfo::new();
6299        path_info.update_observed_address(
6300            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080),
6301            now
6302        );
6303        path_info.mark_notified();
6304        state.path_addresses.insert(0, path_info);
6305        
6306        // Should not send if already notified
6307        assert!(!state.should_send_observation(0, now));
6308        
6309        // But should send for different path
6310        assert!(state.should_send_observation(1, now));
6311    }
6312
6313    #[test]
6314    fn address_discovery_state_rate_limiting() {
6315        let config = crate::transport_parameters::AddressDiscoveryConfig {
6316            enabled: true,
6317            max_observation_rate: 2, // 2 per second
6318            observe_all_paths: true,
6319        };
6320        let now = Instant::now();
6321        let mut state = AddressDiscoveryState::new(&config, now);
6322        
6323        // Should allow first two
6324        assert!(state.should_send_observation(0, now));
6325        assert!(state.should_send_observation(1, now));
6326        
6327        // Third should be rate limited
6328        assert!(!state.should_send_observation(2, now));
6329        
6330        // After 1 second, should have 2 more tokens
6331        let later = now + Duration::from_secs(1);
6332        assert!(state.should_send_observation(2, later));
6333        assert!(state.should_send_observation(3, later));
6334        assert!(!state.should_send_observation(4, later));
6335    }
6336
6337    #[test]
6338    fn address_discovery_state_handle_observed_address() {
6339        let config = crate::transport_parameters::AddressDiscoveryConfig {
6340            enabled: true,
6341            max_observation_rate: 10,
6342            observe_all_paths: true,
6343        };
6344        let now = Instant::now();
6345        let mut state = AddressDiscoveryState::new(&config, now);
6346        
6347        let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 443);
6348        let addr2 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)), 8080);
6349        
6350        // Handle first observation
6351        state.handle_observed_address(addr1, 0, now);
6352        assert_eq!(state.observed_addresses.len(), 1);
6353        assert_eq!(state.observed_addresses[0].address, addr1);
6354        assert_eq!(state.observed_addresses[0].path_id, 0);
6355        
6356        // Handle second observation
6357        let later = now + Duration::from_millis(100);
6358        state.handle_observed_address(addr2, 1, later);
6359        assert_eq!(state.observed_addresses.len(), 2);
6360        assert_eq!(state.observed_addresses[1].address, addr2);
6361        assert_eq!(state.observed_addresses[1].path_id, 1);
6362    }
6363
6364    #[test]
6365    fn address_discovery_state_get_observed_address() {
6366        let config = crate::transport_parameters::AddressDiscoveryConfig {
6367            enabled: true,
6368            max_observation_rate: 10,
6369            observe_all_paths: true,
6370        };
6371        let now = Instant::now();
6372        let mut state = AddressDiscoveryState::new(&config, now);
6373        
6374        // No address initially
6375        assert_eq!(state.get_observed_address(0), None);
6376        
6377        // Add path info
6378        let mut path_info = paths::PathAddressInfo::new();
6379        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80);
6380        path_info.update_observed_address(addr, now);
6381        state.path_addresses.insert(0, path_info);
6382        
6383        // Should return the address
6384        assert_eq!(state.get_observed_address(0), Some(addr));
6385        assert_eq!(state.get_observed_address(1), None);
6386    }
6387
6388    #[test]
6389    fn address_discovery_state_unnotified_changes() {
6390        let config = crate::transport_parameters::AddressDiscoveryConfig {
6391            enabled: true,
6392            max_observation_rate: 10,
6393            observe_all_paths: true,
6394        };
6395        let now = Instant::now();
6396        let mut state = AddressDiscoveryState::new(&config, now);
6397        
6398        // No changes initially
6399        assert!(!state.has_unnotified_changes());
6400        
6401        // Add unnotified path
6402        let mut path_info = paths::PathAddressInfo::new();
6403        path_info.update_observed_address(
6404            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080),
6405            now
6406        );
6407        state.path_addresses.insert(0, path_info);
6408        
6409        // Should have unnotified changes
6410        assert!(state.has_unnotified_changes());
6411        
6412        // Mark as notified
6413        state.record_observation_sent(0);
6414        assert!(!state.has_unnotified_changes());
6415    }
6416
6417    #[test]
6418    fn address_observation_rate_limiter_token_bucket() {
6419        let now = Instant::now();
6420        let mut limiter = AddressObservationRateLimiter::new(5, now); // 5 tokens/sec
6421        
6422        // Initial state
6423        assert_eq!(limiter.tokens, 5.0);
6424        assert_eq!(limiter.max_tokens, 5.0);
6425        assert_eq!(limiter.rate, 5.0);
6426        
6427        // Consume 3 tokens
6428        assert!(limiter.try_consume(3.0, now));
6429        assert_eq!(limiter.tokens, 2.0);
6430        
6431        // Try to consume more than available
6432        assert!(!limiter.try_consume(3.0, now));
6433        assert_eq!(limiter.tokens, 2.0);
6434        
6435        // After 1 second, should have 5 more tokens (capped at max)
6436        let later = now + Duration::from_secs(1);
6437        limiter.update_tokens(later);
6438        assert_eq!(limiter.tokens, 5.0); // 2 + 5 = 7, but capped at 5
6439        
6440        // After 0.5 seconds from original, should have 2.5 more tokens
6441        let half_sec = now + Duration::from_millis(500);
6442        let mut limiter2 = AddressObservationRateLimiter::new(5, now);
6443        limiter2.try_consume(3.0, now);
6444        limiter2.update_tokens(half_sec);
6445        assert_eq!(limiter2.tokens, 4.5); // 2 + 2.5
6446    }
6447
6448    // Tests for address_discovery_state field in Connection
6449    #[test]
6450    fn connection_initializes_address_discovery_state_default() {
6451        // Test that Connection initializes with default address discovery state
6452        // For now, just test that AddressDiscoveryState can be created with default config
6453        let config = crate::transport_parameters::AddressDiscoveryConfig::default();
6454        let state = AddressDiscoveryState::new(&config, Instant::now());
6455        assert!(state.enabled); // Default is now enabled
6456        assert_eq!(state.max_observation_rate, 10); // Default is 10
6457        assert!(!state.observe_all_paths);
6458    }
6459    
6460    #[test]
6461    fn connection_initializes_with_address_discovery_enabled() {
6462        // Test that AddressDiscoveryState can be created with enabled config
6463        let config = crate::transport_parameters::AddressDiscoveryConfig {
6464            enabled: true,
6465            max_observation_rate: 10,
6466            observe_all_paths: false,
6467        };
6468        let state = AddressDiscoveryState::new(&config, Instant::now());
6469        assert!(state.enabled);
6470        assert_eq!(state.max_observation_rate, 10);
6471        assert!(!state.observe_all_paths);
6472    }
6473    
6474    #[test]
6475    fn connection_address_discovery_enabled_by_default() {
6476        // Test that AddressDiscoveryState is enabled with default config
6477        let config = crate::transport_parameters::AddressDiscoveryConfig::default();
6478        let state = AddressDiscoveryState::new(&config, Instant::now());
6479        assert!(state.enabled); // Default is now enabled
6480    }
6481
6482    #[test]
6483    fn negotiate_max_idle_timeout_commutative() {
6484        let test_params = [
6485            (None, None, None),
6486            (None, Some(VarInt(0)), None),
6487            (None, Some(VarInt(2)), Some(Duration::from_millis(2))),
6488            (Some(VarInt(0)), Some(VarInt(0)), None),
6489            (
6490                Some(VarInt(2)),
6491                Some(VarInt(0)),
6492                Some(Duration::from_millis(2)),
6493            ),
6494            (
6495                Some(VarInt(1)),
6496                Some(VarInt(4)),
6497                Some(Duration::from_millis(1)),
6498            ),
6499        ];
6500
6501        for (left, right, result) in test_params {
6502            assert_eq!(negotiate_max_idle_timeout(left, right), result);
6503            assert_eq!(negotiate_max_idle_timeout(right, left), result);
6504        }
6505    }
6506
6507    #[test]
6508    fn path_creation_initializes_address_discovery() {
6509        let config = TransportConfig::default();
6510        let remote = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6511        let now = Instant::now();
6512        
6513        // Test initial path creation
6514        let path = paths::PathData::new(remote, false, None, now, &config);
6515        
6516        // Should have address info initialized
6517        assert!(path.address_info.observed_address.is_none());
6518        assert!(path.address_info.last_observed.is_none());
6519        assert_eq!(path.address_info.observation_count, 0);
6520        assert!(!path.address_info.notified);
6521        
6522        // Should have rate limiter initialized
6523        assert_eq!(path.observation_rate_limiter.rate, 10.0);
6524        assert_eq!(path.observation_rate_limiter.max_tokens, 10.0);
6525        assert_eq!(path.observation_rate_limiter.tokens, 10.0);
6526    }
6527
6528    #[test]
6529    fn path_migration_resets_address_discovery() {
6530        let config = TransportConfig::default();
6531        let remote1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6532        let remote2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 443);
6533        let now = Instant::now();
6534        
6535        // Create initial path with some address discovery state
6536        let mut path1 = paths::PathData::new(remote1, false, None, now, &config);
6537        path1.update_observed_address(remote1, now);
6538        path1.mark_address_notified();
6539        path1.consume_observation_token(now);
6540        path1.set_observation_rate(20);
6541        
6542        // Migrate to new path
6543        let path2 = paths::PathData::from_previous(remote2, &path1, now);
6544        
6545        // Address info should be reset
6546        assert!(path2.address_info.observed_address.is_none());
6547        assert!(path2.address_info.last_observed.is_none());
6548        assert_eq!(path2.address_info.observation_count, 0);
6549        assert!(!path2.address_info.notified);
6550        
6551        // Rate limiter should have same rate but full tokens
6552        assert_eq!(path2.observation_rate_limiter.rate, 20.0);
6553        assert_eq!(path2.observation_rate_limiter.tokens, 20.0);
6554    }
6555
6556    #[test]
6557    fn connection_path_updates_observation_rate() {
6558        let config = TransportConfig::default();
6559        let remote = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 42);
6560        let now = Instant::now();
6561        
6562        let mut path = paths::PathData::new(remote, false, None, now, &config);
6563        
6564        // Initial rate should be default
6565        assert_eq!(path.observation_rate_limiter.rate, 10.0);
6566        
6567        // Update rate based on negotiated config
6568        path.set_observation_rate(25);
6569        assert_eq!(path.observation_rate_limiter.rate, 25.0);
6570        assert_eq!(path.observation_rate_limiter.max_tokens, 25.0);
6571        
6572        // Tokens should be capped at new max if needed
6573        path.observation_rate_limiter.tokens = 30.0; // Set higher than max
6574        path.set_observation_rate(20);
6575        assert_eq!(path.observation_rate_limiter.tokens, 20.0); // Capped at new max
6576    }
6577
6578    #[test]
6579    fn path_validation_preserves_discovery_state() {
6580        let config = TransportConfig::default();
6581        let remote = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6582        let now = Instant::now();
6583        
6584        let mut path = paths::PathData::new(remote, false, None, now, &config);
6585        
6586        // Set up some discovery state
6587        let observed = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 5678);
6588        path.update_observed_address(observed, now);
6589        path.set_observation_rate(15);
6590        
6591        // Simulate path validation
6592        path.validated = true;
6593        
6594        // Discovery state should be preserved
6595        assert_eq!(path.address_info.observed_address, Some(observed));
6596        assert_eq!(path.observation_rate_limiter.rate, 15.0);
6597    }
6598
6599    #[test]
6600    fn address_discovery_state_initialization() {
6601        let mut config = AddressDiscoveryConfig::default();
6602        config.enabled = true;
6603        config.max_observation_rate = 30;
6604        config.observe_all_paths = true;
6605        
6606        let now = Instant::now();
6607        let state = AddressDiscoveryState::new(&config, now);
6608        
6609        assert!(state.enabled);
6610        assert_eq!(state.max_observation_rate, 30);
6611        assert!(state.observe_all_paths);
6612        assert!(state.path_addresses.is_empty());
6613        assert!(state.observed_addresses.is_empty());
6614    }
6615
6616    // Tests for Task 2.3: Frame Processing Pipeline
6617    #[test]
6618    fn handle_observed_address_frame_basic() {
6619        let config = AddressDiscoveryConfig {
6620            enabled: true,
6621            max_observation_rate: 10,
6622            observe_all_paths: false,
6623        };
6624        let mut state = AddressDiscoveryState::new(&config, Instant::now());
6625        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6626        let now = Instant::now();
6627        let path_id = 0;
6628        
6629        // Handle an observed address frame
6630        state.handle_observed_address(addr, path_id, now);
6631        
6632        // Should have recorded the observation
6633        assert_eq!(state.observed_addresses.len(), 1);
6634        assert_eq!(state.observed_addresses[0].address, addr);
6635        assert_eq!(state.observed_addresses[0].path_id, path_id);
6636        assert_eq!(state.observed_addresses[0].received_at, now);
6637        
6638        // Should have updated path state
6639        assert!(state.path_addresses.contains_key(&path_id));
6640        let path_info = &state.path_addresses[&path_id];
6641        assert_eq!(path_info.observed_address, Some(addr));
6642        assert_eq!(path_info.last_observed, Some(now));
6643        assert_eq!(path_info.observation_count, 1);
6644    }
6645
6646    #[test]
6647    fn handle_observed_address_frame_multiple_observations() {
6648        let config = AddressDiscoveryConfig {
6649            enabled: true,
6650            max_observation_rate: 10,
6651            observe_all_paths: false,
6652        };
6653        let mut state = AddressDiscoveryState::new(&config, Instant::now());
6654        let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6655        let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 443);
6656        let now = Instant::now();
6657        let path_id = 0;
6658        
6659        // Handle multiple observations
6660        state.handle_observed_address(addr1, path_id, now);
6661        state.handle_observed_address(addr1, path_id, now + Duration::from_secs(1));
6662        state.handle_observed_address(addr2, path_id, now + Duration::from_secs(2));
6663        
6664        // Should have all observations in the event list
6665        assert_eq!(state.observed_addresses.len(), 3);
6666        
6667        // Path info should reflect the latest observation
6668        let path_info = &state.path_addresses[&path_id];
6669        assert_eq!(path_info.observed_address, Some(addr2));
6670        assert_eq!(path_info.observation_count, 1); // Reset for new address
6671    }
6672
6673    #[test]
6674    fn handle_observed_address_frame_disabled() {
6675        let mut config = AddressDiscoveryConfig::default();
6676        config.enabled = false;
6677        let mut state = AddressDiscoveryState::new(&config, Instant::now());
6678        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6679        let now = Instant::now();
6680        
6681        // Should not handle when disabled
6682        state.handle_observed_address(addr, 0, now);
6683        
6684        // Should not record anything
6685        assert!(state.observed_addresses.is_empty());
6686        assert!(state.path_addresses.is_empty());
6687    }
6688
6689    #[test]
6690    fn should_send_observation_basic() {
6691        let mut config = AddressDiscoveryConfig::default();
6692        config.enabled = true;
6693        config.max_observation_rate = 10;
6694        let mut state = AddressDiscoveryState::new(&config, Instant::now());
6695        let now = Instant::now();
6696        let path_id = 0;
6697        
6698        // Should be able to send initially
6699        assert!(state.should_send_observation(path_id, now));
6700        
6701        // Record that we sent one
6702        state.record_observation_sent(path_id);
6703        
6704        // Should still be able to send (have tokens)
6705        assert!(state.should_send_observation(path_id, now));
6706    }
6707
6708    #[test]
6709    fn should_send_observation_rate_limiting() {
6710        let mut config = AddressDiscoveryConfig::default();
6711        config.enabled = true;
6712        config.max_observation_rate = 2; // Very low rate
6713        let now = Instant::now();
6714        let mut state = AddressDiscoveryState::new(&config, now);
6715        let path_id = 0;
6716        
6717        // Consume all tokens
6718        assert!(state.should_send_observation(path_id, now));
6719        state.record_observation_sent(path_id);
6720        assert!(state.should_send_observation(path_id, now));
6721        state.record_observation_sent(path_id);
6722        
6723        // Should be rate limited now
6724        assert!(!state.should_send_observation(path_id, now));
6725        
6726        // Wait for token replenishment
6727        let later = now + Duration::from_secs(1);
6728        assert!(state.should_send_observation(path_id, later));
6729    }
6730
6731    #[test]
6732    fn should_send_observation_disabled() {
6733        let mut config = AddressDiscoveryConfig::default();
6734        config.enabled = false;
6735        let mut state = AddressDiscoveryState::new(&config, Instant::now());
6736        
6737        // Should never send when disabled
6738        assert!(!state.should_send_observation(0, Instant::now()));
6739    }
6740
6741    #[test]
6742    fn should_send_observation_per_path() {
6743        let mut config = AddressDiscoveryConfig::default();
6744        config.enabled = true;
6745        config.max_observation_rate = 2; // Allow 2 observations per second
6746        config.observe_all_paths = true;
6747        let now = Instant::now();
6748        let mut state = AddressDiscoveryState::new(&config, now);
6749        
6750        // Path 0 uses a token from the shared rate limiter
6751        assert!(state.should_send_observation(0, now));
6752        state.record_observation_sent(0);
6753        
6754        // Path 1 can still send because we have 2 tokens per second
6755        assert!(state.should_send_observation(1, now));
6756        state.record_observation_sent(1);
6757        
6758        // Now both paths should be rate limited (no more tokens)
6759        assert!(!state.should_send_observation(0, now));
6760        assert!(!state.should_send_observation(1, now));
6761        
6762        // After 1 second, we should have new tokens
6763        let later = now + Duration::from_secs(1);
6764        assert!(state.should_send_observation(0, later));
6765    }
6766
6767    #[test]
6768    fn has_unnotified_changes_test() {
6769        let config = AddressDiscoveryConfig {
6770            enabled: true,
6771            max_observation_rate: 10,
6772            observe_all_paths: false,
6773        };
6774        let mut state = AddressDiscoveryState::new(&config, Instant::now());
6775        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6776        let now = Instant::now();
6777        
6778        // Initially no changes
6779        assert!(!state.has_unnotified_changes());
6780        
6781        // After receiving an observation
6782        state.handle_observed_address(addr, 0, now);
6783        assert!(state.has_unnotified_changes());
6784        
6785        // After marking as notified
6786        state.path_addresses.get_mut(&0).unwrap().notified = true;
6787        assert!(!state.has_unnotified_changes());
6788    }
6789
6790    #[test]
6791    fn get_observed_address_test() {
6792        let config = AddressDiscoveryConfig {
6793            enabled: true,
6794            max_observation_rate: 10,
6795            observe_all_paths: false,
6796        };
6797        let mut state = AddressDiscoveryState::new(&config, Instant::now());
6798        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6799        let now = Instant::now();
6800        let path_id = 0;
6801        
6802        // Initially no address
6803        assert_eq!(state.get_observed_address(path_id), None);
6804        
6805        // After observation
6806        state.handle_observed_address(addr, path_id, now);
6807        assert_eq!(state.get_observed_address(path_id), Some(addr));
6808        
6809        // Non-existent path
6810        assert_eq!(state.get_observed_address(999), None);
6811    }
6812
6813    // Tests for Task 2.4: Rate Limiting Implementation
6814    #[test]
6815    fn rate_limiter_token_bucket_basic() {
6816        let now = Instant::now();
6817        let mut limiter = AddressObservationRateLimiter::new(10, now); // 10 tokens per second
6818        
6819        // Should be able to consume tokens up to the limit
6820        assert!(limiter.try_consume(5.0, now));
6821        assert!(limiter.try_consume(5.0, now));
6822        
6823        // Should not be able to consume more tokens
6824        assert!(!limiter.try_consume(1.0, now));
6825    }
6826
6827    #[test]
6828    fn rate_limiter_token_replenishment() {
6829        let now = Instant::now();
6830        let mut limiter = AddressObservationRateLimiter::new(10, now); // 10 tokens per second
6831        
6832        // Consume all tokens
6833        assert!(limiter.try_consume(10.0, now));
6834        assert!(!limiter.try_consume(0.1, now)); // Should be empty
6835        
6836        // After 1 second, should have new tokens
6837        let later = now + Duration::from_secs(1);
6838        assert!(limiter.try_consume(10.0, later)); // Should work after replenishment
6839        
6840        // After 0.5 seconds, should have 5 new tokens
6841        assert!(!limiter.try_consume(0.1, later)); // Empty again
6842        let later = later + Duration::from_millis(500);
6843        assert!(limiter.try_consume(5.0, later)); // Should have ~5 tokens
6844        assert!(!limiter.try_consume(0.1, later)); // But not more
6845    }
6846
6847    #[test]
6848    fn rate_limiter_max_tokens_cap() {
6849        let now = Instant::now();
6850        let mut limiter = AddressObservationRateLimiter::new(10, now);
6851        
6852        // After 2 seconds, should still be capped at max_tokens
6853        let later = now + Duration::from_secs(2);
6854        // Try to consume more than max - should fail
6855        assert!(limiter.try_consume(10.0, later));
6856        assert!(!limiter.try_consume(10.1, later)); // Can't consume more than max even after time
6857        
6858        // Consume some tokens
6859        let later2 = later + Duration::from_secs(1);
6860        assert!(limiter.try_consume(3.0, later2));
6861        
6862        // After another 2 seconds, should be back at max
6863        let much_later = later2 + Duration::from_secs(2);
6864        assert!(limiter.try_consume(10.0, much_later)); // Can consume full amount
6865        assert!(!limiter.try_consume(0.1, much_later)); // But not more
6866    }
6867
6868    #[test]
6869    fn rate_limiter_fractional_consumption() {
6870        let now = Instant::now();
6871        let mut limiter = AddressObservationRateLimiter::new(10, now);
6872        
6873        // Should handle fractional token consumption
6874        assert!(limiter.try_consume(0.5, now));
6875        assert!(limiter.try_consume(2.3, now));
6876        assert!(limiter.try_consume(7.2, now)); // Total: 10.0
6877        assert!(!limiter.try_consume(0.1, now)); // Should be empty
6878        
6879        // Should handle fractional replenishment
6880        let later = now + Duration::from_millis(100); // 0.1 seconds = 1 token
6881        assert!(limiter.try_consume(1.0, later));
6882        assert!(!limiter.try_consume(0.1, later));
6883    }
6884
6885    #[test]
6886    fn rate_limiter_zero_rate() {
6887        let now = Instant::now();
6888        let mut limiter = AddressObservationRateLimiter::new(0, now); // 0 tokens per second
6889        
6890        // Should never be able to consume tokens
6891        assert!(!limiter.try_consume(1.0, now));
6892        assert!(!limiter.try_consume(0.1, now));
6893        assert!(!limiter.try_consume(0.001, now));
6894        
6895        // Even after time passes, no tokens
6896        let later = now + Duration::from_secs(10);
6897        assert!(!limiter.try_consume(0.001, later));
6898    }
6899
6900    #[test]
6901    fn rate_limiter_high_rate() {
6902        let now = Instant::now();
6903        let mut limiter = AddressObservationRateLimiter::new(63, now); // Max allowed rate
6904        
6905        // Consume many tokens
6906        assert!(limiter.try_consume(60.0, now));
6907        assert!(limiter.try_consume(3.0, now));
6908        assert!(!limiter.try_consume(0.1, now)); // Should be empty
6909        
6910        // After 1 second, should have replenished
6911        let later = now + Duration::from_secs(1);
6912        assert!(limiter.try_consume(63.0, later)); // Full amount available
6913        assert!(!limiter.try_consume(0.1, later)); // But not more
6914    }
6915
6916    #[test]
6917    fn rate_limiter_time_precision() {
6918        let now = Instant::now();
6919        let mut limiter = AddressObservationRateLimiter::new(100, now); // 100 tokens per second (max for u8)
6920        
6921        // Consume all tokens
6922        assert!(limiter.try_consume(100.0, now));
6923        assert!(!limiter.try_consume(0.1, now));
6924        
6925        // After 10 milliseconds, should have ~1 token
6926        let later = now + Duration::from_millis(10);
6927        assert!(limiter.try_consume(0.8, later)); // Should have ~1 token (allowing for precision)
6928        assert!(!limiter.try_consume(0.5, later)); // But not much more
6929        
6930        // Reset for next test by waiting longer
6931        let much_later = later + Duration::from_millis(100); // 100ms = 10 tokens
6932        assert!(limiter.try_consume(5.0, much_later)); // Should have some tokens
6933        
6934        // Consume remaining to have a clean state
6935        limiter.tokens = 0.0; // Force empty state
6936        
6937        // After 1 millisecond from empty state
6938        let final_time = much_later + Duration::from_millis(1);
6939        // With 100 tokens/sec, 1 millisecond = 0.1 tokens
6940        limiter.update_tokens(final_time); // Update tokens manually
6941        
6942        // Check we have approximately 0.1 tokens (allow for floating point error)
6943        assert!(limiter.tokens >= 0.09 && limiter.tokens <= 0.11);
6944    }
6945
6946    #[test]
6947    fn per_path_rate_limiting_independent() {
6948        let config = crate::transport_parameters::AddressDiscoveryConfig {
6949            enabled: true,
6950            max_observation_rate: 5, // 5 per second
6951            observe_all_paths: true,
6952        };
6953        let now = Instant::now();
6954        let mut state = AddressDiscoveryState::new(&config, now);
6955        
6956        // Create multiple paths with rate limiters
6957        let path1_id = 0;
6958        let path2_id = 1;
6959        let path3_id = 2;
6960        
6961        // Each path should have independent rate limiting
6962        // Path 1: consume 3 tokens
6963        for _ in 0..3 {
6964            assert!(state.should_send_observation(path1_id, now));
6965            state.record_observation_sent(path1_id);
6966        }
6967        
6968        // Path 2: consume 2 tokens
6969        for _ in 0..2 {
6970            assert!(state.should_send_observation(path2_id, now));
6971            state.record_observation_sent(path2_id);
6972        }
6973        
6974        // Global limit should be hit (5 total)
6975        assert!(!state.should_send_observation(path3_id, now));
6976        
6977        // After 1 second, should have 5 more tokens
6978        let later = now + Duration::from_secs(1);
6979        
6980        // All paths should be able to send again
6981        assert!(state.should_send_observation(path1_id, later));
6982        assert!(state.should_send_observation(path2_id, later));
6983        assert!(state.should_send_observation(path3_id, later));
6984    }
6985
6986    #[test] 
6987    fn per_path_rate_limiting_with_path_specific_limits() {
6988        let now = Instant::now();
6989        let remote1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
6990        let remote2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)), 8081);
6991        let config = TransportConfig::default();
6992        
6993        // Create paths with different rate limits
6994        let mut path1 = paths::PathData::new(remote1, false, None, now, &config);
6995        let mut path2 = paths::PathData::new(remote2, false, None, now, &config);
6996        
6997        // Set different rate limits
6998        path1.observation_rate_limiter = paths::PathObservationRateLimiter::new(10, now); // 10/sec
6999        path2.observation_rate_limiter = paths::PathObservationRateLimiter::new(5, now);  // 5/sec
7000        
7001        // Path 1 should allow 10 observations
7002        for _ in 0..10 {
7003            assert!(path1.observation_rate_limiter.can_send(now));
7004            path1.observation_rate_limiter.consume_token(now);
7005        }
7006        assert!(!path1.observation_rate_limiter.can_send(now));
7007        
7008        // Path 2 should allow 5 observations
7009        for _ in 0..5 {
7010            assert!(path2.observation_rate_limiter.can_send(now));
7011            path2.observation_rate_limiter.consume_token(now);
7012        }
7013        assert!(!path2.observation_rate_limiter.can_send(now));
7014    }
7015
7016    #[test]
7017    fn per_path_rate_limiting_address_change_detection() {
7018        let config = crate::transport_parameters::AddressDiscoveryConfig {
7019            enabled: true,
7020            max_observation_rate: 10,
7021            observe_all_paths: true,
7022        };
7023        let now = Instant::now();
7024        let mut state = AddressDiscoveryState::new(&config, now);
7025        
7026        // Setup initial path with address
7027        let path_id = 0;
7028        let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
7029        let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)), 8080);
7030        
7031        // First observation should be allowed
7032        assert!(state.should_send_observation(path_id, now));
7033        state.handle_observed_address(addr1, path_id, now);
7034        state.record_observation_sent(path_id);
7035        
7036        // Same address, should not send again
7037        assert!(!state.should_send_observation(path_id, now));
7038        
7039        // Address change should trigger new observation need
7040        state.handle_observed_address(addr2, path_id, now);
7041        if let Some(info) = state.path_addresses.get_mut(&path_id) {
7042            info.notified = false; // Simulate address change detection
7043        }
7044        
7045        // Should now allow sending despite rate limit
7046        assert!(state.should_send_observation(path_id, now));
7047    }
7048
7049    #[test]
7050    fn per_path_rate_limiting_migration() {
7051        let now = Instant::now();
7052        let remote1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
7053        let remote2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)), 8081);
7054        let config = TransportConfig::default();
7055        
7056        // Create initial path and consume tokens
7057        let mut path = paths::PathData::new(remote1, false, None, now, &config);
7058        path.observation_rate_limiter = paths::PathObservationRateLimiter::new(10, now);
7059        
7060        // Consume some tokens
7061        for _ in 0..5 {
7062            assert!(path.observation_rate_limiter.can_send(now));
7063            path.observation_rate_limiter.consume_token(now);
7064        }
7065        
7066        // Create new path (simulates connection migration)
7067        let mut new_path = paths::PathData::new(remote2, false, None, now, &config);
7068        
7069        // New path should have fresh rate limiter (migration resets limits)
7070        // Since default observation rate is 0, set it manually
7071        new_path.observation_rate_limiter = paths::PathObservationRateLimiter::new(10, now);
7072        
7073        // Should have full tokens available
7074        for _ in 0..10 {
7075            assert!(new_path.observation_rate_limiter.can_send(now));
7076            new_path.observation_rate_limiter.consume_token(now);
7077        }
7078        assert!(!new_path.observation_rate_limiter.can_send(now));
7079    }
7080
7081    #[test]
7082    fn per_path_rate_limiting_disabled_paths() {
7083        let config = crate::transport_parameters::AddressDiscoveryConfig {
7084            enabled: true,
7085            max_observation_rate: 10,
7086            observe_all_paths: false, // Only primary path
7087        };
7088        let now = Instant::now();
7089        let mut state = AddressDiscoveryState::new(&config, now);
7090        
7091        // Primary path (id 0) should be allowed
7092        assert!(state.should_send_observation(0, now));
7093        
7094        // Non-primary paths should not be allowed when observe_all_paths is false
7095        assert!(!state.should_send_observation(1, now));
7096        assert!(!state.should_send_observation(2, now));
7097        
7098        // Even with rate limit available
7099        let later = now + Duration::from_secs(1);
7100        assert!(!state.should_send_observation(1, later));
7101    }
7102
7103    #[test]
7104    fn respecting_negotiated_max_observation_rate_basic() {
7105        let config = crate::transport_parameters::AddressDiscoveryConfig {
7106            enabled: true,
7107            max_observation_rate: 20, // Local config says 20/sec
7108            observe_all_paths: true,
7109        };
7110        let now = Instant::now();
7111        let mut state = AddressDiscoveryState::new(&config, now);
7112        
7113        // Simulate negotiated rate from peer (lower than ours)
7114        state.max_observation_rate = 10; // Peer only allows 10/sec
7115        state.rate_limiter = AddressObservationRateLimiter::new(10, now);
7116        
7117        // Should respect the negotiated rate (10, not 20)
7118        for _ in 0..10 {
7119            assert!(state.should_send_observation(0, now));
7120        }
7121        // 11th should fail
7122        assert!(!state.should_send_observation(0, now));
7123    }
7124
7125    #[test]
7126    fn respecting_negotiated_max_observation_rate_zero() {
7127        let config = crate::transport_parameters::AddressDiscoveryConfig {
7128            enabled: true,
7129            max_observation_rate: 10,
7130            observe_all_paths: true,
7131        };
7132        let now = Instant::now();
7133        let mut state = AddressDiscoveryState::new(&config, now);
7134        
7135        // Peer negotiated rate of 0 (disabled)
7136        state.max_observation_rate = 0;
7137        state.rate_limiter = AddressObservationRateLimiter::new(0, now);
7138        
7139        // Should not send any observations
7140        assert!(!state.should_send_observation(0, now));
7141        assert!(!state.should_send_observation(1, now));
7142        
7143        // Even after time passes
7144        let later = now + Duration::from_secs(10);
7145        assert!(!state.should_send_observation(0, later));
7146    }
7147
7148    #[test]
7149    fn respecting_negotiated_max_observation_rate_higher() {
7150        let config = crate::transport_parameters::AddressDiscoveryConfig {
7151            enabled: true,
7152            max_observation_rate: 5, // Local config says 5/sec
7153            observe_all_paths: true,
7154        };
7155        let now = Instant::now();
7156        let mut state = AddressDiscoveryState::new(&config, now);
7157        
7158        // Simulate negotiated rate from peer (higher than ours)
7159        // We should still use the minimum of the two
7160        state.max_observation_rate = 10; // Peer allows 10/sec
7161        // But our rate limiter was initialized with 5
7162        
7163        // Should respect our local rate (5, not 10)
7164        for _ in 0..5 {
7165            assert!(state.should_send_observation(0, now));
7166        }
7167        // 6th should fail
7168        assert!(!state.should_send_observation(0, now));
7169    }
7170
7171    #[test]
7172    fn respecting_negotiated_max_observation_rate_dynamic_update() {
7173        let config = crate::transport_parameters::AddressDiscoveryConfig {
7174            enabled: true,
7175            max_observation_rate: 10,
7176            observe_all_paths: true,
7177        };
7178        let now = Instant::now();
7179        let mut state = AddressDiscoveryState::new(&config, now);
7180        
7181        // Use initial rate - consume 5 tokens
7182        for _i in 0..5 {
7183            assert!(state.should_send_observation(0, now)); // Same path, consuming global tokens
7184            state.record_observation_sent(0);
7185        }
7186        
7187        // We have 5 tokens remaining
7188        
7189        // Simulate rate renegotiation (e.g., from transport parameter update)
7190        state.max_observation_rate = 3;
7191        state.rate_limiter.set_rate(3);
7192        
7193        // Can still use remaining tokens from before (5 tokens)
7194        // But they're capped at new max (3), so we'll have 3 tokens
7195        for i in 0..3 {
7196            assert!(state.should_send_observation(i+1, now)); // Different paths to bypass notification check
7197            state.record_observation_sent(i+1);
7198        }
7199        assert!(!state.should_send_observation(10, now));
7200        
7201        // After 1 second, should only have 3 new tokens
7202        let later = now + Duration::from_secs(1);
7203        for i in 0..3 {
7204            assert!(state.should_send_observation(i+20, later)); // New paths
7205            state.record_observation_sent(i+20);
7206        }
7207        assert!(!state.should_send_observation(30, later));
7208    }
7209
7210    #[test]
7211    fn respecting_negotiated_max_observation_rate_with_paths() {
7212        let config = crate::transport_parameters::AddressDiscoveryConfig {
7213            enabled: true,
7214            max_observation_rate: 6, // 6 total per second
7215            observe_all_paths: true,
7216        };
7217        let now = Instant::now();
7218        let mut state = AddressDiscoveryState::new(&config, now);
7219        
7220        // Distribute observations across paths
7221        assert!(state.should_send_observation(0, now));
7222        assert!(state.should_send_observation(1, now));
7223        assert!(state.should_send_observation(2, now));
7224        assert!(state.should_send_observation(0, now));
7225        assert!(state.should_send_observation(1, now));
7226        assert!(state.should_send_observation(2, now));
7227        
7228        // All paths should be rate limited now
7229        assert!(!state.should_send_observation(0, now));
7230        assert!(!state.should_send_observation(1, now));
7231        assert!(!state.should_send_observation(2, now));
7232    }
7233
7234    #[test]
7235    fn queue_observed_address_frame_basic() {
7236        let config = crate::transport_parameters::AddressDiscoveryConfig {
7237            enabled: true,
7238            max_observation_rate: 10,
7239            observe_all_paths: true,
7240        };
7241        let now = Instant::now();
7242        let mut state = AddressDiscoveryState::new(&config, now);
7243        
7244        // Queue a frame for path 0
7245        let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
7246        let frame = state.queue_observed_address_frame(0, address);
7247        
7248        // Should return Some(frame) since this is the first observation
7249        assert!(frame.is_some());
7250        let frame = frame.unwrap();
7251        assert_eq!(frame.address, address);
7252        
7253        // Should mark path as notified
7254        assert!(state.path_addresses.contains_key(&0));
7255        assert!(state.path_addresses.get(&0).unwrap().notified);
7256    }
7257
7258    #[test]
7259    fn queue_observed_address_frame_rate_limited() {
7260        let config = crate::transport_parameters::AddressDiscoveryConfig {
7261            enabled: true,
7262            max_observation_rate: 2, // Very low rate
7263            observe_all_paths: true,
7264        };
7265        let now = Instant::now();
7266        let mut state = AddressDiscoveryState::new(&config, now);
7267        
7268        // Queue frames up to rate limit
7269        let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 5000);
7270        let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)), 5001);
7271        let addr3 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 3)), 5002);
7272        
7273        assert!(state.queue_observed_address_frame(0, addr1).is_some());
7274        assert!(state.queue_observed_address_frame(1, addr2).is_some());
7275        
7276        // Third should be rate limited
7277        assert!(state.queue_observed_address_frame(2, addr3).is_none());
7278    }
7279
7280    #[test]
7281    fn queue_observed_address_frame_disabled() {
7282        let config = crate::transport_parameters::AddressDiscoveryConfig {
7283            enabled: false, // Disabled
7284            max_observation_rate: 10,
7285            observe_all_paths: true,
7286        };
7287        let now = Instant::now();
7288        let mut state = AddressDiscoveryState::new(&config, now);
7289        
7290        let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
7291        
7292        // Should return None when disabled
7293        assert!(state.queue_observed_address_frame(0, address).is_none());
7294    }
7295
7296    #[test]
7297    fn queue_observed_address_frame_already_notified() {
7298        let config = crate::transport_parameters::AddressDiscoveryConfig {
7299            enabled: true,
7300            max_observation_rate: 10,
7301            observe_all_paths: true,
7302        };
7303        let now = Instant::now();
7304        let mut state = AddressDiscoveryState::new(&config, now);
7305        
7306        let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
7307        
7308        // First observation should succeed
7309        assert!(state.queue_observed_address_frame(0, address).is_some());
7310        
7311        // Second observation for same address should return None
7312        assert!(state.queue_observed_address_frame(0, address).is_none());
7313        
7314        // Even with different address, if already notified, should return None
7315        let new_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 101)), 5001);
7316        assert!(state.queue_observed_address_frame(0, new_address).is_none());
7317    }
7318
7319    #[test]
7320    fn queue_observed_address_frame_primary_path_only() {
7321        let config = crate::transport_parameters::AddressDiscoveryConfig {
7322            enabled: true,
7323            max_observation_rate: 10,
7324            observe_all_paths: false, // Only primary path
7325        };
7326        let now = Instant::now();
7327        let mut state = AddressDiscoveryState::new(&config, now);
7328        
7329        let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
7330        
7331        // Primary path should work
7332        assert!(state.queue_observed_address_frame(0, address).is_some());
7333        
7334        // Non-primary paths should not work
7335        assert!(state.queue_observed_address_frame(1, address).is_none());
7336        assert!(state.queue_observed_address_frame(2, address).is_none());
7337    }
7338
7339    #[test]
7340    fn queue_observed_address_frame_updates_path_info() {
7341        let config = crate::transport_parameters::AddressDiscoveryConfig {
7342            enabled: true,
7343            max_observation_rate: 10,
7344            observe_all_paths: true,
7345        };
7346        let now = Instant::now();
7347        let mut state = AddressDiscoveryState::new(&config, now);
7348        
7349        let address = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)), 5000);
7350        
7351        // Queue frame
7352        let frame = state.queue_observed_address_frame(0, address);
7353        assert!(frame.is_some());
7354        
7355        // Check path info was updated
7356        let path_info = state.path_addresses.get(&0).unwrap();
7357        assert_eq!(path_info.observed_address, Some(address));
7358        assert!(path_info.notified);
7359        
7360        // Note: observed_addresses list is NOT updated by queue_observed_address_frame
7361        // That list is for addresses we've received from peers, not ones we're sending
7362        assert_eq!(state.observed_addresses.len(), 0);
7363    }
7364
7365    #[test]
7366    fn retransmits_includes_observed_addresses() {
7367        use crate::connection::spaces::Retransmits;
7368        
7369        // Create a retransmits struct
7370        let mut retransmits = Retransmits::default();
7371        
7372        // Initially should be empty
7373        assert!(retransmits.observed_addresses.is_empty());
7374        
7375        // Add an observed address frame
7376        let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
7377        let frame = frame::ObservedAddress { address };
7378        retransmits.observed_addresses.push(frame);
7379        
7380        // Should now have one frame
7381        assert_eq!(retransmits.observed_addresses.len(), 1);
7382        assert_eq!(retransmits.observed_addresses[0].address, address);
7383    }
7384
7385    #[test]
7386    fn check_for_address_observations_no_peer_support() {
7387        let config = crate::transport_parameters::AddressDiscoveryConfig {
7388            enabled: true,
7389            max_observation_rate: 10,
7390            observe_all_paths: false,
7391        };
7392        let now = Instant::now();
7393        let mut state = AddressDiscoveryState::new(&config, now);
7394        
7395        // Simulate address change on path 0
7396        state.path_addresses.insert(0, paths::PathAddressInfo::new());
7397        state.path_addresses.get_mut(&0).unwrap().observed_address = 
7398            Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000));
7399        
7400        // Check for observations with no peer support
7401        let frames = state.check_for_address_observations(0, false, now);
7402        
7403        // Should return empty vec when peer doesn't support
7404        assert!(frames.is_empty());
7405    }
7406
7407    #[test]
7408    fn check_for_address_observations_with_peer_support() {
7409        let config = crate::transport_parameters::AddressDiscoveryConfig {
7410            enabled: true,
7411            max_observation_rate: 10,
7412            observe_all_paths: false,
7413        };
7414        let now = Instant::now();
7415        let mut state = AddressDiscoveryState::new(&config, now);
7416        
7417        // Simulate address change on path 0
7418        let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
7419        state.path_addresses.insert(0, paths::PathAddressInfo::new());
7420        state.path_addresses.get_mut(&0).unwrap().observed_address = Some(address);
7421        
7422        // Check for observations with peer support
7423        let frames = state.check_for_address_observations(0, true, now);
7424        
7425        // Should return frame for unnotified address
7426        assert_eq!(frames.len(), 1);
7427        assert_eq!(frames[0].address, address);
7428        
7429        // Path should now be marked as notified
7430        assert!(state.path_addresses.get(&0).unwrap().notified);
7431    }
7432
7433    #[test]
7434    fn check_for_address_observations_rate_limited() {
7435        let config = crate::transport_parameters::AddressDiscoveryConfig {
7436            enabled: true,
7437            max_observation_rate: 1, // Very low rate
7438            observe_all_paths: true,
7439        };
7440        let now = Instant::now();
7441        let mut state = AddressDiscoveryState::new(&config, now);
7442        
7443        // Set up multiple paths with observed addresses
7444        for i in 0..3 {
7445            let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100 + i)), 5000);
7446            state.path_addresses.insert(i as u64, paths::PathAddressInfo::new());
7447            state.path_addresses.get_mut(&(i as u64)).unwrap().observed_address = Some(address);
7448        }
7449        
7450        // First check should get one frame
7451        let frames1 = state.check_for_address_observations(0, true, now);
7452        assert_eq!(frames1.len(), 1);
7453        
7454        // Immediate second check should be rate limited
7455        let frames2 = state.check_for_address_observations(1, true, now);
7456        assert_eq!(frames2.len(), 0);
7457        
7458        // After time passes, should be able to send again
7459        let later = now + Duration::from_secs(2);
7460        let frames3 = state.check_for_address_observations(1, true, later);
7461        assert_eq!(frames3.len(), 1);
7462    }
7463
7464    #[test]
7465    fn check_for_address_observations_multiple_paths() {
7466        let config = crate::transport_parameters::AddressDiscoveryConfig {
7467            enabled: true,
7468            max_observation_rate: 10,
7469            observe_all_paths: true,
7470        };
7471        let now = Instant::now();
7472        let mut state = AddressDiscoveryState::new(&config, now);
7473        
7474        // Set up two paths with observed addresses
7475        let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
7476        let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 101)), 5001);
7477        
7478        state.path_addresses.insert(0, paths::PathAddressInfo::new());
7479        state.path_addresses.get_mut(&0).unwrap().observed_address = Some(addr1);
7480        
7481        state.path_addresses.insert(1, paths::PathAddressInfo::new());
7482        state.path_addresses.get_mut(&1).unwrap().observed_address = Some(addr2);
7483        
7484        // Check for observations - should get both since we have tokens
7485        let frames = state.check_for_address_observations(0, true, now);
7486        
7487        // Should get frames for both paths
7488        assert_eq!(frames.len(), 2);
7489        
7490        // Verify both addresses are included
7491        let addresses: Vec<_> = frames.iter().map(|f| f.address).collect();
7492        assert!(addresses.contains(&addr1));
7493        assert!(addresses.contains(&addr2));
7494        
7495        // Both paths should be marked as notified
7496        assert!(state.path_addresses.get(&0).unwrap().notified);
7497        assert!(state.path_addresses.get(&1).unwrap().notified);
7498    }
7499
7500    // Tests for Task 2.4: Rate Limiter Configuration
7501    #[test]
7502    fn test_rate_limiter_configuration() {
7503        // Test different rate configurations
7504        let state = AddressDiscoveryState::new_with_params(true, 10.0, false);
7505        assert_eq!(state.rate_limiter.rate, 10.0);
7506        assert_eq!(state.rate_limiter.max_tokens, 10.0);
7507        assert_eq!(state.rate_limiter.tokens, 10.0);
7508        
7509        let state = AddressDiscoveryState::new_with_params(true, 63.0, false);
7510        assert_eq!(state.rate_limiter.rate, 63.0);
7511        assert_eq!(state.rate_limiter.max_tokens, 63.0);
7512    }
7513
7514    #[test]
7515    fn test_rate_limiter_update_configuration() {
7516        let mut state = AddressDiscoveryState::new_with_params(true, 5.0, false);
7517        
7518        // Initial configuration
7519        assert_eq!(state.rate_limiter.rate, 5.0);
7520        
7521        // Update configuration
7522        state.update_rate_limit(10.0);
7523        assert_eq!(state.rate_limiter.rate, 10.0);
7524        assert_eq!(state.rate_limiter.max_tokens, 10.0);
7525        
7526        // Tokens should not exceed new max
7527        state.rate_limiter.tokens = 15.0;
7528        state.update_rate_limit(8.0);
7529        assert_eq!(state.rate_limiter.tokens, 8.0);
7530    }
7531
7532    #[test]
7533    fn test_rate_limiter_from_transport_params() {
7534        let mut params = TransportParameters::default();
7535        params.address_discovery = Some(AddressDiscoveryConfig {
7536            enabled: true,
7537            max_observation_rate: 25,
7538            observe_all_paths: true,
7539        });
7540        
7541        let state = AddressDiscoveryState::from_transport_params(&params);
7542        assert!(state.is_some());
7543        let state = state.unwrap();
7544        assert_eq!(state.rate_limiter.rate, 25.0);
7545        assert!(state.observe_all_paths);
7546    }
7547
7548    #[test]
7549    fn test_rate_limiter_zero_rate() {
7550        let state = AddressDiscoveryState::new_with_params(true, 0.0, false);
7551        assert_eq!(state.rate_limiter.rate, 0.0);
7552        assert_eq!(state.rate_limiter.tokens, 0.0);
7553        
7554        // Should never allow sending with zero rate
7555        let address = "192.168.1.1:443".parse().unwrap();
7556        let mut state = AddressDiscoveryState::new_with_params(true, 0.0, false);
7557        let frame = state.queue_observed_address_frame(0, address);
7558        assert!(frame.is_none());
7559    }
7560
7561    #[test]
7562    fn test_rate_limiter_configuration_edge_cases() {
7563        // Test maximum allowed rate (63)
7564        let state = AddressDiscoveryState::new_with_params(true, 63.0, false);
7565        assert_eq!(state.rate_limiter.rate, 63.0);
7566        
7567        // Test rates > 63 get converted to u8 then back to f64
7568        let state = AddressDiscoveryState::new_with_params(true, 100.0, false);
7569        // 100 as u8 is 100
7570        assert_eq!(state.rate_limiter.rate, 100.0);
7571        
7572        // Test fractional rates get truncated due to u8 storage
7573        let state = AddressDiscoveryState::new_with_params(true, 2.5, false);
7574        // 2.5 as u8 is 2, then back to f64 is 2.0
7575        assert_eq!(state.rate_limiter.rate, 2.0);
7576    }
7577
7578    #[test]
7579    fn test_rate_limiter_runtime_update() {
7580        let mut state = AddressDiscoveryState::new_with_params(true, 10.0, false);
7581        let now = Instant::now();
7582        
7583        // Consume some tokens
7584        state.rate_limiter.tokens = 5.0;
7585        
7586        // Update rate while tokens are partially consumed
7587        state.update_rate_limit(3.0);
7588        
7589        // Tokens should be capped at new max
7590        assert_eq!(state.rate_limiter.tokens, 3.0);
7591        assert_eq!(state.rate_limiter.rate, 3.0);
7592        assert_eq!(state.rate_limiter.max_tokens, 3.0);
7593        
7594        // Wait for replenishment
7595        let later = now + Duration::from_secs(1);
7596        state.rate_limiter.update_tokens(later);
7597        
7598        // Should be capped at new max
7599        assert_eq!(state.rate_limiter.tokens, 3.0);
7600    }
7601
7602    // Tests for Task 2.5: Connection Tests
7603    #[test]
7604    fn test_address_discovery_state_initialization_default() {
7605        // Test that connection initializes with default address discovery state
7606        let now = Instant::now();
7607        let default_config = crate::transport_parameters::AddressDiscoveryConfig::default();
7608        
7609        // Create a connection (simplified test setup)
7610        // In reality, this happens in Connection::new()
7611        let address_discovery_state = Some(AddressDiscoveryState::new(&default_config, now));
7612        
7613        assert!(address_discovery_state.is_some());
7614        let state = address_discovery_state.unwrap();
7615        
7616        // Default config should have address discovery disabled
7617        assert!(state.enabled); // Default is now enabled
7618        assert_eq!(state.max_observation_rate, 10); // Default rate
7619        assert!(!state.observe_all_paths);
7620    }
7621
7622    #[test]
7623    fn test_address_discovery_state_initialization_on_handshake() {
7624        // Test that address discovery state is updated when transport parameters are received
7625        let now = Instant::now();
7626        
7627        // Simulate initial state (as in Connection::new)
7628        let mut address_discovery_state = Some(AddressDiscoveryState::new(
7629            &crate::transport_parameters::AddressDiscoveryConfig::default(),
7630            now
7631        ));
7632        
7633        // Simulate receiving peer's transport parameters with address discovery enabled
7634        let peer_params = TransportParameters {
7635            address_discovery: Some(AddressDiscoveryConfig {
7636                enabled: true,
7637                max_observation_rate: 20,
7638                observe_all_paths: true,
7639            }),
7640            ..TransportParameters::default()
7641        };
7642        
7643        // Update address discovery state based on peer params
7644        if let Some(peer_config) = &peer_params.address_discovery {
7645            if peer_config.enabled {
7646                address_discovery_state = Some(AddressDiscoveryState::new(peer_config, now));
7647            }
7648        }
7649        
7650        // Verify state was updated
7651        assert!(address_discovery_state.is_some());
7652        let state = address_discovery_state.unwrap();
7653        assert!(state.enabled);
7654        assert_eq!(state.max_observation_rate, 20);
7655        assert!(state.observe_all_paths);
7656    }
7657
7658    #[test]
7659    fn test_address_discovery_negotiation_disabled_peer() {
7660        // Test when peer doesn't support address discovery
7661        let now = Instant::now();
7662        
7663        // Start with our config enabling address discovery
7664        let our_config = AddressDiscoveryConfig {
7665            enabled: true,
7666            max_observation_rate: 30,
7667            observe_all_paths: false,
7668        };
7669        let mut address_discovery_state = Some(AddressDiscoveryState::new(&our_config, now));
7670        
7671        // Peer's transport parameters without address discovery
7672        let peer_params = TransportParameters {
7673            address_discovery: None,
7674            ..TransportParameters::default()
7675        };
7676        
7677        // If peer doesn't advertise address discovery, we should disable it
7678        if peer_params.address_discovery.is_none() {
7679            if let Some(state) = &mut address_discovery_state {
7680                state.enabled = false;
7681            }
7682        }
7683        
7684        // Verify it's disabled
7685        let state = address_discovery_state.unwrap();
7686        assert!(!state.enabled); // Should be disabled when peer doesn't support it
7687    }
7688
7689    #[test]
7690    fn test_address_discovery_negotiation_rate_limiting() {
7691        // Test rate limit negotiation - should use minimum of local and peer rates
7692        let now = Instant::now();
7693        
7694        // Our config with rate 30
7695        let our_config = AddressDiscoveryConfig {
7696            enabled: true,
7697            max_observation_rate: 30,
7698            observe_all_paths: true,
7699        };
7700        let mut address_discovery_state = Some(AddressDiscoveryState::new(&our_config, now));
7701        
7702        // Peer config with rate 15
7703        let peer_params = TransportParameters {
7704            address_discovery: Some(AddressDiscoveryConfig {
7705                enabled: true,
7706                max_observation_rate: 15,
7707                observe_all_paths: true,
7708            }),
7709            ..TransportParameters::default()
7710        };
7711        
7712        // Negotiate - should use minimum rate
7713        if let (Some(state), Some(peer_config)) = (&mut address_discovery_state, &peer_params.address_discovery) {
7714            if peer_config.enabled && state.enabled {
7715                // Use minimum of the two rates
7716                let negotiated_rate = state.max_observation_rate.min(peer_config.max_observation_rate);
7717                state.update_rate_limit(negotiated_rate as f64);
7718            }
7719        }
7720        
7721        // Verify negotiated rate
7722        let state = address_discovery_state.unwrap();
7723        assert_eq!(state.rate_limiter.rate, 15.0); // Min of 30 and 15
7724    }
7725
7726    #[test]
7727    fn test_address_discovery_path_initialization() {
7728        // Test that paths are initialized with address discovery support
7729        let now = Instant::now();
7730        let config = AddressDiscoveryConfig {
7731            enabled: true,
7732            max_observation_rate: 10,
7733            observe_all_paths: false,
7734        };
7735        let mut state = AddressDiscoveryState::new(&config, now);
7736        
7737        // Simulate path creation (path_id = 0)
7738        assert!(state.path_addresses.is_empty());
7739        
7740        // When we first check if we should send observation, it should create path entry
7741        let should_send = state.should_send_observation(0, now);
7742        assert!(should_send); // Should allow first observation
7743        
7744        // Path entry should now exist (created on demand)
7745        // Note: In the actual implementation, path entries are created when needed
7746    }
7747
7748    #[test]
7749    fn test_address_discovery_multiple_path_initialization() {
7750        // Test initialization with multiple paths
7751        let now = Instant::now();
7752        let config = AddressDiscoveryConfig {
7753            enabled: true,
7754            max_observation_rate: 10,
7755            observe_all_paths: true, // Allow all paths
7756        };
7757        let mut state = AddressDiscoveryState::new(&config, now);
7758        
7759        // Check multiple paths
7760        assert!(state.should_send_observation(0, now)); // Primary path
7761        assert!(state.should_send_observation(1, now)); // Secondary path
7762        assert!(state.should_send_observation(2, now)); // Additional path
7763        
7764        // With observe_all_paths = false, only primary path should be allowed
7765        let config_primary_only = AddressDiscoveryConfig {
7766            enabled: true,
7767            max_observation_rate: 10,
7768            observe_all_paths: false,
7769        };
7770        let mut state_primary = AddressDiscoveryState::new(&config_primary_only, now);
7771        
7772        assert!(state_primary.should_send_observation(0, now)); // Primary path allowed
7773        assert!(!state_primary.should_send_observation(1, now)); // Secondary path not allowed
7774    }
7775
7776    #[test]
7777    fn test_handle_observed_address_frame_valid() {
7778        // Test processing a valid OBSERVED_ADDRESS frame
7779        let now = Instant::now();
7780        let config = AddressDiscoveryConfig {
7781            enabled: true,
7782            max_observation_rate: 10,
7783            observe_all_paths: true,
7784        };
7785        let mut state = AddressDiscoveryState::new(&config, now);
7786        
7787        // Simulate receiving an OBSERVED_ADDRESS frame
7788        let observed_addr = SocketAddr::from(([192, 168, 1, 100], 5000));
7789        state.handle_observed_address(observed_addr, 0, now);
7790        
7791        // Verify the address was recorded
7792        assert_eq!(state.observed_addresses.len(), 1);
7793        assert_eq!(state.observed_addresses[0].address, observed_addr);
7794        assert_eq!(state.observed_addresses[0].path_id, 0);
7795        assert_eq!(state.observed_addresses[0].received_at, now);
7796        
7797        // Path should also have the observed address
7798        let path_info = state.path_addresses.get(&0).unwrap();
7799        assert_eq!(path_info.observed_address, Some(observed_addr));
7800        assert_eq!(path_info.last_observed, Some(now));
7801        assert_eq!(path_info.observation_count, 1);
7802    }
7803
7804    #[test]
7805    fn test_handle_multiple_observed_addresses() {
7806        // Test processing multiple OBSERVED_ADDRESS frames from different paths
7807        let now = Instant::now();
7808        let config = AddressDiscoveryConfig {
7809            enabled: true,
7810            max_observation_rate: 10,
7811            observe_all_paths: true,
7812        };
7813        let mut state = AddressDiscoveryState::new(&config, now);
7814        
7815        // Receive addresses from multiple paths
7816        let addr1 = SocketAddr::from(([192, 168, 1, 100], 5000));
7817        let addr2 = SocketAddr::from(([10, 0, 0, 50], 6000));
7818        let addr3 = SocketAddr::from(([192, 168, 1, 100], 7000)); // Same IP, different port
7819        
7820        state.handle_observed_address(addr1, 0, now);
7821        state.handle_observed_address(addr2, 1, now);
7822        state.handle_observed_address(addr3, 0, now + Duration::from_millis(100));
7823        
7824        // Verify all addresses were recorded
7825        assert_eq!(state.observed_addresses.len(), 3);
7826        
7827        // Path 0 should have the most recent address (addr3)
7828        let path0_info = state.path_addresses.get(&0).unwrap();
7829        assert_eq!(path0_info.observed_address, Some(addr3));
7830        assert_eq!(path0_info.observation_count, 1); // Reset to 1 for new address
7831        
7832        // Path 1 should have addr2
7833        let path1_info = state.path_addresses.get(&1).unwrap();
7834        assert_eq!(path1_info.observed_address, Some(addr2));
7835        assert_eq!(path1_info.observation_count, 1);
7836    }
7837
7838    #[test]
7839    fn test_get_observed_address() {
7840        // Test retrieving observed addresses for specific paths
7841        let now = Instant::now();
7842        let config = AddressDiscoveryConfig {
7843            enabled: true,
7844            max_observation_rate: 10,
7845            observe_all_paths: true,
7846        };
7847        let mut state = AddressDiscoveryState::new(&config, now);
7848        
7849        // Initially no address
7850        assert_eq!(state.get_observed_address(0), None);
7851        
7852        // Add an address
7853        let addr = SocketAddr::from(([192, 168, 1, 100], 5000));
7854        state.handle_observed_address(addr, 0, now);
7855        
7856        // Should return the most recent address for the path
7857        assert_eq!(state.get_observed_address(0), Some(addr));
7858        
7859        // Non-existent path should return None
7860        assert_eq!(state.get_observed_address(999), None);
7861    }
7862
7863    #[test]
7864    fn test_has_unnotified_changes() {
7865        // Test detection of unnotified address changes
7866        let now = Instant::now();
7867        let config = AddressDiscoveryConfig {
7868            enabled: true,
7869            max_observation_rate: 10,
7870            observe_all_paths: true,
7871        };
7872        let mut state = AddressDiscoveryState::new(&config, now);
7873        
7874        // Initially no changes
7875        assert!(!state.has_unnotified_changes());
7876        
7877        // Add an address - should have unnotified change
7878        let addr = SocketAddr::from(([192, 168, 1, 100], 5000));
7879        state.handle_observed_address(addr, 0, now);
7880        assert!(state.has_unnotified_changes());
7881        
7882        // Mark as notified
7883        if let Some(path_info) = state.path_addresses.get_mut(&0) {
7884            path_info.notified = true;
7885        }
7886        assert!(!state.has_unnotified_changes());
7887        
7888        // Add another address - should have change again
7889        let addr2 = SocketAddr::from(([192, 168, 1, 100], 6000));
7890        state.handle_observed_address(addr2, 0, now + Duration::from_secs(1));
7891        assert!(state.has_unnotified_changes());
7892    }
7893
7894    #[test]
7895    fn test_address_discovery_disabled() {
7896        // Test that frames are not processed when address discovery is disabled
7897        let now = Instant::now();
7898        let config = AddressDiscoveryConfig {
7899            enabled: false, // Disabled
7900            max_observation_rate: 10,
7901            observe_all_paths: true,
7902        };
7903        let mut state = AddressDiscoveryState::new(&config, now);
7904        
7905        // Try to process a frame
7906        let addr = SocketAddr::from(([192, 168, 1, 100], 5000));
7907        state.handle_observed_address(addr, 0, now);
7908        
7909        // Nothing should be recorded
7910        assert_eq!(state.observed_addresses.len(), 0);
7911        assert_eq!(state.path_addresses.len(), 0);
7912        
7913        // Should not send observations either
7914        assert!(!state.should_send_observation(0, now));
7915    }
7916
7917    #[test]
7918    fn test_rate_limiting_basic() {
7919        // Test basic rate limiting functionality
7920        let now = Instant::now();
7921        let config = AddressDiscoveryConfig {
7922            enabled: true,
7923            max_observation_rate: 2, // 2 per second
7924            observe_all_paths: true,
7925        };
7926        let mut state = AddressDiscoveryState::new(&config, now);
7927        
7928        // First observation should be allowed and consumes a token
7929        assert!(state.should_send_observation(0, now));
7930        // Need to mark path 0 as notified so subsequent checks will pass
7931        state.record_observation_sent(0);
7932        
7933        // Need a different path since path 0 is already notified
7934        assert!(state.should_send_observation(1, now));
7935        state.record_observation_sent(1);
7936        
7937        // Third observation should be rate limited (no more tokens)
7938        assert!(!state.should_send_observation(2, now));
7939        
7940        // After 500ms, we should have 1 token available
7941        let later = now + Duration::from_millis(500);
7942        assert!(state.should_send_observation(3, later));
7943        state.record_observation_sent(3);
7944        
7945        // But not a second one (all tokens consumed)
7946        assert!(!state.should_send_observation(4, later));
7947        
7948        // After 1 second from start, we've consumed 3 tokens total
7949        // With rate 2/sec, after 1 second we've generated 2 new tokens
7950        // So we should have 0 tokens available (consumed 3, generated 2 = -1, but capped at 0)
7951        let _one_sec_later = now + Duration::from_secs(1);
7952        // Actually we need to wait longer to accumulate more tokens
7953        // After 1.5 seconds, we've generated 3 tokens total, consumed 3, so we can send 0 more
7954        // After 2 seconds, we've generated 4 tokens total, consumed 3, so we can send 1 more
7955        let two_sec_later = now + Duration::from_secs(2);
7956        assert!(state.should_send_observation(5, two_sec_later));
7957        state.record_observation_sent(5);
7958        
7959        // At exactly 2 seconds, we have:
7960        // - Generated: 4 tokens (2 per second × 2 seconds)
7961        // - Consumed: 4 tokens (paths 0, 1, 3, 5)
7962        // - Remaining: 0 tokens
7963        // But since the rate limiter is continuous and tokens accumulate over time,
7964        // by the time we check, we might have accumulated a tiny fraction more.
7965        // The test shows we have exactly 1 token, which makes sense - we're checking
7966        // slightly after consuming for path 5, so we've accumulated a bit more.
7967        
7968        // So path 6 CAN send one more time, consuming that 1 token
7969        assert!(state.should_send_observation(6, two_sec_later));
7970        state.record_observation_sent(6);
7971        
7972        // NOW we should be out of tokens
7973        assert!(!state.should_send_observation(7, two_sec_later), "Expected no tokens available");
7974    }
7975
7976    #[test]
7977    fn test_rate_limiting_per_path() {
7978        // Test that rate limiting is shared across paths (not per-path)
7979        let now = Instant::now();
7980        let config = AddressDiscoveryConfig {
7981            enabled: true,
7982            max_observation_rate: 1, // 1 per second
7983            observe_all_paths: true,
7984        };
7985        let mut state = AddressDiscoveryState::new(&config, now);
7986        
7987        // Path 0 can send and consumes the only token
7988        assert!(state.should_send_observation(0, now));
7989        state.record_observation_sent(0);
7990        
7991        // Path 0 is marked as notified, so won't try to send again
7992        assert!(!state.should_send_observation(0, now));
7993        
7994        // Path 1 cannot send because the shared rate limiter has no tokens
7995        assert!(!state.should_send_observation(1, now));
7996        
7997        // After 1 second, we get 1 token back
7998        let later = now + Duration::from_secs(1);
7999        assert!(state.should_send_observation(1, later));
8000        state.record_observation_sent(1);
8001        
8002        // And it's consumed again
8003        assert!(!state.should_send_observation(2, later));
8004    }
8005
8006    #[test]
8007    fn test_rate_limiting_zero_rate() {
8008        // Test that rate of 0 means no observations
8009        let now = Instant::now();
8010        let config = AddressDiscoveryConfig {
8011            enabled: true,
8012            max_observation_rate: 0, // No observations allowed
8013            observe_all_paths: true,
8014        };
8015        let mut state = AddressDiscoveryState::new(&config, now);
8016        
8017        // Should never allow observations
8018        assert!(!state.should_send_observation(0, now));
8019        assert!(!state.should_send_observation(0, now + Duration::from_secs(10)));
8020        assert!(!state.should_send_observation(0, now + Duration::from_secs(100)));
8021    }
8022
8023    #[test]
8024    fn test_rate_limiting_update() {
8025        // Test updating rate limit during connection
8026        let now = Instant::now();
8027        let config = AddressDiscoveryConfig {
8028            enabled: true,
8029            max_observation_rate: 1, // Start with 1 per second
8030            observe_all_paths: true,
8031        };
8032        let mut state = AddressDiscoveryState::new(&config, now);
8033        
8034        // Use the initial token
8035        assert!(state.should_send_observation(0, now));
8036        state.record_observation_sent(0);
8037        // Path 0 is notified, try a different path
8038        assert!(!state.should_send_observation(1, now));
8039        
8040        // Update rate limit to 10 per second
8041        state.update_rate_limit(10.0);
8042        
8043        // Tokens don't immediately increase, need to wait for replenishment
8044        // After 100ms with rate 10/sec, we should get 1 token
8045        let later = now + Duration::from_millis(100);
8046        assert!(state.should_send_observation(1, later));
8047        state.record_observation_sent(1);
8048        
8049        // And we can continue sending at the new rate
8050        let later2 = now + Duration::from_millis(200);
8051        assert!(state.should_send_observation(2, later2));
8052    }
8053
8054    #[test]
8055    fn test_rate_limiting_burst() {
8056        // Test that rate limiter allows burst up to bucket capacity
8057        let now = Instant::now();
8058        let config = AddressDiscoveryConfig {
8059            enabled: true,
8060            max_observation_rate: 10, // 10 per second
8061            observe_all_paths: true,
8062        };
8063        let mut state = AddressDiscoveryState::new(&config, now);
8064        
8065        // Should allow up to 10 observations in burst
8066        for _ in 0..10 {
8067            assert!(state.should_send_observation(0, now));
8068            state.record_observation_sent(0);
8069        }
8070        
8071        // 11th should be rate limited
8072        assert!(!state.should_send_observation(0, now));
8073        
8074        // After 100ms, we should have 1 more token
8075        let later = now + Duration::from_millis(100);
8076        assert!(state.should_send_observation(0, later));
8077        state.record_observation_sent(0);
8078        assert!(!state.should_send_observation(0, later));
8079    }
8080
8081    #[test]
8082    fn test_connection_rate_limiting_with_check_observations() {
8083        // Test rate limiting through check_for_address_observations
8084        let now = Instant::now();
8085        let config = AddressDiscoveryConfig {
8086            enabled: true,
8087            max_observation_rate: 2, // 2 per second
8088            observe_all_paths: false,
8089        };
8090        let mut state = AddressDiscoveryState::new(&config, now);
8091        
8092        // Set up a path with an address
8093        let mut path_info = paths::PathAddressInfo::new();
8094        path_info.update_observed_address(
8095            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080),
8096            now
8097        );
8098        state.path_addresses.insert(0, path_info);
8099        
8100        // First observation should succeed
8101        let frame1 = state.queue_observed_address_frame(0, SocketAddr::from(([192, 168, 1, 1], 8080)));
8102        assert!(frame1.is_some());
8103        state.record_observation_sent(0);
8104        
8105        // Reset notified flag to test rate limiting (simulate address change or new observation opportunity)
8106        if let Some(info) = state.path_addresses.get_mut(&0) {
8107            info.notified = false;
8108        }
8109        
8110        // Second observation should also succeed (still have tokens)
8111        let frame2 = state.queue_observed_address_frame(0, SocketAddr::from(([192, 168, 1, 1], 8080)));
8112        assert!(frame2.is_some());
8113        state.record_observation_sent(0);
8114        
8115        // Reset notified flag again to test pure rate limiting
8116        if let Some(info) = state.path_addresses.get_mut(&0) {
8117            info.notified = false;
8118        }
8119        
8120        // Third should be rate limited (no more tokens)
8121        let frame3 = state.queue_observed_address_frame(0, SocketAddr::from(([192, 168, 1, 1], 8080)));
8122        assert!(frame3.is_none()); // Should fail due to rate limiting
8123        
8124        // After 500ms, should allow 1 more (rate is 2/sec, so 0.5s = 1 token)
8125        let later = now + Duration::from_millis(500);
8126        state.rate_limiter.update_tokens(later); // Update tokens based on elapsed time
8127        
8128        // Reset notified flag to test token replenishment
8129        if let Some(info) = state.path_addresses.get_mut(&0) {
8130            info.notified = false;
8131        }
8132        
8133        let frame4 = state.queue_observed_address_frame(0, SocketAddr::from(([192, 168, 1, 1], 8080)));
8134        assert!(frame4.is_some()); // Should succeed due to token replenishment
8135    }
8136
8137    #[test]
8138    fn test_queue_observed_address_frame() {
8139        // Test queueing OBSERVED_ADDRESS frames with rate limiting
8140        let now = Instant::now();
8141        let config = AddressDiscoveryConfig {
8142            enabled: true,
8143            max_observation_rate: 5,
8144            observe_all_paths: true,
8145        };
8146        let mut state = AddressDiscoveryState::new(&config, now);
8147        
8148        let addr = SocketAddr::from(([192, 168, 1, 100], 5000));
8149        
8150        // Should queue frame when allowed
8151        let frame = state.queue_observed_address_frame(0, addr);
8152        assert!(frame.is_some());
8153        assert_eq!(frame.unwrap().address, addr);
8154        
8155        // Record that we sent it
8156        state.record_observation_sent(0);
8157        
8158        // Should respect rate limiting
8159        for i in 0..4 {
8160            // Reset notified flag to test rate limiting  
8161            if let Some(info) = state.path_addresses.get_mut(&0) {
8162                info.notified = false;
8163            }
8164            
8165            let frame = state.queue_observed_address_frame(0, addr);
8166            assert!(frame.is_some(), "Frame {} should be allowed", i + 2);
8167            state.record_observation_sent(0);
8168        }
8169        
8170        // Reset notified flag one more time
8171        if let Some(info) = state.path_addresses.get_mut(&0) {
8172            info.notified = false;
8173        }
8174        
8175        // 6th should be rate limited (we've used all 5 tokens)
8176        let frame = state.queue_observed_address_frame(0, addr);
8177        assert!(frame.is_none(), "6th frame should be rate limited");
8178    }
8179
8180    #[test]
8181    fn test_multi_path_basic() {
8182        // Test basic multi-path functionality
8183        let now = Instant::now();
8184        let config = AddressDiscoveryConfig {
8185            enabled: true,
8186            max_observation_rate: 10,
8187            observe_all_paths: true,
8188        };
8189        let mut state = AddressDiscoveryState::new(&config, now);
8190        
8191        let addr1 = SocketAddr::from(([192, 168, 1, 1], 5000));
8192        let addr2 = SocketAddr::from(([10, 0, 0, 1], 6000));
8193        let addr3 = SocketAddr::from(([172, 16, 0, 1], 7000));
8194        
8195        // Handle observations for different paths
8196        state.handle_observed_address(addr1, 0, now);
8197        state.handle_observed_address(addr2, 1, now);
8198        state.handle_observed_address(addr3, 2, now);
8199        
8200        // Each path should have its own observed address
8201        assert_eq!(state.get_observed_address(0), Some(addr1));
8202        assert_eq!(state.get_observed_address(1), Some(addr2));
8203        assert_eq!(state.get_observed_address(2), Some(addr3));
8204        
8205        // All paths should have unnotified changes
8206        assert!(state.has_unnotified_changes());
8207        
8208        // Check that we have 3 observation events
8209        assert_eq!(state.observed_addresses.len(), 3);
8210    }
8211
8212    #[test]
8213    fn test_multi_path_observe_primary_only() {
8214        // Test that when observe_all_paths is false, only primary path is observed
8215        let now = Instant::now();
8216        let config = AddressDiscoveryConfig {
8217            enabled: true,
8218            max_observation_rate: 10,
8219            observe_all_paths: false, // Only observe primary path
8220        };
8221        let mut state = AddressDiscoveryState::new(&config, now);
8222        
8223        // Primary path (0) should be observable
8224        assert!(state.should_send_observation(0, now));
8225        state.record_observation_sent(0);
8226        
8227        // Non-primary paths should not be observable
8228        assert!(!state.should_send_observation(1, now));
8229        assert!(!state.should_send_observation(2, now));
8230        
8231        // Can't queue frames for non-primary paths
8232        let addr = SocketAddr::from(([192, 168, 1, 1], 5000));
8233        assert!(state.queue_observed_address_frame(0, addr).is_some());
8234        assert!(state.queue_observed_address_frame(1, addr).is_none());
8235        assert!(state.queue_observed_address_frame(2, addr).is_none());
8236    }
8237
8238    #[test]
8239    fn test_multi_path_rate_limiting() {
8240        // Test that rate limiting is shared across all paths
8241        let now = Instant::now();
8242        let config = AddressDiscoveryConfig {
8243            enabled: true,
8244            max_observation_rate: 3, // Low rate to test sharing
8245            observe_all_paths: true,
8246        };
8247        let mut state = AddressDiscoveryState::new(&config, now);
8248        
8249        // Use tokens across different paths
8250        assert!(state.should_send_observation(0, now));
8251        state.record_observation_sent(0);
8252        
8253        assert!(state.should_send_observation(1, now));
8254        state.record_observation_sent(1);
8255        
8256        assert!(state.should_send_observation(2, now));
8257        state.record_observation_sent(2);
8258        
8259        // All tokens consumed, no path can send
8260        assert!(!state.should_send_observation(3, now));
8261        assert!(!state.should_send_observation(0, now)); // Even path 0 can't send again
8262        
8263        // After 1 second, all paths can use the new tokens
8264        let later = now + Duration::from_secs(1);
8265        assert!(state.should_send_observation(4, later));
8266        assert!(state.should_send_observation(5, later));
8267        assert!(state.should_send_observation(6, later));
8268    }
8269
8270    #[test]
8271    fn test_multi_path_address_changes() {
8272        // Test handling address changes on different paths
8273        let now = Instant::now();
8274        let config = AddressDiscoveryConfig {
8275            enabled: true,
8276            max_observation_rate: 10,
8277            observe_all_paths: true,
8278        };
8279        let mut state = AddressDiscoveryState::new(&config, now);
8280        
8281        let addr1a = SocketAddr::from(([192, 168, 1, 1], 5000));
8282        let addr1b = SocketAddr::from(([192, 168, 1, 2], 5000));
8283        let addr2a = SocketAddr::from(([10, 0, 0, 1], 6000));
8284        let addr2b = SocketAddr::from(([10, 0, 0, 2], 6000));
8285        
8286        // Initial addresses
8287        state.handle_observed_address(addr1a, 0, now);
8288        state.handle_observed_address(addr2a, 1, now);
8289        
8290        // Mark as notified
8291        state.record_observation_sent(0);
8292        state.record_observation_sent(1);
8293        assert!(!state.has_unnotified_changes());
8294        
8295        // Change address on path 0
8296        state.handle_observed_address(addr1b, 0, now + Duration::from_secs(1));
8297        assert!(state.has_unnotified_changes());
8298        
8299        // Path 0 should have new address, path 1 unchanged
8300        assert_eq!(state.get_observed_address(0), Some(addr1b));
8301        assert_eq!(state.get_observed_address(1), Some(addr2a));
8302        
8303        // Mark path 0 as notified
8304        state.record_observation_sent(0);
8305        assert!(!state.has_unnotified_changes());
8306        
8307        // Change address on path 1
8308        state.handle_observed_address(addr2b, 1, now + Duration::from_secs(2));
8309        assert!(state.has_unnotified_changes());
8310    }
8311
8312    #[test]
8313    fn test_multi_path_migration() {
8314        // Test path migration scenario
8315        let now = Instant::now();
8316        let config = AddressDiscoveryConfig {
8317            enabled: true,
8318            max_observation_rate: 10,
8319            observe_all_paths: true,
8320        };
8321        let mut state = AddressDiscoveryState::new(&config, now);
8322        
8323        let addr_old = SocketAddr::from(([192, 168, 1, 1], 5000));
8324        let addr_new = SocketAddr::from(([10, 0, 0, 1], 6000));
8325        
8326        // Establish observation on path 0
8327        state.handle_observed_address(addr_old, 0, now);
8328        assert_eq!(state.get_observed_address(0), Some(addr_old));
8329        
8330        // Simulate path migration - new path gets different ID
8331        state.handle_observed_address(addr_new, 1, now + Duration::from_secs(1));
8332        
8333        // Both paths should have their addresses
8334        assert_eq!(state.get_observed_address(0), Some(addr_old));
8335        assert_eq!(state.get_observed_address(1), Some(addr_new));
8336        
8337        // In real implementation, old path would be cleaned up eventually
8338        // For now, we just track both
8339        assert_eq!(state.path_addresses.len(), 2);
8340    }
8341
8342    #[test]
8343    fn test_check_for_address_observations_multi_path() {
8344        // Test the check_for_address_observations method with multiple paths
8345        let now = Instant::now();
8346        let config = AddressDiscoveryConfig {
8347            enabled: true,
8348            max_observation_rate: 10,
8349            observe_all_paths: true,
8350        };
8351        let mut state = AddressDiscoveryState::new(&config, now);
8352        
8353        // Set up multiple paths with unnotified addresses
8354        let addr1 = SocketAddr::from(([192, 168, 1, 1], 5000));
8355        let addr2 = SocketAddr::from(([10, 0, 0, 1], 6000));
8356        let addr3 = SocketAddr::from(([172, 16, 0, 1], 7000));
8357        
8358        state.handle_observed_address(addr1, 0, now);
8359        state.handle_observed_address(addr2, 1, now);
8360        state.handle_observed_address(addr3, 2, now);
8361        
8362        // Check for observations - should return frames for all unnotified paths
8363        let frames = state.check_for_address_observations(0, true, now);
8364        
8365        // Should get frames for all 3 paths
8366        assert_eq!(frames.len(), 3);
8367        
8368        // Test the ordering - frames should be in path ID order
8369        // This test should fail initially
8370        assert_eq!(frames[0].address, addr1);
8371        assert_eq!(frames[1].address, addr2);
8372        assert_eq!(frames[2].address, addr3);
8373        
8374        // Verify addresses in frames
8375        let frame_addrs: Vec<_> = frames.iter().map(|f| f.address).collect();
8376        assert!(frame_addrs.contains(&addr1));
8377        assert!(frame_addrs.contains(&addr2));
8378        assert!(frame_addrs.contains(&addr3));
8379        
8380        // All paths should now be marked as notified
8381        assert!(!state.has_unnotified_changes());
8382    }
8383
8384    #[test]
8385    fn test_multi_path_with_peer_not_supporting() {
8386        // Test behavior when peer doesn't support address discovery
8387        let now = Instant::now();
8388        let config = AddressDiscoveryConfig {
8389            enabled: true,
8390            max_observation_rate: 10,
8391            observe_all_paths: true,
8392        };
8393        let mut state = AddressDiscoveryState::new(&config, now);
8394        
8395        // Set up paths
8396        state.handle_observed_address(SocketAddr::from(([192, 168, 1, 1], 5000)), 0, now);
8397        state.handle_observed_address(SocketAddr::from(([10, 0, 0, 1], 6000)), 1, now);
8398        
8399        // Check with peer not supporting - should return empty
8400        let frames = state.check_for_address_observations(0, false, now);
8401        assert_eq!(frames.len(), 0);
8402        
8403        // Paths should still have unnotified changes
8404        assert!(state.has_unnotified_changes());
8405    }
8406
8407    // Tests for Phase 3.2: Bootstrap Node Behavior
8408    #[test]
8409    fn test_bootstrap_node_aggressive_observation_mode() {
8410        // Test that bootstrap nodes use more aggressive observation settings
8411        let config = AddressDiscoveryConfig {
8412            enabled: true,
8413            max_observation_rate: 10,
8414            observe_all_paths: false,
8415        };
8416        let now = Instant::now();
8417        let mut state = AddressDiscoveryState::new(&config, now);
8418        
8419        // Initially not in bootstrap mode
8420        assert!(!state.is_bootstrap_mode());
8421        
8422        // Enable bootstrap mode
8423        state.set_bootstrap_mode(true);
8424        assert!(state.is_bootstrap_mode());
8425        
8426        // Bootstrap mode should observe all paths regardless of config
8427        assert!(state.should_observe_path(0)); // Primary path
8428        assert!(state.should_observe_path(1)); // Secondary paths
8429        assert!(state.should_observe_path(2));
8430        
8431        // Bootstrap mode should have higher rate limit
8432        let bootstrap_rate = state.get_effective_rate_limit();
8433        assert!(bootstrap_rate > 10.0); // Should be higher than configured
8434    }
8435
8436    #[test]
8437    fn test_bootstrap_node_immediate_observation() {
8438        // Test that bootstrap nodes send observations immediately on new connections
8439        let config = AddressDiscoveryConfig {
8440            enabled: true,
8441            max_observation_rate: 10,
8442            observe_all_paths: false,
8443        };
8444        let now = Instant::now();
8445        let mut state = AddressDiscoveryState::new(&config, now);
8446        state.set_bootstrap_mode(true);
8447        
8448        // Add an observed address
8449        let addr = SocketAddr::from(([192, 168, 1, 100], 5000));
8450        state.handle_observed_address(addr, 0, now);
8451        
8452        // Bootstrap nodes should want to send immediately on new connections
8453        assert!(state.should_send_observation_immediately(true));
8454        
8455        // Should bypass normal rate limiting for first observation
8456        assert!(state.should_send_observation(0, now));
8457        
8458        // Queue the frame
8459        let frame = state.queue_observed_address_frame(0, addr);
8460        assert!(frame.is_some());
8461    }
8462
8463    #[test]
8464    fn test_bootstrap_node_multiple_path_observations() {
8465        // Test bootstrap nodes observe all paths aggressively
8466        let config = AddressDiscoveryConfig {
8467            enabled: true,
8468            max_observation_rate: 5, // Low rate
8469            observe_all_paths: false, // Normally only primary
8470        };
8471        let now = Instant::now();
8472        let mut state = AddressDiscoveryState::new(&config, now);
8473        state.set_bootstrap_mode(true);
8474        
8475        // Add addresses on multiple paths
8476        let addrs = vec![
8477            (0, SocketAddr::from(([192, 168, 1, 1], 5000))),
8478            (1, SocketAddr::from(([10, 0, 0, 1], 6000))),
8479            (2, SocketAddr::from(([172, 16, 0, 1], 7000))),
8480        ];
8481        
8482        for (path_id, addr) in &addrs {
8483            state.handle_observed_address(*addr, *path_id, now);
8484        }
8485        
8486        // Bootstrap nodes should observe all paths despite config
8487        let frames = state.check_for_address_observations(0, true, now);
8488        assert_eq!(frames.len(), 3);
8489        
8490        // Verify all addresses are included
8491        for (_, addr) in &addrs {
8492            assert!(frames.iter().any(|f| f.address == *addr));
8493        }
8494    }
8495
8496    #[test]
8497    fn test_bootstrap_node_rate_limit_override() {
8498        // Test that bootstrap nodes have higher rate limits
8499        let config = AddressDiscoveryConfig {
8500            enabled: true,
8501            max_observation_rate: 1, // Very low configured rate
8502            observe_all_paths: false,
8503        };
8504        let now = Instant::now();
8505        let mut state = AddressDiscoveryState::new(&config, now);
8506        state.set_bootstrap_mode(true);
8507        
8508        // Bootstrap nodes should be able to send more than configured rate
8509        let addr = SocketAddr::from(([192, 168, 1, 1], 5000));
8510        
8511        // Send multiple observations rapidly
8512        for i in 0..10 {
8513            state.handle_observed_address(addr, i, now);
8514            let can_send = state.should_send_observation(i, now);
8515            assert!(can_send, "Bootstrap node should send observation {}", i);
8516            state.record_observation_sent(i);
8517        }
8518    }
8519
8520    #[test]
8521    fn test_bootstrap_node_configuration() {
8522        // Test bootstrap-specific configuration
8523        let mut config = AddressDiscoveryConfig {
8524            enabled: true,
8525            max_observation_rate: 10,
8526            observe_all_paths: false,
8527        };
8528        
8529        // Apply bootstrap configuration
8530        config.apply_bootstrap_settings();
8531        
8532        // Bootstrap config should have maximum rate and observe all paths
8533        assert_eq!(config.max_observation_rate, 63); // Maximum 6-bit value
8534        assert!(config.observe_all_paths);
8535        assert!(config.enabled);
8536    }
8537
8538    #[test]
8539    fn test_bootstrap_role_detection() {
8540        use crate::transport_parameters::{NatTraversalRole, NatTraversalConfig};
8541        use crate::VarInt;
8542        
8543        // Test automatic detection of bootstrap role
8544        let nat_config = NatTraversalConfig::new(
8545            NatTraversalRole::Bootstrap,
8546            VarInt::from_u32(8),
8547            VarInt::from_u32(10000),
8548            VarInt::from_u32(3),
8549            None
8550        );
8551        
8552        // When connection is established with bootstrap role,
8553        // address discovery should automatically enable bootstrap mode
8554        let addr_discovery_config = AddressDiscoveryConfig {
8555            enabled: true,
8556            max_observation_rate: 10,
8557            observe_all_paths: false,
8558        };
8559        
8560        let mut state = AddressDiscoveryState::new(&addr_discovery_config, Instant::now());
8561        
8562        // Simulate role detection
8563        if matches!(nat_config.role(), NatTraversalRole::Bootstrap) {
8564            state.set_bootstrap_mode(true);
8565        }
8566        
8567        assert!(state.is_bootstrap_mode());
8568    }
8569
8570    #[test]
8571    fn test_bootstrap_node_persistent_observation() {
8572        // Test that bootstrap nodes continue observing throughout connection lifetime
8573        let config = AddressDiscoveryConfig {
8574            enabled: true,
8575            max_observation_rate: 10,
8576            observe_all_paths: false,
8577        };
8578        let mut now = Instant::now();
8579        let mut state = AddressDiscoveryState::new(&config, now);
8580        state.set_bootstrap_mode(true);
8581        
8582        let addr1 = SocketAddr::from(([192, 168, 1, 1], 5000));
8583        let addr2 = SocketAddr::from(([192, 168, 1, 2], 5000));
8584        
8585        // Initial observation
8586        state.handle_observed_address(addr1, 0, now);
8587        assert!(state.should_send_observation(0, now));
8588        state.record_observation_sent(0);
8589        
8590        // After some time, address changes
8591        now += Duration::from_secs(60);
8592        state.handle_observed_address(addr2, 0, now);
8593        
8594        // Bootstrap nodes should still be observing actively
8595        assert!(state.should_send_observation(0, now));
8596    }
8597
8598    #[test]
8599    fn test_bootstrap_node_multi_peer_support() {
8600        // Test that bootstrap nodes can handle observations for multiple peers
8601        // This is more of an integration test concept, but we can test the state management
8602        let config = AddressDiscoveryConfig {
8603            enabled: true,
8604            max_observation_rate: 50, // Higher rate for multiple peers
8605            observe_all_paths: true,
8606        };
8607        let now = Instant::now();
8608        let mut state = AddressDiscoveryState::new(&config, now);
8609        state.set_bootstrap_mode(true);
8610        
8611        // Simulate multiple peer connections (using different path IDs)
8612        let peer_addresses = vec![
8613            (0, SocketAddr::from(([192, 168, 1, 1], 5000))), // Peer 1
8614            (1, SocketAddr::from(([10, 0, 0, 1], 6000))),    // Peer 2
8615            (2, SocketAddr::from(([172, 16, 0, 1], 7000))),  // Peer 3
8616            (3, SocketAddr::from(([192, 168, 2, 1], 8000))), // Peer 4
8617        ];
8618        
8619        // Add all peer addresses
8620        for (path_id, addr) in &peer_addresses {
8621            state.handle_observed_address(*addr, *path_id, now);
8622        }
8623        
8624        // Bootstrap should observe all peers
8625        let frames = state.check_for_address_observations(0, true, now);
8626        assert_eq!(frames.len(), peer_addresses.len());
8627        
8628        // Verify all addresses are observed
8629        for (_, addr) in &peer_addresses {
8630            assert!(frames.iter().any(|f| f.address == *addr));
8631        }
8632    }
8633    
8634    // Include comprehensive address discovery tests
8635    mod address_discovery_tests {
8636        include!("address_discovery_tests.rs");
8637    }
8638}