Skip to main content

simoom_quic/
connection.rs

1//! The QUIC connection state machine (RFC 9000, RFC 9001, RFC 9002), sans-io.
2//!
3//! Feed received datagrams with [`Connection::recv`], send what [`Connection::poll_transmit`]
4//! produces, call [`Connection::handle_timeout`] at [`Connection::poll_timeout`], and drain
5//! [`Connection::poll_event`]. Streams are used through the `stream_*` methods.
6
7use crate::coding::{put_varint_fixed, Reader};
8use crate::config::Config;
9use crate::crypto::{CryptoSession, HeaderKey, KeyChange, Keys, Level, NextSecrets, PacketKey};
10use crate::error::*;
11use crate::frame::{self, Frame};
12use crate::packet::{self, PacketType, MIN_INITIAL_SIZE};
13use crate::params::{Cid, TransportParams};
14use crate::ranges::RangeSet;
15use crate::recovery::{Recovery, SentFrame, SentPacket};
16use crate::stream::{Control, StreamConfig, StreamEvent, Streams};
17use std::collections::{BTreeMap, VecDeque};
18use std::net::SocketAddr;
19use std::sync::Arc;
20use std::time::{Duration, Instant};
21
22/// Why a connection ended.
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub enum ConnectionError {
25    /// We closed it because of a transport error.
26    Transport(TransportError),
27    /// The peer closed it with a transport error.
28    PeerTransport { code: u64, frame_type: u64, reason: Vec<u8> },
29    /// The peer closed it from the application.
30    PeerApplication { code: u64, reason: Vec<u8> },
31    /// We closed it from the application.
32    LocalApplication { code: u64 },
33    IdleTimeout,
34    StatelessReset,
35    /// The server supports none of our versions.
36    VersionMismatch,
37}
38
39/// Application-visible events.
40#[derive(Clone, Debug, PartialEq, Eq)]
41pub enum Event {
42    /// The handshake completed.
43    Connected,
44    /// The peer opened a stream.
45    StreamOpened(u64),
46    StreamReadable(u64),
47    StreamWritable(u64),
48    /// The peer sent STOP_SENDING (a RESET_STREAM was sent in reply).
49    StreamStopped { id: u64, code: u64 },
50    /// The peer reset the stream.
51    StreamReset { id: u64, code: u64 },
52    /// More locally initiated streams of this kind (`true` = bidirectional) may be opened.
53    StreamsAvailable(bool),
54    /// A path changed after successful validation.
55    PathMigrated(SocketAddr),
56    /// The connection closed; it drains for a while before [`Connection::is_drained`].
57    Closed(ConnectionError),
58}
59
60/// Changes the endpoint must apply to its connection-ID routing table.
61#[derive(Clone, Debug, PartialEq, Eq)]
62pub enum EndpointEvent {
63    NewCid(Cid),
64    RetireCid(Cid),
65    /// A stateless reset token the peer may use against us.
66    ResetToken([u8; 16]),
67}
68
69/// One or more datagrams in the caller's buffer, all to `destination`. When
70/// `segment_size` is set, the buffer holds several datagrams of that size (the last may be
71/// shorter): suitable for GSO, or to be split by the caller.
72#[derive(Clone, Copy, Debug, PartialEq, Eq)]
73pub struct Transmit {
74    pub destination: SocketAddr,
75    pub size: usize,
76    pub segment_size: Option<usize>,
77}
78
79#[derive(Clone, Copy, Debug, Default)]
80pub struct Stats {
81    pub sent_packets: u64,
82    pub recv_packets: u64,
83    pub lost_packets: u64,
84    pub sent_bytes: u64,
85    pub recv_bytes: u64,
86    pub dropped_packets: u64,
87    pub key_updates: u64,
88    pub cwnd: u64,
89    pub rtt: Duration,
90    pub mtu: usize,
91}
92
93#[derive(Clone, Copy, Debug, PartialEq, Eq)]
94enum State {
95    Handshake,
96    Established,
97    Closing(Instant),
98    Draining(Instant),
99    Drained,
100}
101
102/// Average spacing of skipped 1-RTT packet numbers (optimistic-ACK detection).
103const PN_SKIP_PERIOD: u64 = 256;
104
105/// Bookkeeping charged per buffered out-of-order CRYPTO chunk (map entry and Vec header).
106const CRYPTO_CHUNK_OVERHEAD: usize = 64;
107
108/// Out-of-order CRYPTO reassembly for one level.
109#[derive(Default)]
110struct CryptoIn {
111    read: u64,
112    ooo: BTreeMap<u64, Vec<u8>>,
113    ooo_bytes: usize,
114}
115
116#[derive(Default)]
117struct Space {
118    keys: Option<Keys>,
119    crypto_out: Vec<u8>,
120    crypto_sent: u64,
121    crypto_retx: RangeSet,
122    crypto_in: CryptoIn,
123    recv: RangeSet,
124    ack_floor: u64,
125    largest_recv: Option<(u64, Instant)>,
126    unacked_eliciting: u32,
127    ack_now: bool,
128    ack_deadline: Option<Instant>,
129    probes: u8,
130    discarded: bool,
131}
132
133impl Space {
134    fn has_crypto(&self) -> bool {
135        !self.crypto_retx.is_empty() || self.crypto_sent < self.crypto_out.len() as u64
136    }
137}
138
139struct OneRtt {
140    local: Box<dyn PacketKey>,
141    remote: Box<dyn PacketKey>,
142    local_hp: Box<dyn HeaderKey>,
143    remote_hp: Box<dyn HeaderKey>,
144    secrets: Box<dyn NextSecrets>,
145    phase: bool,
146    next: Option<(Box<dyn PacketKey>, Box<dyn PacketKey>)>,
147    prev_remote: Option<(Box<dyn PacketKey>, Option<Instant>)>,
148    phase_first_sent: u64,
149    phase_first_recv: Option<u64>,
150    update_allowed: bool,
151    sealed: u64,
152}
153
154struct Path {
155    remote: SocketAddr,
156    validated: bool,
157    recv_bytes: u64,
158    sent_bytes: u64,
159    challenge: Option<([u8; 8], Instant)>,
160    challenge_pending: bool,
161}
162
163impl Path {
164    fn new(remote: SocketAddr, validated: bool) -> Self {
165        Path { remote, validated, recv_bytes: 0, sent_bytes: 0, challenge: None, challenge_pending: false }
166    }
167    /// Bytes we may still send before address validation (RFC 9000 §8.1).
168    fn budget(&self) -> usize {
169        if self.validated {
170            usize::MAX
171        } else {
172            (self.recv_bytes * 3).saturating_sub(self.sent_bytes) as usize
173        }
174    }
175}
176
177struct LocalCid {
178    seq: u64,
179    cid: Cid,
180    retired: bool,
181}
182
183struct RemoteCid {
184    seq: u64,
185    cid: Cid,
186    token: Option<[u8; 16]>,
187}
188
189/// A packet written into the datagram buffer but not yet sealed.
190struct Building {
191    space: usize,
192    start: usize,
193    len_at: Option<usize>,
194    pn_at: usize,
195    pn: u64,
196    pn_len: usize,
197    eliciting: bool,
198    frames: Vec<SentFrame>,
199    mtu_probe: bool,
200}
201
202pub struct Connection {
203    cfg: Arc<Config>,
204    is_server: bool,
205    version: u32,
206    state: State,
207    session: Box<dyn CryptoSession>,
208    write_level: Level,
209    spaces: [Space; 3],
210    one_rtt: Option<OneRtt>,
211    handshake_complete: bool,
212    handshake_confirmed: bool,
213    peer_params: Option<TransportParams>,
214    streams: Streams,
215    recovery: Recovery,
216    path: Path,
217    prev_path: Option<Path>,
218    path_responses: VecDeque<([u8; 8], SocketAddr)>,
219    local_cids: Vec<LocalCid>,
220    next_local_seq: u64,
221    remote_cids: Vec<RemoteCid>,
222    remote_cid_seq: u64,
223    retire_prior_to: u64,
224    pending_retire: VecDeque<u64>,
225    pending_new_cids: VecDeque<u64>,
226    /// The client's first destination CID (server: from the first Initial).
227    orig_dcid: Cid,
228    /// Client: the DCID chosen by the server is adopted once.
229    dcid_switched: bool,
230    retry_scid: Option<Cid>,
231    peer_initial_scid: Option<Cid>,
232    token: Vec<u8>,
233    new_token: Option<Vec<u8>>,
234    new_token_pending: bool,
235    received_new_token: Option<Vec<u8>>,
236    handshake_done_pending: bool,
237    ping_pending: bool,
238    /// Test hook: raw frame bytes written verbatim into the next 1-RTT packet.
239    raw_frames: Vec<u8>,
240    close: Option<(u64, Option<u64>, Vec<u8>)>,
241    close_sent_count: u32,
242    close_recv_count: u32,
243    error: Option<ConnectionError>,
244    events: VecDeque<Event>,
245    endpoint_events: VecDeque<EndpointEvent>,
246    idle_timeout: Duration,
247    last_activity: Instant,
248    eliciting_since_recv: bool,
249    mds: usize,
250    mtu_probe: Option<(usize, u8)>,
251    mtu_probe_inflight: bool,
252    probe_allowed: bool,
253    pacing_until: Option<Instant>,
254    failed_decrypts: u64,
255    any_packet_processed: bool,
256    stats: Stats,
257    /// The connection ID the Initial keys are derived from (RFC 9001 §5.2).
258    initial_dcid: Cid,
259    /// Server with more than one version: the TLS session starts once the whole ClientHello
260    /// is in, so its version (RFC 9368) is known. Holds (odcid, retry_scid) until then.
261    deferred: Option<(Cid, Option<Cid>)>,
262    /// The ClientHello bytes buffered while `deferred` is set.
263    hello: Vec<u8>,
264    /// Server that switched versions (RFC 9368): the original version and its Initial keys,
265    /// kept to read the client's Initial packets still sent in that version (retransmissions,
266    /// ACKs) until the Initial keys are discarded (RFC 9368 §4).
267    orig_initial: Option<(u32, Keys)>,
268}
269
270fn space_of(ty: PacketType) -> usize {
271    match ty {
272        PacketType::Initial => 0,
273        PacketType::Handshake => 1,
274        _ => 2,
275    }
276}
277
278impl Connection {
279    fn new(
280        cfg: Arc<Config>,
281        is_server: bool,
282        version: u32,
283        now: Instant,
284        remote: SocketAddr,
285        session: Box<dyn CryptoSession>,
286        local_cid: Cid,
287        remote_cid: Cid,
288        orig_dcid: Cid,
289    ) -> Self {
290        let t = &cfg.transport;
291        let streams = Streams::new(
292            is_server,
293            StreamConfig {
294                max_streams_bidi: t.max_streams_bidi,
295                max_streams_uni: t.max_streams_uni,
296                stream_window_bidi_local: t.stream_window_bidi_local,
297                stream_window_bidi_remote: t.stream_window_bidi_remote,
298                stream_window_uni: t.stream_window_uni,
299                conn_window: t.max_data,
300                send_buffer: t.send_buffer,
301            },
302        );
303        let mut spaces: [Space; 3] = Default::default();
304        spaces[0].keys = Some(cfg.provider.initial_keys(version, &orig_dcid, is_server));
305        let idle = t.max_idle_timeout;
306        Connection {
307            is_server,
308            version,
309            state: State::Handshake,
310            session,
311            write_level: Level::Initial,
312            spaces,
313            one_rtt: None,
314            handshake_complete: false,
315            handshake_confirmed: false,
316            peer_params: None,
317            streams,
318            recovery: Recovery::new(MIN_INITIAL_SIZE as u64),
319            path: Path::new(remote, !is_server),
320            prev_path: None,
321            path_responses: VecDeque::new(),
322            local_cids: vec![LocalCid { seq: 0, cid: local_cid, retired: false }],
323            next_local_seq: 1,
324            remote_cids: vec![RemoteCid { seq: 0, cid: remote_cid, token: None }],
325            remote_cid_seq: 0,
326            retire_prior_to: 0,
327            pending_retire: VecDeque::new(),
328            pending_new_cids: VecDeque::new(),
329            orig_dcid,
330            dcid_switched: is_server,
331            retry_scid: None,
332            peer_initial_scid: None,
333            token: Vec::new(),
334            new_token: None,
335            new_token_pending: false,
336            received_new_token: None,
337            handshake_done_pending: false,
338            ping_pending: false,
339            raw_frames: Vec::new(),
340            close: None,
341            close_sent_count: 0,
342            close_recv_count: 0,
343            error: None,
344            events: VecDeque::new(),
345            endpoint_events: VecDeque::new(),
346            idle_timeout: idle,
347            last_activity: now,
348            eliciting_since_recv: false,
349            mds: MIN_INITIAL_SIZE,
350            mtu_probe: None,
351            mtu_probe_inflight: false,
352            probe_allowed: false,
353            pacing_until: None,
354            failed_decrypts: 0,
355            any_packet_processed: false,
356            stats: Stats::default(),
357            initial_dcid: orig_dcid,
358            deferred: None,
359            hello: Vec::new(),
360            orig_initial: None,
361            cfg,
362        }
363    }
364
365    fn local_params(&self, odcid: Option<Cid>, retry_scid: Option<Cid>) -> Vec<u8> {
366        let t = &self.cfg.transport;
367        let local = self.local_cids[0].cid;
368        let p = TransportParams {
369            original_destination_connection_id: odcid,
370            max_idle_timeout: t.max_idle_timeout.as_millis() as u64,
371            stateless_reset_token: if self.is_server { Some(self.cfg.reset_token(&local)) } else { None },
372            max_udp_payload_size: t.max_udp_payload_size,
373            initial_max_data: t.max_data,
374            initial_max_stream_data_bidi_local: t.stream_window_bidi_local,
375            initial_max_stream_data_bidi_remote: t.stream_window_bidi_remote,
376            initial_max_stream_data_uni: t.stream_window_uni,
377            initial_max_streams_bidi: t.max_streams_bidi,
378            initial_max_streams_uni: t.max_streams_uni,
379            ack_delay_exponent: t.ack_delay_exponent,
380            max_ack_delay: t.max_ack_delay.as_millis() as u64,
381            disable_active_migration: t.disable_active_migration,
382            preferred_address: None,
383            active_connection_id_limit: t.active_connection_id_limit,
384            initial_source_connection_id: Some(local),
385            retry_source_connection_id: retry_scid,
386            // Compatible version negotiation (RFC 9368): only when more than one version is
387            // configured, so a v1-only endpoint sends exactly what it did before.
388            version_information: (self.cfg.versions.len() > 1).then(|| (self.version, self.cfg.versions.clone())),
389        };
390        let mut b = Vec::with_capacity(128);
391        p.encode(&mut b);
392        b
393    }
394
395    /// Starts a client connection to `remote`. `token` is a NEW_TOKEN value from an
396    /// earlier connection, or empty.
397    pub fn connect(
398        cfg: Arc<Config>,
399        now: Instant,
400        remote: SocketAddr,
401        server_name: &str,
402        token: &[u8],
403    ) -> Result<Self, TransportError> {
404        let mut scid = [0u8; 20];
405        let mut dcid = [0u8; 8];
406        cfg.provider.fill_random(&mut scid[..cfg.cid_len]);
407        cfg.provider.fill_random(&mut dcid);
408        let local = Cid::new(&scid[..cfg.cid_len]);
409        let dcid = Cid::new(&dcid);
410        let version = cfg.versions[0];
411        let placeholder: Box<dyn CryptoSession> = Box::new(Placeholder);
412        let mut c = Connection::new(cfg.clone(), false, version, now, remote, placeholder, local, dcid, dcid);
413        let tp = c.local_params(None, None);
414        c.session = cfg.provider.client_session(version, server_name, tp)?;
415        c.token = token.to_vec();
416        c.endpoint_events.push_back(EndpointEvent::NewCid(local));
417        c.drive_crypto()?;
418        Ok(c)
419    }
420
421    /// Creates a server connection for a client Initial (called by the endpoint).
422    #[allow(clippy::too_many_arguments)]
423    pub(crate) fn accept(
424        cfg: Arc<Config>,
425        now: Instant,
426        remote: SocketAddr,
427        version: u32,
428        local_cid: Cid,
429        client_dcid: Cid,
430        client_scid: Cid,
431        odcid: Cid,
432        retry_scid: Option<Cid>,
433        validated: bool,
434    ) -> Result<Self, TransportError> {
435        let placeholder: Box<dyn CryptoSession> = Box::new(Placeholder);
436        let mut c = Connection::new(cfg.clone(), true, version, now, remote, placeholder, local_cid, client_scid, client_dcid);
437        if cfg.versions.len() > 1 {
438            // The version may still change (RFC 9368): start TLS after the ClientHello.
439            c.deferred = Some((odcid, retry_scid));
440        } else {
441            let tp = c.local_params(Some(odcid), retry_scid);
442            c.session = cfg.provider.server_session(version, tp)?;
443        }
444        c.orig_dcid = odcid;
445        c.retry_scid = retry_scid;
446        c.peer_initial_scid = Some(client_scid);
447        c.path.validated = validated;
448        Ok(c)
449    }
450
451    // ---------------------------------------------------------------- accessors
452
453    pub fn is_server(&self) -> bool {
454        self.is_server
455    }
456    pub fn is_established(&self) -> bool {
457        self.state == State::Established
458    }
459    pub fn is_handshaking(&self) -> bool {
460        self.state == State::Handshake
461    }
462    /// Closing or draining (no new streams or data).
463    pub fn is_closed(&self) -> bool {
464        matches!(self.state, State::Closing(_) | State::Draining(_) | State::Drained)
465    }
466    /// The connection can be dropped.
467    pub fn is_drained(&self) -> bool {
468        self.state == State::Drained
469    }
470    pub fn error(&self) -> Option<&ConnectionError> {
471        self.error.as_ref()
472    }
473    pub fn alpn(&self) -> Option<&[u8]> {
474        self.session.alpn_protocol()
475    }
476    /// The TLS session: SNI, cipher suite, the peer's certificate chain.
477    pub fn tls(&self) -> &dyn CryptoSession {
478        &*self.session
479    }
480    pub fn remote_address(&self) -> SocketAddr {
481        self.path.remote
482    }
483    pub fn path_validated(&self) -> bool {
484        self.path.validated
485    }
486    pub fn peer_params(&self) -> Option<&TransportParams> {
487        self.peer_params.as_ref()
488    }
489    pub fn version(&self) -> u32 {
490        self.version
491    }
492    pub fn stats(&self) -> Stats {
493        let mut s = self.stats;
494        s.cwnd = self.recovery.cc.cwnd;
495        s.rtt = self.recovery.rtt.smoothed;
496        s.mtu = self.mds;
497        s
498    }
499    /// Our connection IDs currently active.
500    pub fn local_cids(&self) -> impl Iterator<Item = Cid> + '_ {
501        self.local_cids.iter().filter(|c| !c.retired).map(|c| c.cid)
502    }
503    /// The destination connection ID in use.
504    pub fn remote_cid(&self) -> Cid {
505        self.remote_cids[0].cid
506    }
507    /// The original destination connection ID (client's first DCID).
508    pub fn original_dcid(&self) -> Cid {
509        self.orig_dcid
510    }
511    /// Client: a token received in NEW_TOKEN, for a later connection.
512    pub fn new_token(&self) -> Option<&[u8]> {
513        self.received_new_token.as_deref()
514    }
515    pub fn poll_event(&mut self) -> Option<Event> {
516        self.pull_stream_events();
517        self.events.pop_front()
518    }
519    pub fn poll_endpoint_event(&mut self) -> Option<EndpointEvent> {
520        self.endpoint_events.pop_front()
521    }
522    /// Streams currently tracked.
523    pub fn stream_count(&self) -> usize {
524        self.streams.len()
525    }
526
527    fn pull_stream_events(&mut self) {
528        while let Some(e) = self.streams.events.pop_front() {
529            self.events.push_back(match e {
530                StreamEvent::Opened(id) => Event::StreamOpened(id),
531                StreamEvent::Readable(id) => Event::StreamReadable(id),
532                StreamEvent::Writable(id) => Event::StreamWritable(id),
533                StreamEvent::Stopped(id, code) => Event::StreamStopped { id, code },
534                StreamEvent::Reset(id, code) => Event::StreamReset { id, code },
535                StreamEvent::Available(b) => Event::StreamsAvailable(b),
536            });
537        }
538    }
539
540    // ---------------------------------------------------------------- streams
541
542    fn usable(&self) -> Result<(), StreamError> {
543        if self.is_closed() {
544            Err(StreamError::ConnectionClosed)
545        } else {
546            Ok(())
547        }
548    }
549
550    /// Opens a bidirectional stream.
551    pub fn open_bi(&mut self) -> Result<u64, StreamError> {
552        self.usable()?;
553        self.streams.open(true)
554    }
555    /// Opens a unidirectional stream.
556    pub fn open_uni(&mut self) -> Result<u64, StreamError> {
557        self.usable()?;
558        self.streams.open(false)
559    }
560    /// Queues data; returns the number of bytes accepted (backpressure: fewer than given).
561    pub fn stream_send(&mut self, id: u64, data: &[u8], fin: bool) -> Result<usize, StreamError> {
562        self.usable()?;
563        self.streams.write(id, data, fin)
564    }
565    /// Ends the send side.
566    pub fn stream_finish(&mut self, id: u64) -> Result<(), StreamError> {
567        self.usable()?;
568        self.streams.write(id, &[], true).map(|_| ())
569    }
570    /// Reads data; returns (bytes, fin).
571    pub fn stream_recv(&mut self, id: u64, out: &mut [u8]) -> Result<(usize, bool), StreamError> {
572        self.usable()?;
573        self.streams.read(id, out)
574    }
575    pub fn stream_reset(&mut self, id: u64, code: u64) -> Result<(), StreamError> {
576        self.usable()?;
577        self.streams.reset(id, code)
578    }
579    pub fn stream_stop(&mut self, id: u64, code: u64) -> Result<(), StreamError> {
580        self.usable()?;
581        self.streams.stop(id, code)
582    }
583    /// Bytes `stream_send` would accept now.
584    pub fn stream_writable(&self, id: u64) -> Option<u64> {
585        self.streams.writable(id)
586    }
587    /// Bytes written to the stream but not yet acknowledged.
588    pub fn stream_unacked(&self, id: u64) -> Option<u64> {
589        self.streams.unacked(id)
590    }
591    pub fn stream_exists(&self, id: u64) -> bool {
592        self.streams.contains(id)
593    }
594    /// Sends a PING (keep-alive).
595    pub fn ping(&mut self) {
596        self.ping_pending = true;
597    }
598
599    /// Test hook for adversarial tests: the largest 1-RTT packet number sent so far. Not part
600    /// of the stable API.
601    #[doc(hidden)]
602    pub fn largest_sent_packet_number(&self) -> Option<u64> {
603        let sp = &self.recovery.spaces[2];
604        let last = sp.next_pn.checked_sub(1)?;
605        if sp.skipped.back() == Some(&last) {
606            last.checked_sub(1)
607        } else {
608            Some(last)
609        }
610    }
611
612    /// Test hook for adversarial tests: `frames` (already encoded) are written verbatim into
613    /// the next 1-RTT packet, so a misbehaving peer can be played through the real packet
614    /// protection. Not part of the stable API.
615    #[doc(hidden)]
616    pub fn send_raw_frames(&mut self, frames: &[u8]) {
617        self.raw_frames.extend_from_slice(frames);
618        self.ping_pending = true;
619    }
620
621    // ---------------------------------------------------------------- closing
622
623    /// Closes the connection with an application error code.
624    pub fn close(&mut self, now: Instant, code: u64, reason: &[u8]) {
625        if self.is_closed() {
626            return;
627        }
628        self.close = Some((code, None, reason.to_vec()));
629        self.error = Some(ConnectionError::LocalApplication { code });
630        self.enter_closing(now);
631    }
632
633    fn close_transport(&mut self, now: Instant, e: TransportError) {
634        if self.is_closed() {
635            return;
636        }
637        self.close = Some((e.code, Some(e.frame_type), e.reason.as_bytes().to_vec()));
638        self.error = Some(ConnectionError::Transport(e.clone()));
639        self.events.push_back(Event::Closed(ConnectionError::Transport(e)));
640        self.enter_closing(now);
641    }
642
643    fn enter_closing(&mut self, now: Instant) {
644        let until = now + self.recovery.pto(2) * 3;
645        self.state = State::Closing(until);
646        self.close_sent_count = 0;
647        self.close_recv_count = 0;
648        self.ping_pending = false;
649    }
650
651    fn enter_draining(&mut self, now: Instant, err: ConnectionError) {
652        if matches!(self.state, State::Draining(_) | State::Drained) {
653            return;
654        }
655        let already_closing = matches!(self.state, State::Closing(_));
656        self.state = State::Draining(now + self.recovery.pto(2) * 3);
657        if !already_closing {
658            self.error = Some(err.clone());
659            self.events.push_back(Event::Closed(err));
660        }
661    }
662
663    fn drain_now(&mut self, err: ConnectionError) {
664        if self.state == State::Drained {
665            return;
666        }
667        if !self.is_closed() {
668            self.error = Some(err.clone());
669            self.events.push_back(Event::Closed(err));
670        }
671        self.state = State::Drained;
672        for c in &self.local_cids {
673            if !c.retired {
674                self.endpoint_events.push_back(EndpointEvent::RetireCid(c.cid));
675            }
676        }
677    }
678
679    // ---------------------------------------------------------------- receiving
680
681    /// Processes one received datagram (may hold coalesced packets). `data` is decrypted in
682    /// place.
683    pub fn recv(&mut self, now: Instant, remote: SocketAddr, data: &mut [u8]) {
684        if self.state == State::Drained {
685            return;
686        }
687        let len = data.len();
688        self.stats.recv_bytes += len as u64;
689        if remote == self.path.remote {
690            self.path.recv_bytes += len as u64;
691        } else if let Some(p) = self.prev_path.as_mut().filter(|p| p.remote == remote) {
692            p.recv_bytes += len as u64;
693        }
694        let mut start = 0;
695        let mut processed_any = false;
696        let mut first_dcid: Option<Cid> = None;
697        while start < len {
698            let cid_len = self.local_cids[0].cid.len();
699            let Some(h) = packet::parse_header(data, start, cid_len) else { break };
700            if let Some(f) = first_dcid {
701                // Coalesced packets must share the connection ID (RFC 9000 §12.2).
702                if data[h.dcid.clone()] != f[..] {
703                    break;
704                }
705            } else {
706                first_dcid = Some(Cid::new(&data[h.dcid.clone()]));
707            }
708            let end = h.end;
709            match h.ty {
710                PacketType::VersionNegotiation => {
711                    self.on_version_negotiation(now, &data[h.token.clone()]);
712                    return;
713                }
714                PacketType::Retry => {
715                    self.on_retry(now, data, &h);
716                    return;
717                }
718                PacketType::ZeroRtt => {
719                    // 0-RTT is not supported: discard.
720                    self.stats.dropped_packets += 1;
721                    start = end;
722                    continue;
723                }
724                _ => {}
725            }
726            // A client Initial in the version the server switched away from (RFC 9368 §4).
727            let original = self.is_server && h.ty == PacketType::Initial && self.orig_initial.as_ref().is_some_and(|o| o.0 == h.version);
728            if h.ty != PacketType::OneRtt && h.version != self.version && !original && !self.follow_version(&h) {
729                break;
730            }
731            let result = if original { self.recv_original_initial(now, remote, data, start, &h) } else { self.recv_packet(now, remote, data, start, &h) };
732            match result {
733                Ok(true) => processed_any = true,
734                Ok(false) => self.stats.dropped_packets += 1,
735                Err(e) => {
736                    self.close_transport(now, e);
737                    return;
738                }
739            }
740            if self.state == State::Drained {
741                return;
742            }
743            start = end;
744        }
745        if !processed_any {
746            self.check_stateless_reset(now, data);
747        }
748    }
749
750    fn check_stateless_reset(&mut self, _now: Instant, data: &[u8]) {
751        if data.len() < packet::MIN_RESET_SIZE || data[0] & 0x80 != 0 {
752            return;
753        }
754        let tail = &data[data.len() - 16..];
755        let hit = self.remote_cids.iter().any(|c| c.token.is_some_and(|t| crate::crypto::ct_eq(&t, tail)));
756        if hit {
757            self.drain_now(ConnectionError::StatelessReset);
758        }
759    }
760
761    /// Server: processes a client Initial in the original version with that version's keys
762    /// (packet numbers and CRYPTO offsets are shared across versions).
763    fn recv_original_initial(&mut self, now: Instant, remote: SocketAddr, data: &mut [u8], start: usize, h: &packet::Header) -> Result<bool, TransportError> {
764        let (v, keys) = self.orig_initial.take().expect("original keys");
765        let current = std::mem::replace(&mut self.spaces[0].keys, Some(keys));
766        let r = self.recv_packet(now, remote, data, start, h);
767        let used = std::mem::replace(&mut self.spaces[0].keys, current);
768        if self.spaces[0].discarded {
769            self.spaces[0].keys = None;
770        } else if let Some(k) = used {
771            self.orig_initial = Some((v, k));
772        }
773        r
774    }
775
776    /// Client: the server answered our first Initial in another configured, compatible
777    /// version (compatible version negotiation, RFC 9368 §2.3); continue in it.
778    fn follow_version(&mut self, h: &packet::Header) -> bool {
779        let ok = !self.is_server
780            && !self.any_packet_processed
781            && h.ty == PacketType::Initial
782            && self.cfg.versions.contains(&h.version)
783            && crate::vn::compatible(self.version, h.version);
784        if ok {
785            self.version = h.version;
786            self.spaces[0].keys = Some(self.cfg.provider.initial_keys(h.version, &self.initial_dcid, false));
787            self.session.set_version(h.version);
788        }
789        ok
790    }
791
792    fn on_version_negotiation(&mut self, now: Instant, list: &[u8]) {
793        if self.is_server || self.any_packet_processed {
794            return;
795        }
796        let mut r = Reader::new(list);
797        while let Some(v) = r.u32() {
798            if v == self.version {
799                return; // Must be ignored (RFC 9000 §6.2).
800            }
801        }
802        let _ = now;
803        self.drain_now(ConnectionError::VersionMismatch);
804    }
805
806    fn on_retry(&mut self, _now: Instant, data: &[u8], h: &packet::Header) {
807        if self.is_server || self.any_packet_processed || self.retry_scid.is_some() {
808            return;
809        }
810        let scid = Cid::new(&data[h.scid.clone()]);
811        let token = &data[h.token.clone()];
812        if token.is_empty() || scid[..] == self.remote_cids[0].cid[..] {
813            return;
814        }
815        let tag_at = data.len() - 16;
816        let expect = packet::retry_tag(&*self.cfg.provider, self.version, &self.orig_dcid, &data[..tag_at]);
817        if !crate::crypto::ct_eq(&expect, &data[tag_at..]) {
818            return;
819        }
820        self.retry_scid = Some(scid);
821        self.remote_cids[0].cid = scid;
822        self.token = token.to_vec();
823        self.spaces[0].keys = Some(self.cfg.provider.initial_keys(self.version, &scid, false));
824        self.initial_dcid = scid;
825        // Everything sent in Initial packets is resent with the token.
826        let s = &mut self.spaces[0];
827        s.crypto_retx.clear();
828        s.crypto_sent = 0;
829        self.recovery.discard(0);
830    }
831
832    /// Returns Ok(false) if the packet was dropped.
833    fn recv_packet(
834        &mut self,
835        now: Instant,
836        remote: SocketAddr,
837        data: &mut [u8],
838        start: usize,
839        h: &packet::Header,
840    ) -> Result<bool, TransportError> {
841        let space = space_of(h.ty);
842        if self.spaces[space].discarded {
843            return Ok(false);
844        }
845        if space < 2 && self.spaces[space].keys.is_none() {
846            return Ok(false);
847        }
848        if space == 2 && self.one_rtt.is_none() {
849            return Ok(false);
850        }
851        // Header protection.
852        let hp: &dyn HeaderKey = if space == 2 {
853            &*self.one_rtt.as_ref().unwrap().remote_hp
854        } else {
855            &*self.spaces[space].keys.as_ref().unwrap().remote.header
856        };
857        let first_before = data[start];
858        let Some((tpn, pn_len)) = packet::unprotect(data, start, h.pn_offset, h.end, hp) else {
859            return Ok(false);
860        };
861        let largest = self.spaces[space].largest_recv.map(|x| x.0);
862        let pn = packet::decode_pn(largest, tpn, pn_len);
863        let hdr_end = h.pn_offset + pn_len;
864        let first = data[start];
865        let (head, rest) = data[start..h.end].split_at_mut(hdr_end - start);
866        let decrypted = if space == 2 {
867            let phase = first & 0x04 != 0;
868            self.open_one_rtt(now, pn, phase, head, rest)
869        } else {
870            self.spaces[space].keys.as_ref().unwrap().remote.packet.open(pn, head, rest).ok()
871        };
872        let Some(plen) = decrypted else {
873            data[start] = first_before;
874            self.failed_decrypts += 1;
875            let limit = self.one_rtt.as_ref().map(|k| k.remote.integrity_limit()).unwrap_or(u64::MAX);
876            if self.failed_decrypts >= limit {
877                return Err(TransportError::new(AEAD_LIMIT_REACHED, "integrity limit reached"));
878            }
879            return Ok(false);
880        };
881        // Reserved bits must be zero once protection is removed (RFC 9000 §17.2, §17.3.1).
882        let reserved = if first & 0x80 != 0 { first & 0x0c } else { first & 0x18 };
883        if reserved != 0 {
884            return Err(TransportError::proto("reserved header bits set"));
885        }
886        // Duplicate detection.
887        let sp = &self.spaces[space];
888        if pn < sp.ack_floor || sp.recv.contains(pn) {
889            return Ok(false);
890        }
891        self.any_packet_processed = true;
892        self.stats.recv_packets += 1;
893
894        // Client: adopt the server's chosen connection ID from its first Initial/Handshake.
895        if !self.is_server && !self.dcid_switched && space < 2 {
896            self.dcid_switched = true;
897            let scid = Cid::new(&data[h.scid.clone()]);
898            self.remote_cids[0].cid = scid;
899            self.peer_initial_scid = Some(scid);
900        }
901        let dcid = Cid::new(&data[h.dcid.clone()]);
902        let payload_start = hdr_end;
903        let payload_end = hdr_end + plen;
904        let payload: &[u8] = &data[payload_start..payload_end];
905        let ptype = h.ty;
906        let (eliciting, non_probing) = self.process_frames(now, remote, ptype, space, payload, &dcid)?;
907
908        // Record for acknowledgement.
909        let sp = &mut self.spaces[space];
910        let out_of_order = sp.largest_recv.is_some_and(|(l, _)| pn != l + 1);
911        sp.recv.insert(pn, pn + 1);
912        sp.recv.truncate_low(self.cfg.transport.max_ack_ranges);
913        if sp.largest_recv.is_none_or(|(l, _)| pn > l) {
914            sp.largest_recv = Some((pn, now));
915        }
916        if eliciting {
917            sp.unacked_eliciting += 1;
918            if space < 2 || out_of_order || sp.unacked_eliciting >= self.cfg.transport.ack_eliciting_threshold {
919                sp.ack_now = true;
920            } else if sp.ack_deadline.is_none() {
921                sp.ack_deadline = Some(now + self.cfg.transport.max_ack_delay);
922            }
923        }
924        // Server: a Handshake packet proves the client's address; Initial keys go.
925        if self.is_server && space == 1 {
926            self.path.validated = true;
927            self.discard_space(0);
928        }
929        // Migration (RFC 9000 §9): a non-probing packet with the highest number from a new
930        // address moves the connection there.
931        if space == 2 && remote != self.path.remote && non_probing {
932            let highest = self.spaces[2].largest_recv.is_some_and(|(l, _)| l == pn);
933            if highest && self.is_server && self.handshake_confirmed {
934                self.migrate(now, remote);
935            }
936        }
937        if self.is_closed() {
938            if let State::Closing(_) = self.state {
939                // Answer packets in the closing state with CONNECTION_CLOSE, at a falling rate.
940                self.close_recv_count += 1;
941            }
942            return Ok(true);
943        }
944        self.last_activity = now;
945        self.eliciting_since_recv = false;
946        Ok(true)
947    }
948
949    fn open_one_rtt(&mut self, now: Instant, pn: u64, phase: bool, head: &[u8], rest: &mut [u8]) -> Option<usize> {
950        let k = self.one_rtt.as_mut().unwrap();
951        if phase == k.phase {
952            let n = k.remote.open(pn, head, rest).ok()?;
953            if k.phase_first_recv.is_none_or(|f| pn < f) {
954                if k.phase_first_recv.is_none() {
955                    // The peer moved to the phase we started: the old key can go soon.
956                    let pto3 = self.recovery.pto(2) * 3;
957                    if let Some(p) = k.prev_remote.as_mut() {
958                        p.1.get_or_insert(now + pto3);
959                    }
960                }
961                k.phase_first_recv = Some(pn);
962            }
963            return Some(n);
964        }
965        // Old phase: a reordered packet from before the last update, or the peer has not
966        // yet seen the update we started.
967        if let Some((prev, _)) = &k.prev_remote {
968            if k.phase_first_recv.is_none_or(|f| pn < f) {
969                return prev.open(pn, head, rest).ok();
970            }
971        }
972        // New phase: the peer updated keys (RFC 9001 §6.2).
973        if k.next.is_none() {
974            k.next = Some(k.secrets.next_packet_keys());
975        }
976        let n = k.next.as_ref().unwrap().1.open(pn, head, rest).ok()?;
977        if k.phase_first_recv.is_some_and(|f| pn < f) {
978            return None;
979        }
980        let pto3 = self.recovery.pto(2) * 3;
981        let k = self.one_rtt.as_mut().unwrap();
982        let (nl, nr) = k.next.take().unwrap();
983        let old_remote = std::mem::replace(&mut k.remote, nr);
984        k.local = nl;
985        k.prev_remote = Some((old_remote, Some(now + pto3)));
986        k.phase = !k.phase;
987        k.phase_first_recv = Some(pn);
988        k.phase_first_sent = self.recovery.spaces[2].next_pn;
989        k.update_allowed = false;
990        k.sealed = 0;
991        self.stats.key_updates += 1;
992        Some(n)
993    }
994
995    /// Starts a key update (RFC 9001 §6.1). Returns false when one is not allowed yet.
996    pub fn initiate_key_update(&mut self) -> bool {
997        if !self.handshake_confirmed {
998            return false;
999        }
1000        let next_pn = self.recovery.spaces[2].next_pn;
1001        let Some(k) = self.one_rtt.as_mut() else { return false };
1002        if !k.update_allowed {
1003            return false;
1004        }
1005        if k.next.is_none() {
1006            k.next = Some(k.secrets.next_packet_keys());
1007        }
1008        let (nl, nr) = k.next.take().unwrap();
1009        let old_remote = std::mem::replace(&mut k.remote, nr);
1010        k.local = nl;
1011        // The old remote key stays until the peer has moved to the new phase.
1012        k.prev_remote = Some((old_remote, None));
1013        k.phase = !k.phase;
1014        k.phase_first_recv = None;
1015        k.phase_first_sent = next_pn;
1016        k.update_allowed = false;
1017        k.sealed = 0;
1018        self.stats.key_updates += 1;
1019        true
1020    }
1021
1022    fn process_frames(
1023        &mut self,
1024        now: Instant,
1025        remote: SocketAddr,
1026        ptype: PacketType,
1027        space: usize,
1028        payload: &[u8],
1029        dcid: &Cid,
1030    ) -> Result<(bool, bool), TransportError> {
1031        if payload.is_empty() {
1032            return Err(TransportError::proto("packet without frames"));
1033        }
1034        let mut r = Reader::new(payload);
1035        let mut eliciting = false;
1036        let mut non_probing = false;
1037        while !r.is_empty() {
1038            let (ty, f) = frame::parse(&mut r)?;
1039            let allowed = match ptype {
1040                PacketType::Initial | PacketType::Handshake => matches!(
1041                    f,
1042                    Frame::Padding | Frame::Ping | Frame::Ack { .. } | Frame::Crypto { .. }
1043                ) || matches!(f, Frame::ConnectionClose { frame_type: Some(_), .. }),
1044                _ => true,
1045            };
1046            if !allowed {
1047                return Err(TransportError::frame(PROTOCOL_VIOLATION, ty, "frame not allowed in this packet type"));
1048            }
1049            eliciting |= f.is_ack_eliciting();
1050            non_probing |= !f.is_probing();
1051            if self.is_closed() {
1052                // In the closing or draining state only CONNECTION_CLOSE matters.
1053                if let Frame::ConnectionClose { code, frame_type, reason } = f {
1054                    self.on_peer_close(now, code, frame_type, reason);
1055                }
1056                continue;
1057            }
1058            self.process_frame(now, remote, space, ty, f, dcid)?;
1059            if self.state == State::Drained {
1060                break;
1061            }
1062        }
1063        Ok((eliciting, non_probing))
1064    }
1065
1066    fn on_peer_close(&mut self, now: Instant, code: u64, frame_type: Option<u64>, reason: &[u8]) {
1067        let reason = reason[..reason.len().min(256)].to_vec();
1068        let err = match frame_type {
1069            Some(frame_type) => ConnectionError::PeerTransport { code, frame_type, reason },
1070            None => ConnectionError::PeerApplication { code, reason },
1071        };
1072        self.enter_draining(now, err);
1073    }
1074
1075    fn process_frame(
1076        &mut self,
1077        now: Instant,
1078        remote: SocketAddr,
1079        space: usize,
1080        ty: u64,
1081        f: Frame<'_>,
1082        dcid: &Cid,
1083    ) -> Result<(), TransportError> {
1084        let server_only = |is_server: bool| {
1085            if is_server {
1086                Err(TransportError::frame(PROTOCOL_VIOLATION, ty, "frame only a server may send"))
1087            } else {
1088                Ok(())
1089            }
1090        };
1091        match f {
1092            Frame::Padding | Frame::Ping => {}
1093            Frame::Ack { ranges, delay, .. } => {
1094                let exp = self.peer_params.as_ref().map_or(3, |p| p.ack_delay_exponent);
1095                let delay = Duration::from_micros(delay.checked_shl(exp as u32).unwrap_or(u64::MAX).min(1 << 40));
1096                let res = self.recovery.on_ack(space, &ranges, delay, now, self.handshake_confirmed)?;
1097                for p in res.acked {
1098                    self.on_packet_acked(space, p);
1099                }
1100                self.on_packets_lost(space, res.lost);
1101            }
1102            Frame::Crypto { offset, data } => self.on_crypto(space, offset, data)?,
1103            Frame::Stream { id, offset, data, fin } => self.streams.on_stream(id, offset, data, fin)?,
1104            Frame::ResetStream { id, code, final_size } => self.streams.on_reset(id, code, final_size)?,
1105            Frame::StopSending { id, code } => self.streams.on_stop_sending(id, code)?,
1106            Frame::MaxData(m) => self.streams.on_max_data(m),
1107            Frame::MaxStreamData { id, max } => self.streams.on_max_stream_data(id, max)?,
1108            Frame::MaxStreams { bidi, max } => self.streams.on_max_streams(bidi, max),
1109            Frame::DataBlocked(_) => {}
1110            Frame::StreamDataBlocked { id, .. } => self.streams.on_stream_data_blocked(id)?,
1111            Frame::StreamsBlocked { bidi, limit } => self.streams.on_streams_blocked(bidi, limit),
1112            Frame::NewToken { token } => {
1113                server_only(self.is_server)?;
1114                self.received_new_token = Some(token.to_vec());
1115            }
1116            Frame::NewConnectionId { seq, retire_prior_to, cid, reset_token } => {
1117                self.on_new_cid(seq, retire_prior_to, cid, reset_token)?
1118            }
1119            Frame::RetireConnectionId { seq } => self.on_retire_cid(seq, dcid)?,
1120            Frame::PathChallenge(d) => {
1121                if self.path_responses.len() < 8 {
1122                    self.path_responses.push_back((d, remote));
1123                }
1124            }
1125            Frame::PathResponse(d) => self.on_path_response(now, d),
1126            Frame::ConnectionClose { code, frame_type, reason } => self.on_peer_close(now, code, frame_type, reason),
1127            Frame::HandshakeDone => {
1128                server_only(self.is_server)?;
1129                if !self.handshake_confirmed {
1130                    self.handshake_confirmed = true;
1131                    self.discard_space(1);
1132                    self.start_mtu_probe();
1133                }
1134            }
1135        }
1136        Ok(())
1137    }
1138
1139    // ---------------------------------------------------------------- crypto
1140
1141    fn on_crypto(&mut self, space: usize, offset: u64, data: &[u8]) -> Result<(), TransportError> {
1142        let cap = self.cfg.transport.crypto_buffer;
1143        let level = Level::ALL[space];
1144        let ci = &mut self.spaces[space].crypto_in;
1145        let end = offset + data.len() as u64;
1146        if end <= ci.read {
1147            // A server that sees the client's ClientHello again during the handshake knows
1148            // the client's PTO fired, so its own flight was most likely lost: resend it now
1149            // rather than wait for its own (backed-off) PTO. Still subject to the
1150            // anti-amplification limit and congestion control.
1151            if self.is_server && space == 0 && !data.is_empty() && !self.handshake_complete {
1152                self.resend_handshake_flight();
1153            }
1154            return Ok(());
1155        }
1156        if offset > ci.read {
1157            // Each buffered chunk is charged its bookkeeping too, so a flood of tiny
1158            // out-of-order frames cannot hold far more memory than the buffer size.
1159            let charge = data.len() + CRYPTO_CHUNK_OVERHEAD;
1160            if end - ci.read > cap as u64 || ci.ooo_bytes + charge > cap {
1161                return Err(TransportError::frame(CRYPTO_BUFFER_EXCEEDED, frame::CRYPTO, "CRYPTO buffer exceeded"));
1162            }
1163            if !ci.ooo.contains_key(&offset) {
1164                ci.ooo_bytes += charge;
1165                ci.ooo.insert(offset, data.to_vec());
1166            }
1167            return Ok(());
1168        }
1169        let skip = (ci.read - offset) as usize;
1170        ci.read = end;
1171        self.feed_handshake(level, &data[skip..])?;
1172        // Deliver buffered chunks that became contiguous.
1173        loop {
1174            let ci = &mut self.spaces[space].crypto_in;
1175            let Some((&o, _)) = ci.ooo.first_key_value() else { break };
1176            if o > ci.read {
1177                break;
1178            }
1179            let chunk = ci.ooo.pop_first().unwrap().1;
1180            ci.ooo_bytes -= chunk.len() + CRYPTO_CHUNK_OVERHEAD;
1181            let e = o + chunk.len() as u64;
1182            if e <= ci.read {
1183                continue;
1184            }
1185            let skip = (ci.read - o) as usize;
1186            ci.read = e;
1187            self.feed_handshake(level, &chunk[skip..])?;
1188        }
1189        self.drive_crypto()
1190    }
1191
1192    /// Hands in-order handshake bytes to TLS. A server with more than one version first
1193    /// collects the whole ClientHello, picks the version from the client's
1194    /// `version_information` (RFC 9368), and only then starts its TLS session in that version.
1195    fn feed_handshake(&mut self, level: Level, data: &[u8]) -> Result<(), TransportError> {
1196        let Some((odcid, retry_scid)) = self.deferred else {
1197            return Ok(self.session.read_handshake(level, data)?);
1198        };
1199        if level != Level::Initial {
1200            return Err(TransportError::new(PROTOCOL_VIOLATION, "handshake data before the ClientHello"));
1201        }
1202        self.hello.extend_from_slice(data);
1203        if self.hello.is_empty() {
1204            return Ok(());
1205        }
1206        // Not a TLS ClientHello (a test crypto provider's handshake): no negotiation.
1207        let tls = self.hello[0] == 1;
1208        let need = if tls { crate::vn::hello_len(&self.hello) } else { Some(0) };
1209        let Some(need) = need else { return Ok(()) };
1210        if need > self.cfg.transport.crypto_buffer {
1211            return Err(TransportError::new(CRYPTO_BUFFER_EXCEEDED, "ClientHello too large"));
1212        }
1213        if self.hello.len() < need {
1214            return Ok(());
1215        }
1216        let client = if tls { crate::vn::client_versions(&self.hello[..need]) } else { None };
1217        let chosen = crate::vn::choose(self.version, &self.cfg.versions, client.as_ref());
1218        if chosen != self.version {
1219            // Continue in the negotiated version: our Initial packets (and the client's from
1220            // now on) use its keys, derived from the same connection ID.
1221            let original = std::mem::replace(&mut self.version, chosen);
1222            let old = self.spaces[0].keys.replace(self.cfg.provider.initial_keys(chosen, &self.initial_dcid, true));
1223            self.orig_initial = old.map(|k| (original, k));
1224        }
1225        self.deferred = None;
1226        let tp = self.local_params(Some(odcid), retry_scid);
1227        self.session = self.cfg.provider.server_session(self.version, tp)?;
1228        let hello = std::mem::take(&mut self.hello);
1229        Ok(self.session.read_handshake(level, &hello)?)
1230    }
1231
1232    /// Pulls handshake output and key changes from the TLS session.
1233    fn drive_crypto(&mut self) -> Result<(), TransportError> {
1234        let mut buf = Vec::new();
1235        loop {
1236            buf.clear();
1237            let change = self.session.write_handshake(&mut buf);
1238            let lvl = self.write_level as usize;
1239            self.spaces[lvl].crypto_out.extend_from_slice(&buf);
1240            match change {
1241                None => break,
1242                Some(KeyChange::Handshake { keys }) => {
1243                    self.spaces[1].keys = Some(keys);
1244                    self.write_level = Level::Handshake;
1245                }
1246                Some(KeyChange::OneRtt { keys, next }) => {
1247                    let Keys { local, remote } = keys;
1248                    self.one_rtt = Some(OneRtt {
1249                        local: local.packet,
1250                        remote: remote.packet,
1251                        local_hp: local.header,
1252                        remote_hp: remote.header,
1253                        secrets: next,
1254                        phase: false,
1255                        next: None,
1256                        prev_remote: None,
1257                        phase_first_sent: 0,
1258                        phase_first_recv: None,
1259                        update_allowed: false,
1260                        sealed: 0,
1261                    });
1262                    self.write_level = Level::OneRtt;
1263                }
1264            }
1265        }
1266        if self.peer_params.is_none() {
1267            if let Some(tp) = self.session.peer_transport_params() {
1268                let p = TransportParams::decode(tp, !self.is_server)?;
1269                self.apply_peer_params(p)?;
1270            }
1271        }
1272        if !self.handshake_complete && !self.session.is_handshaking() {
1273            if self.peer_params.is_none() {
1274                return Err(TransportError::new(TRANSPORT_PARAMETER_ERROR, "missing transport parameters"));
1275            }
1276            self.handshake_complete = true;
1277            self.state = State::Established;
1278            self.events.push_back(Event::Connected);
1279            if self.is_server {
1280                self.handshake_confirmed = true;
1281                self.handshake_done_pending = true;
1282                self.discard_space(1);
1283                if self.cfg.new_token_lifetime.is_some() {
1284                    self.new_token_pending = true;
1285                }
1286                self.start_mtu_probe();
1287            }
1288            self.issue_cids();
1289        }
1290        Ok(())
1291    }
1292
1293    fn apply_peer_params(&mut self, p: TransportParams) -> Result<(), TransportError> {
1294        let err = |r| TransportError::new(TRANSPORT_PARAMETER_ERROR, r);
1295        if p.initial_source_connection_id != self.peer_initial_scid {
1296            return Err(err("initial_source_connection_id mismatch"));
1297        }
1298        if !self.is_server {
1299            if p.original_destination_connection_id != Some(self.orig_dcid) {
1300                return Err(err("original_destination_connection_id mismatch"));
1301            }
1302            if p.retry_source_connection_id != self.retry_scid {
1303                return Err(err("retry_source_connection_id mismatch"));
1304            }
1305            self.remote_cids[0].token = p.stateless_reset_token;
1306            if let Some(t) = p.stateless_reset_token {
1307                self.endpoint_events.push_back(EndpointEvent::ResetToken(t));
1308            }
1309        }
1310        self.streams.set_peer_params(&p);
1311        let peer_idle = Duration::from_millis(p.max_idle_timeout);
1312        let local_idle = self.cfg.transport.max_idle_timeout;
1313        self.idle_timeout = match (local_idle.is_zero(), peer_idle.is_zero()) {
1314            (true, true) => Duration::ZERO,
1315            (true, false) => peer_idle,
1316            (false, true) => local_idle,
1317            (false, false) => local_idle.min(peer_idle),
1318        };
1319        self.recovery.max_ack_delay = Duration::from_millis(p.max_ack_delay);
1320        self.peer_params = Some(p);
1321        Ok(())
1322    }
1323
1324    fn discard_space(&mut self, space: usize) {
1325        let s = &mut self.spaces[space];
1326        if s.discarded {
1327            return;
1328        }
1329        s.discarded = true;
1330        s.keys = None;
1331        if space == 0 {
1332            self.orig_initial = None;
1333        }
1334        let s = &mut self.spaces[space];
1335        s.crypto_out = Vec::new();
1336        s.crypto_retx.clear();
1337        s.ack_now = false;
1338        s.ack_deadline = None;
1339        s.probes = 0;
1340        self.recovery.discard(space);
1341    }
1342
1343    // ---------------------------------------------------------------- connection IDs
1344
1345    fn issue_cids(&mut self) {
1346        let peer_limit = self.peer_params.as_ref().map_or(2, |p| p.active_connection_id_limit);
1347        let want = peer_limit.min(self.cfg.transport.max_local_cids);
1348        while (self.local_cids.iter().filter(|c| !c.retired).count() as u64) < want {
1349            let mut b = [0u8; 20];
1350            self.cfg.provider.fill_random(&mut b[..self.cfg.cid_len]);
1351            let cid = Cid::new(&b[..self.cfg.cid_len]);
1352            let seq = self.next_local_seq;
1353            self.next_local_seq += 1;
1354            self.local_cids.push(LocalCid { seq, cid, retired: false });
1355            self.pending_new_cids.push_back(seq);
1356            self.endpoint_events.push_back(EndpointEvent::NewCid(cid));
1357        }
1358    }
1359
1360    fn on_retire_cid(&mut self, seq: u64, dcid: &Cid) -> Result<(), TransportError> {
1361        if seq >= self.next_local_seq {
1362            return Err(TransportError::frame(PROTOCOL_VIOLATION, frame::RETIRE_CONNECTION_ID, "retired an unissued CID"));
1363        }
1364        let Some(c) = self.local_cids.iter_mut().find(|c| c.seq == seq) else { return Ok(()) };
1365        if c.retired {
1366            return Ok(());
1367        }
1368        if c.cid == *dcid {
1369            return Err(TransportError::frame(
1370                PROTOCOL_VIOLATION,
1371                frame::RETIRE_CONNECTION_ID,
1372                "retired the CID the packet was sent to",
1373            ));
1374        }
1375        c.retired = true;
1376        let cid = c.cid;
1377        self.endpoint_events.push_back(EndpointEvent::RetireCid(cid));
1378        self.local_cids.retain(|c| !c.retired);
1379        self.issue_cids();
1380        Ok(())
1381    }
1382
1383    fn on_new_cid(&mut self, seq: u64, rpt: u64, cid: &[u8], token: [u8; 16]) -> Result<(), TransportError> {
1384        let ty = frame::NEW_CONNECTION_ID;
1385        if self.remote_cids[0].cid.is_empty() {
1386            return Err(TransportError::frame(PROTOCOL_VIOLATION, ty, "NEW_CONNECTION_ID with a zero-length CID"));
1387        }
1388        let cid = Cid::new(cid);
1389        if let Some(c) = self.remote_cids.iter().find(|c| c.seq == seq) {
1390            if c.cid != cid || (c.token.is_some() && c.token != Some(token)) {
1391                return Err(TransportError::frame(PROTOCOL_VIOLATION, ty, "NEW_CONNECTION_ID changed"));
1392            }
1393            return Ok(());
1394        }
1395        if seq < self.retire_prior_to {
1396            // Already retired by an earlier retire_prior_to.
1397            self.queue_retire(seq)?;
1398            return Ok(());
1399        }
1400        self.remote_cids.push(RemoteCid { seq, cid, token: Some(token) });
1401        self.endpoint_events.push_back(EndpointEvent::ResetToken(token));
1402        if rpt > self.retire_prior_to {
1403            self.retire_prior_to = rpt;
1404            let mut i = 0;
1405            while i < self.remote_cids.len() {
1406                if self.remote_cids[i].seq < rpt {
1407                    let c = self.remote_cids.remove(i);
1408                    self.queue_retire(c.seq)?;
1409                } else {
1410                    i += 1;
1411                }
1412            }
1413            if self.remote_cids.is_empty() {
1414                return Err(TransportError::frame(PROTOCOL_VIOLATION, ty, "no connection ID left"));
1415            }
1416            // Element 0 is the one in use; keep the lowest sequence number active.
1417            self.remote_cids.sort_by_key(|c| c.seq);
1418            self.remote_cid_seq = self.remote_cids[0].seq;
1419        }
1420        if self.remote_cids.len() as u64 > self.cfg.transport.active_connection_id_limit {
1421            return Err(TransportError::frame(CONNECTION_ID_LIMIT_ERROR, ty, "too many connection IDs"));
1422        }
1423        Ok(())
1424    }
1425
1426    /// Queues a RETIRE_CONNECTION_ID. Duplicates are dropped, and a peer that makes us queue
1427    /// more retirements than a few times its CID limit is closed with
1428    /// CONNECTION_ID_LIMIT_ERROR (RFC 9000 §5.1.2), so NEW_CONNECTION_ID frames that raise
1429    /// retire_prior_to (or replay old sequence numbers) cannot grow the queue without bound.
1430    fn queue_retire(&mut self, seq: u64) -> Result<(), TransportError> {
1431        if self.pending_retire.contains(&seq) {
1432            return Ok(());
1433        }
1434        let cap = (self.cfg.transport.active_connection_id_limit.max(2) * 8) as usize;
1435        if self.pending_retire.len() >= cap {
1436            return Err(TransportError::frame(
1437                CONNECTION_ID_LIMIT_ERROR,
1438                frame::NEW_CONNECTION_ID,
1439                "too many connection IDs waiting to be retired",
1440            ));
1441        }
1442        self.pending_retire.push_back(seq);
1443        Ok(())
1444    }
1445
1446    /// Switches to an unused destination connection ID and retires the current one.
1447    /// Returns false if none is available.
1448    pub fn rotate_remote_cid(&mut self) -> bool {
1449        if self.remote_cids.len() < 2 {
1450            return false;
1451        }
1452        let old = self.remote_cids.remove(0);
1453        self.pending_retire.push_back(old.seq);
1454        self.remote_cid_seq = self.remote_cids[0].seq;
1455        true
1456    }
1457
1458    // ---------------------------------------------------------------- paths
1459
1460    fn migrate(&mut self, now: Instant, remote: SocketAddr) {
1461        // disable_active_migration does not stop us following a NAT rebinding (RFC 9000 §9).
1462        let mut new = Path::new(remote, false);
1463        // Count the datagram that triggered the migration.
1464        new.recv_bytes = self.stats.recv_bytes.min(MIN_INITIAL_SIZE as u64 * 3);
1465        let old = std::mem::replace(&mut self.path, new);
1466        self.prev_path = Some(old);
1467        self.recovery.cc.reset();
1468        self.rotate_remote_cid();
1469        self.start_challenge(now);
1470    }
1471
1472    fn start_challenge(&mut self, now: Instant) {
1473        let mut d = [0u8; 8];
1474        self.cfg.provider.fill_random(&mut d);
1475        let pto = self.recovery.pto(2);
1476        self.path.challenge = Some((d, now + (pto * 3).max(Duration::from_millis(100))));
1477        self.path.challenge_pending = true;
1478    }
1479
1480    fn on_path_response(&mut self, now: Instant, d: [u8; 8]) {
1481        if let Some((c, _)) = self.path.challenge {
1482            if c == d {
1483                self.path.challenge = None;
1484                self.path.challenge_pending = false;
1485                if !self.path.validated {
1486                    self.path.validated = true;
1487                    self.prev_path = None;
1488                    self.events.push_back(Event::PathMigrated(self.path.remote));
1489                }
1490            }
1491        }
1492        let _ = now;
1493    }
1494
1495    // ---------------------------------------------------------------- acks and loss
1496
1497    fn on_packet_acked(&mut self, space: usize, p: SentPacket) {
1498        if p.mtu_probe_size() > 0 {
1499            self.mds = p.mtu_probe_size();
1500            self.recovery.cc.mds = self.mds as u64;
1501            self.mtu_probe_inflight = false;
1502            self.next_mtu_probe(true);
1503        }
1504        if space == 2 {
1505            if let Some(k) = self.one_rtt.as_mut() {
1506                if p.pn >= k.phase_first_sent {
1507                    k.update_allowed = true;
1508                }
1509            }
1510        }
1511        for f in p.frames {
1512            match f {
1513                SentFrame::Stream { id, off, len, fin } => self.streams.on_stream_acked(id, off, len as u64, fin),
1514                SentFrame::Crypto { off, len } => {
1515                    self.spaces[space].crypto_retx.remove(off, off + len as u64);
1516                }
1517                SentFrame::Control(Control::ResetStream(id)) => self.streams.on_reset_acked(id),
1518                SentFrame::Ack(largest) => {
1519                    // The peer has our ACK up to `largest`: stop reporting older packets.
1520                    let s = &mut self.spaces[space];
1521                    if largest >= s.ack_floor && s.recv.max().is_some_and(|m| m > largest) {
1522                        s.recv.remove_below(largest + 1);
1523                        s.ack_floor = largest + 1;
1524                    }
1525                }
1526                _ => {}
1527            }
1528        }
1529    }
1530
1531    fn on_packets_lost(&mut self, space: usize, lost: Vec<SentPacket>) {
1532        for p in lost {
1533            self.stats.lost_packets += 1;
1534            if p.mtu_probe_size() > 0 {
1535                self.mtu_probe_inflight = false;
1536                self.next_mtu_probe(false);
1537            }
1538            self.requeue(space, &p.frames);
1539        }
1540    }
1541
1542    fn requeue(&mut self, space: usize, frames: &[SentFrame]) {
1543        for &f in frames {
1544            match f {
1545                SentFrame::Stream { id, off, len, fin } => self.streams.on_stream_lost(id, off, len as u64, fin),
1546                SentFrame::Crypto { off, len } => {
1547                    if !self.spaces[space].discarded {
1548                        self.spaces[space].crypto_retx.insert(off, off + len as u64);
1549                    }
1550                }
1551                SentFrame::Control(c) => {
1552                    if !self.streams.control.contains(&c) {
1553                        self.streams.control.push_back(c);
1554                    }
1555                }
1556                SentFrame::NewConnectionId(seq) => {
1557                    if self.local_cids.iter().any(|c| c.seq == seq) && !self.pending_new_cids.contains(&seq) {
1558                        self.pending_new_cids.push_back(seq);
1559                    }
1560                }
1561                SentFrame::RetireConnectionId(seq) => {
1562                    if !self.pending_retire.contains(&seq) {
1563                        self.pending_retire.push_back(seq);
1564                    }
1565                }
1566                SentFrame::HandshakeDone => self.handshake_done_pending = true,
1567                SentFrame::NewToken => self.new_token_pending = true,
1568                SentFrame::Ack(_) | SentFrame::Ping | SentFrame::MtuProbe(_) => {}
1569            }
1570        }
1571    }
1572
1573    fn start_mtu_probe(&mut self) {
1574        if self.cfg.transport.mtu_probing && self.cfg.transport.max_datagram_size > self.mds {
1575            self.next_mtu_probe(true);
1576        }
1577    }
1578
1579    /// Simple PMTU search: try the configured maximum, then the midpoint, each up to 3 times.
1580    fn next_mtu_probe(&mut self, success: bool) {
1581        let peer = self.peer_params.as_ref().map_or(1200, |p| p.max_udp_payload_size) as usize;
1582        let target = self.cfg.transport.max_datagram_size.min(peer);
1583        if target <= self.mds {
1584            self.mtu_probe = None;
1585            return;
1586        }
1587        self.mtu_probe = match self.mtu_probe {
1588            Some((size, tries)) if !success && tries < 2 => Some((size, tries + 1)),
1589            Some((size, _)) if !success => {
1590                let mid = (self.mds + size) / 2;
1591                if mid > self.mds + 20 {
1592                    Some((mid, 0))
1593                } else {
1594                    None
1595                }
1596            }
1597            _ => Some((target, 0)),
1598        };
1599    }
1600
1601    // ---------------------------------------------------------------- timers
1602
1603    /// The next time [`Connection::handle_timeout`] must be called.
1604    pub fn poll_timeout(&self) -> Option<Instant> {
1605        let mut t: Option<Instant> = None;
1606        let mut put = |x: Option<Instant>| {
1607            if let Some(x) = x {
1608                t = Some(t.map_or(x, |y| y.min(x)));
1609            }
1610        };
1611        match self.state {
1612            State::Drained => return None,
1613            State::Closing(u) | State::Draining(u) => return Some(u),
1614            _ => {}
1615        }
1616        if !self.idle_timeout.is_zero() {
1617            let idle = self.idle_timeout.max(self.recovery.pto(2) * 3);
1618            put(Some(self.last_activity + idle));
1619        }
1620        for s in &self.spaces {
1621            put(s.ack_deadline);
1622        }
1623        put(self.loss_timer());
1624        put(self.path.challenge.map(|c| c.1));
1625        if let Some(k) = &self.one_rtt {
1626            put(k.prev_remote.as_ref().and_then(|p| p.1));
1627        }
1628        put(self.pacing_until);
1629        t
1630    }
1631
1632    fn active_spaces(&self) -> [bool; 3] {
1633        [
1634            self.spaces[0].keys.is_some(),
1635            self.spaces[1].keys.is_some(),
1636            self.one_rtt.is_some(),
1637        ]
1638    }
1639
1640    fn loss_timer(&self) -> Option<Instant> {
1641        if let Some((t, _)) = self.recovery.earliest_loss_time() {
1642            return Some(t);
1643        }
1644        if self.is_server && self.path.budget() < MIN_INITIAL_SIZE / 2 {
1645            return None; // Blocked by the anti-amplification limit (RFC 9002 §6.2.2.1).
1646        }
1647        let anti_deadlock = !self.is_server && !self.handshake_complete;
1648        self.recovery
1649            .pto_deadline(self.last_activity, self.active_spaces(), self.handshake_confirmed, anti_deadlock)
1650            .map(|x| x.0)
1651    }
1652
1653    pub fn handle_timeout(&mut self, now: Instant) {
1654        match self.state {
1655            State::Drained => return,
1656            State::Closing(u) | State::Draining(u) => {
1657                if now >= u {
1658                    let err = self.error.clone().unwrap_or(ConnectionError::IdleTimeout);
1659                    self.drain_now(err);
1660                }
1661                return;
1662            }
1663            _ => {}
1664        }
1665        if self.pacing_until.is_some_and(|t| now >= t) {
1666            self.pacing_until = None;
1667        }
1668        if !self.idle_timeout.is_zero() {
1669            let idle = self.idle_timeout.max(self.recovery.pto(2) * 3);
1670            if now >= self.last_activity + idle {
1671                self.drain_now(ConnectionError::IdleTimeout);
1672                return;
1673            }
1674        }
1675        for s in &mut self.spaces {
1676            if s.ack_deadline.is_some_and(|d| now >= d) {
1677                s.ack_deadline = None;
1678                s.ack_now = true;
1679            }
1680        }
1681        if let Some((_, deadline)) = self.path.challenge {
1682            if now >= deadline {
1683                // Validation failed: go back to the previous path if there is one.
1684                self.path.challenge = None;
1685                self.path.challenge_pending = false;
1686                if let Some(prev) = self.prev_path.take() {
1687                    self.path = prev;
1688                }
1689            }
1690        }
1691        if let Some(k) = self.one_rtt.as_mut() {
1692            if k.prev_remote.as_ref().and_then(|p| p.1).is_some_and(|d| now >= d) {
1693                k.prev_remote = None;
1694            }
1695        }
1696        // Loss detection timer (RFC 9002 §6.2, Appendix A.9).
1697        if let Some((t, space)) = self.recovery.earliest_loss_time() {
1698            if now >= t {
1699                let lost = self.recovery.detect_lost(space, now);
1700                self.on_packets_lost(space, lost);
1701            }
1702            return;
1703        }
1704        if let Some(t) = self.loss_timer() {
1705            if now >= t {
1706                self.on_pto(now);
1707            }
1708        }
1709    }
1710
1711    /// Server: queues the unacknowledged Initial and Handshake data again (see `on_crypto`).
1712    fn resend_handshake_flight(&mut self) {
1713        for space in 0..2 {
1714            if self.spaces[space].keys.is_none() || self.spaces[space].discarded {
1715                continue;
1716            }
1717            let frames: Vec<SentFrame> = self.recovery.spaces[space].sent.values().flat_map(|p| p.frames.iter().copied()).collect();
1718            self.requeue(space, &frames);
1719        }
1720    }
1721
1722    fn on_pto(&mut self, _now: Instant) {
1723        let active = self.active_spaces();
1724        let anti_deadlock = !self.is_server && !self.handshake_complete;
1725        let space = match self.recovery.pto_deadline(self.last_activity, active, self.handshake_confirmed, anti_deadlock) {
1726            Some((_, s)) => s,
1727            None => return,
1728        };
1729        self.recovery.pto_count += 1;
1730        // Probe: resend unacknowledged data from the oldest packets (RFC 9002 §6.2.4).
1731        let frames: Vec<SentFrame> = if space < 2 {
1732            self.recovery.spaces[space].sent.values().flat_map(|p| p.frames.iter().copied()).collect()
1733        } else {
1734            self.recovery.spaces[space].sent.values().filter(|p| p.ack_eliciting).take(2).flat_map(|p| p.frames.iter().copied()).collect()
1735        };
1736        self.requeue(space, &frames);
1737        self.spaces[space].probes = 2;
1738        // During the handshake, a client also probes Initial if Handshake has nothing.
1739        if space == 1 && !self.is_server && self.spaces[0].keys.is_some() {
1740            self.spaces[0].probes = 1;
1741        }
1742    }
1743
1744    // ---------------------------------------------------------------- sending
1745
1746    /// Writes up to `max_datagrams` datagrams into `buf` (cleared first).
1747    pub fn poll_transmit(&mut self, now: Instant, buf: &mut Vec<u8>, max_datagrams: usize) -> Option<Transmit> {
1748        buf.clear();
1749        if matches!(self.state, State::Draining(_) | State::Drained) {
1750            return None;
1751        }
1752        self.maybe_auto_key_update();
1753        // PATH_RESPONSEs for other addresses go alone.
1754        if let Some(&(_, addr)) = self.path_responses.front() {
1755            if addr != self.path.remote {
1756                let (d, addr) = self.path_responses.pop_front().unwrap();
1757                if self.build_path_response(now, buf, d, addr) {
1758                    return Some(Transmit { destination: addr, size: buf.len(), segment_size: None });
1759                }
1760                buf.clear();
1761            }
1762        }
1763        let seg = self.mds;
1764        let mut count = 0;
1765        while count < max_datagrams.max(1) {
1766            let before = buf.len();
1767            // A PMTU probe is larger than the segment size, so it only starts a batch.
1768            self.probe_allowed = count == 0;
1769            let built = self.build_datagram(now, buf);
1770            self.probe_allowed = false;
1771            if !built {
1772                break;
1773            }
1774            let n = buf.len() - before;
1775            count += 1;
1776            if n != seg {
1777                break;
1778            }
1779            if let State::Closing(_) = self.state {
1780                break;
1781            }
1782        }
1783        if count == 0 {
1784            return None;
1785        }
1786        let dest = self.path.remote;
1787        Some(Transmit { destination: dest, size: buf.len(), segment_size: if count > 1 { Some(seg) } else { None } })
1788    }
1789
1790    fn maybe_auto_key_update(&mut self) {
1791        let Some(k) = &self.one_rtt else { return };
1792        let limit = match self.cfg.transport.key_update_interval {
1793            Some(n) => n,
1794            None => k.local.confidentiality_limit().saturating_sub(1000),
1795        };
1796        if k.sealed >= limit && k.update_allowed {
1797            self.initiate_key_update();
1798        }
1799    }
1800
1801    fn build_path_response(&mut self, now: Instant, buf: &mut Vec<u8>, d: [u8; 8], addr: SocketAddr) -> bool {
1802        if self.one_rtt.is_none() {
1803            return false;
1804        }
1805        let Some(mut b) = self.begin_packet(buf, 2) else { return false };
1806        frame::put_path(buf, true, &d);
1807        b.eliciting = true;
1808        // Pad to 1200 when the amplification budget for that address allows (RFC 9000 §8.2.1).
1809        let budget = 3 * MIN_INITIAL_SIZE;
1810        let target = MIN_INITIAL_SIZE.min(budget) - self.one_rtt.as_ref().unwrap().local.tag_len();
1811        if buf.len() < target {
1812            buf.resize(target, 0);
1813        }
1814        self.finish_packet(now, buf, b);
1815        let _ = addr;
1816        true
1817    }
1818
1819    /// Room left in the datagram that starts at `dstart` given amplification and size.
1820    fn datagram_limit(&self) -> usize {
1821        let mut limit = self.mds;
1822        if !self.handshake_confirmed {
1823            limit = MIN_INITIAL_SIZE;
1824        }
1825        limit.min(self.path.budget())
1826    }
1827
1828    fn wants_ack(&self, space: usize) -> bool {
1829        let s = &self.spaces[space];
1830        s.ack_now && !s.recv.is_empty()
1831    }
1832
1833    fn space_has_data(&self, space: usize) -> bool {
1834        let s = &self.spaces[space];
1835        if s.has_crypto() || s.probes > 0 {
1836            return true;
1837        }
1838        if space == 2 {
1839            return self.handshake_done_pending
1840                || self.ping_pending
1841                || self.path.challenge_pending
1842                || self.path_responses.front().is_some_and(|x| x.1 == self.path.remote)
1843                || !self.pending_new_cids.is_empty()
1844                || !self.pending_retire.is_empty()
1845                || self.new_token_pending
1846                || !self.streams.control.is_empty()
1847                || self.streams.has_pending_data()
1848                || (self.probe_allowed && self.mtu_probe.is_some() && !self.mtu_probe_inflight && self.recovery.rtt.has_sample);
1849        }
1850        false
1851    }
1852
1853    /// Builds one datagram; returns false if there was nothing to send.
1854    fn build_datagram(&mut self, now: Instant, buf: &mut Vec<u8>) -> bool {
1855        let dstart = buf.len();
1856        let closing = matches!(self.state, State::Closing(_));
1857        if closing {
1858            // Send CONNECTION_CLOSE once, then again only for every few packets received.
1859            let due = self.close_sent_count == 0 || self.close_recv_count >= (1 << self.close_sent_count.min(10));
1860            if !due {
1861                return false;
1862            }
1863            self.close_recv_count = 0;
1864        }
1865        let limit_total = self.datagram_limit();
1866        if limit_total < 64 {
1867            return false;
1868        }
1869        let cwnd_room = self.recovery.cc.available() as usize;
1870        let probing = self.spaces.iter().any(|s| s.probes > 0);
1871        // Pacing.
1872        if self.cfg.transport.pacing && !closing && !probing && self.recovery.rtt.has_sample {
1873            if let Some(t) = self.recovery.pacer.delay(
1874                now,
1875                self.mds as u64,
1876                self.recovery.rtt.smoothed,
1877                self.recovery.cc.cwnd,
1878                self.mds as u64,
1879            ) {
1880                if self.spaces.iter().all(|s| !s.ack_now) {
1881                    self.pacing_until = Some(t);
1882                    return false;
1883                }
1884            }
1885        }
1886        let mut pending: Option<Building> = None;
1887        let mut needs_padding = false;
1888        let mut sent_initial = false;
1889        for space in 0..3 {
1890            let has_keys = if space == 2 { self.one_rtt.is_some() } else { self.spaces[space].keys.is_some() };
1891            if !has_keys {
1892                continue;
1893            }
1894            // Before the handshake completes, a server does not send 1-RTT data other than
1895            // what TLS allows (0.5-RTT); we keep it simple and wait for completion, except
1896            // for closing.
1897            if space == 2 && !self.handshake_complete && !closing {
1898                continue;
1899            }
1900            let ack = self.wants_ack(space);
1901            let data = self.space_has_data(space);
1902            if !(ack || data || (closing && self.close_space_ok(space))) {
1903                continue;
1904            }
1905            // Room for this packet.
1906            let used = buf.len() - dstart;
1907            let tag = self.tag_len(space);
1908            if used + 40 + tag >= limit_total {
1909                break;
1910            }
1911            // Congestion control: ack-only and close packets are not limited, nor is the
1912            // PATH_CHALLENGE that validates a new path (after a migration the bytes still in
1913            // flight on the old path can fill the reset window, and the first packet on the
1914            // new path must carry the challenge, RFC 9000 §9.3).
1915            let cc_limited = !closing && !probing && cwnd_room < self.mds;
1916            let challenge = space == 2 && self.path.challenge_pending;
1917            if cc_limited && !ack && !challenge {
1918                continue;
1919            }
1920            if let Some(p) = pending.take() {
1921                self.finish_packet(now, buf, p);
1922            }
1923            let Some(mut b) = self.begin_packet(buf, space) else { continue };
1924            let limit = dstart + limit_total - tag;
1925            // An ACK-only packet goes out only when an ACK is due; otherwise "data" that
1926            // writes nothing would send ACK-only packets in a loop at one instant.
1927            let ack_due = ack || self.spaces[space].unacked_eliciting > 0;
1928            self.write_frames(now, buf, &mut b, limit, closing, cc_limited);
1929            let ack_only = b.frames.iter().all(|f| matches!(f, SentFrame::Ack(_)));
1930            if !closing && ((b.frames.is_empty() && buf.len() == b.pn_at + b.pn_len) || (ack_only && !ack_due)) {
1931                // Nothing (useful) fit: roll back.
1932                buf.truncate(b.start);
1933                continue;
1934            }
1935            if space == 0 {
1936                sent_initial = true;
1937                if !self.is_server || b.eliciting {
1938                    needs_padding = true;
1939                }
1940            }
1941            if b.mtu_probe {
1942                needs_padding = false;
1943            }
1944            pending = Some(b);
1945            if space == 2 {
1946                break;
1947            }
1948        }
1949        let Some(mut last) = pending else {
1950            return false;
1951        };
1952        let tag = self.tag_len(last.space);
1953        if needs_padding {
1954            let target = dstart + MIN_INITIAL_SIZE.min(limit_total) - tag;
1955            if buf.len() < target {
1956                buf.resize(target, 0);
1957            }
1958        }
1959        if last.mtu_probe {
1960            let size = self.mtu_probe.map_or(self.mds, |m| m.0);
1961            let target = dstart + size - tag;
1962            if buf.len() < target {
1963                buf.resize(target, 0);
1964            }
1965            last.eliciting = true;
1966        }
1967        self.finish_packet(now, buf, last);
1968        if closing {
1969            self.close_sent_count += 1;
1970        }
1971        let n = buf.len() - dstart;
1972        self.path.sent_bytes += n as u64;
1973        self.stats.sent_bytes += n as u64;
1974        // A client discards Initial keys when it first sends a Handshake packet.
1975        if !self.is_server && self.spaces[1].keys.is_some() && !sent_initial && self.spaces[0].keys.is_some() {
1976            let sent_handshake = self.recovery.spaces[1].next_pn > 0;
1977            if sent_handshake {
1978                self.discard_space(0);
1979            }
1980        }
1981        true
1982    }
1983
1984    fn close_space_ok(&self, space: usize) -> bool {
1985        // Send the close in every space we have keys for until the handshake is confirmed.
1986        space == 2 || !self.handshake_confirmed
1987    }
1988
1989    fn tag_len(&self, space: usize) -> usize {
1990        if space == 2 {
1991            self.one_rtt.as_ref().map_or(16, |k| k.local.tag_len())
1992        } else {
1993            self.spaces[space].keys.as_ref().map_or(16, |k| k.local.packet.tag_len())
1994        }
1995    }
1996
1997    fn begin_packet(&mut self, buf: &mut Vec<u8>, space: usize) -> Option<Building> {
1998        let start = buf.len();
1999        let pn = self.recovery.spaces[space].next_pn;
2000        let pn_len = packet::pn_len(pn, self.recovery.spaces[space].largest_acked);
2001        let dcid = self.remote_cids[0].cid;
2002        let (len_at, pn_at) = if space == 2 {
2003            let phase = self.one_rtt.as_ref()?.phase;
2004            (None, packet::put_short_header(buf, false, phase, &dcid, pn, pn_len))
2005        } else {
2006            let ty = if space == 0 { PacketType::Initial } else { PacketType::Handshake };
2007            let token = if space == 0 { Some(&self.token[..]).filter(|_| !self.is_server).or(Some(&[][..])) } else { None };
2008            let scid = self.local_cids[0].cid;
2009            let (l, p) = packet::put_long_header(buf, self.version, ty, &dcid, &scid, token, pn, pn_len);
2010            (Some(l), p)
2011        };
2012        Some(Building { space, start, len_at, pn_at, pn, pn_len, eliciting: false, frames: Vec::new(), mtu_probe: false })
2013    }
2014
2015    fn write_frames(&mut self, now: Instant, buf: &mut Vec<u8>, b: &mut Building, limit: usize, closing: bool, cc_limited: bool) {
2016        let space = b.space;
2017        // ACK first.
2018        if !self.spaces[space].recv.is_empty() && (self.spaces[space].ack_now || self.spaces[space].unacked_eliciting > 0 || closing || !cc_limited) {
2019            let s = &mut self.spaces[space];
2020            let delay = s.largest_recv.map_or(0, |(_, t)| now.saturating_duration_since(t).as_micros() as u64)
2021                >> self.cfg.transport.ack_delay_exponent;
2022            let before = buf.len();
2023            let delay = if space == 2 { delay } else { 0 };
2024            frame::put_ack(buf, &s.recv, delay, self.cfg.transport.max_ack_ranges);
2025            if buf.len() > limit {
2026                buf.truncate(before);
2027            } else {
2028                b.frames.push(SentFrame::Ack(s.recv.max().unwrap()));
2029                s.ack_now = false;
2030                s.ack_deadline = None;
2031                s.unacked_eliciting = 0;
2032            }
2033        }
2034        if closing {
2035            let (code, ft, reason) = self.close.clone().unwrap_or((0, Some(0), Vec::new()));
2036            let reason = &reason[..reason.len().min(limit.saturating_sub(buf.len() + 24))];
2037            if space == 2 {
2038                frame::put_close(buf, code, ft, reason);
2039            } else {
2040                // Application closes are sent as APPLICATION_ERROR before 1-RTT (RFC 9000 §10.2.3).
2041                match ft {
2042                    Some(t) => frame::put_close(buf, code, Some(t), reason),
2043                    None => frame::put_close(buf, APPLICATION_ERROR, Some(0), b""),
2044                }
2045            }
2046            b.frames.push(SentFrame::Ping);
2047            return;
2048        }
2049        // The PATH_CHALLENGE for a new path goes first and is not held back by congestion
2050        // control (see `build_datagram`).
2051        if space == 2 && self.path.challenge_pending && buf.len() + 9 <= limit {
2052            if let Some((d, _)) = self.path.challenge {
2053                frame::put_path(buf, false, &d);
2054                self.path.challenge_pending = false;
2055                b.eliciting = true;
2056                b.frames.push(SentFrame::Ping);
2057            }
2058        }
2059        if cc_limited {
2060            return;
2061        }
2062        if space == 2 {
2063            if self.handshake_done_pending && buf.len() + 1 <= limit {
2064                frame::put_simple(buf, frame::HANDSHAKE_DONE, &[]);
2065                self.handshake_done_pending = false;
2066                b.frames.push(SentFrame::HandshakeDone);
2067                b.eliciting = true;
2068            }
2069            while let Some(&(d, addr)) = self.path_responses.front() {
2070                if addr != self.path.remote || buf.len() + 9 > limit {
2071                    break;
2072                }
2073                frame::put_path(buf, true, &d);
2074                self.path_responses.pop_front();
2075                b.eliciting = true;
2076            }
2077            while let Some(&seq) = self.pending_new_cids.front() {
2078                if buf.len() + 1 + 8 + 8 + 21 + 16 > limit {
2079                    break;
2080                }
2081                self.pending_new_cids.pop_front();
2082                if let Some(c) = self.local_cids.iter().find(|c| c.seq == seq && !c.retired) {
2083                    let token = self.cfg.reset_token(&c.cid);
2084                    frame::put_new_connection_id(buf, seq, 0, &c.cid, &token);
2085                    b.frames.push(SentFrame::NewConnectionId(seq));
2086                    b.eliciting = true;
2087                }
2088            }
2089            while let Some(&seq) = self.pending_retire.front() {
2090                if buf.len() + 9 > limit {
2091                    break;
2092                }
2093                self.pending_retire.pop_front();
2094                frame::put_simple(buf, frame::RETIRE_CONNECTION_ID, &[seq]);
2095                b.frames.push(SentFrame::RetireConnectionId(seq));
2096                b.eliciting = true;
2097            }
2098            if self.new_token_pending && buf.len() + 80 <= limit {
2099                self.new_token_pending = false;
2100                let token = self.new_token.get_or_insert_with(|| {
2101                    crate::token::new_token(&self.cfg, self.path.remote, now)
2102                });
2103                frame::put_new_token(buf, token);
2104                b.frames.push(SentFrame::NewToken);
2105                b.eliciting = true;
2106            }
2107            let mut n = self.streams.control.len();
2108            while n > 0 {
2109                n -= 1;
2110                let Some(c) = self.streams.control.pop_front() else { break };
2111                match self.streams.write_control(c, buf, limit) {
2112                    None => {}
2113                    Some(true) => {
2114                        b.frames.push(SentFrame::Control(c));
2115                        b.eliciting = true;
2116                    }
2117                    Some(false) => {
2118                        self.streams.control.push_front(c);
2119                        break;
2120                    }
2121                }
2122            }
2123        }
2124        // CRYPTO data: retransmissions first.
2125        while buf.len() + 16 < limit {
2126            let s = &mut self.spaces[space];
2127            let room = (limit - buf.len()) as u64;
2128            let (off, len) = if let Some((a, e)) = s.crypto_retx.first() {
2129                let ov = frame::crypto_overhead(a, (e - a) as usize) as u64;
2130                if room <= ov {
2131                    break;
2132                }
2133                let len = (e - a).min(room - ov);
2134                s.crypto_retx.remove(a, a + len);
2135                (a, len)
2136            } else if s.crypto_sent < s.crypto_out.len() as u64 {
2137                let a = s.crypto_sent;
2138                let avail = s.crypto_out.len() as u64 - a;
2139                let ov = frame::crypto_overhead(a, avail as usize) as u64;
2140                if room <= ov {
2141                    break;
2142                }
2143                let len = avail.min(room - ov);
2144                s.crypto_sent += len;
2145                (a, len)
2146            } else {
2147                break;
2148            };
2149            frame::put_crypto(buf, off, &s.crypto_out[off as usize..(off + len) as usize]);
2150            b.frames.push(SentFrame::Crypto { off, len: len as u32 });
2151            b.eliciting = true;
2152        }
2153        if space == 2 {
2154            if self.probe_allowed && self.mtu_probe.is_some() && !self.mtu_probe_inflight && self.recovery.rtt.has_sample {
2155                let size = self.mtu_probe.unwrap().0;
2156                // A probe carries only PING and PADDING, so loss does not lose data.
2157                if b.frames.iter().all(|f| matches!(f, SentFrame::Ack(_))) {
2158                    frame::put_simple(buf, frame::PING, &[]);
2159                    b.frames.push(SentFrame::MtuProbe(size as u16));
2160                    b.mtu_probe = true;
2161                    b.eliciting = true;
2162                    self.mtu_probe_inflight = true;
2163                    return;
2164                }
2165            }
2166            let before = b.frames.len();
2167            self.streams.write_frames(buf, limit, &mut b.frames);
2168            if b.frames.len() > before {
2169                b.eliciting = true;
2170            } else if !self.streams.has_pending_data() && self.recovery.cc.available() > 0 {
2171                self.recovery.app_limited = true;
2172            }
2173            if self.streams.has_pending_data() {
2174                self.recovery.app_limited = false;
2175            }
2176            if !self.raw_frames.is_empty() && buf.len() + self.raw_frames.len() <= limit {
2177                buf.extend_from_slice(&self.raw_frames);
2178                self.raw_frames.clear();
2179                b.frames.push(SentFrame::Ping);
2180                b.eliciting = true;
2181            }
2182            if self.ping_pending && buf.len() < limit {
2183                frame::put_simple(buf, frame::PING, &[]);
2184                self.ping_pending = false;
2185                b.frames.push(SentFrame::Ping);
2186                b.eliciting = true;
2187            }
2188        }
2189        let s = &mut self.spaces[space];
2190        if s.probes > 0 {
2191            s.probes -= 1;
2192            if !b.eliciting && buf.len() < limit {
2193                frame::put_simple(buf, frame::PING, &[]);
2194                b.frames.push(SentFrame::Ping);
2195                b.eliciting = true;
2196            }
2197        }
2198    }
2199
2200    /// Pads, seals and header-protects the packet, then records it.
2201    fn finish_packet(&mut self, now: Instant, buf: &mut Vec<u8>, b: Building) {
2202        let payload_start = b.pn_at + b.pn_len;
2203        // The header protection sample needs 4 bytes after the packet number start.
2204        if buf.len() < b.pn_at + 4 {
2205            buf.resize(b.pn_at + 4, 0);
2206        }
2207        let tag_len = self.tag_len(b.space);
2208        if let Some(len_at) = b.len_at {
2209            let len = buf.len() - b.pn_at + tag_len;
2210            put_varint_fixed(&mut buf[len_at..], len as u64, 2);
2211        }
2212        let end = buf.len();
2213        buf.resize(end + tag_len, 0);
2214        {
2215            let (head, rest) = buf[b.start..].split_at_mut(payload_start - b.start);
2216            let (payload, tag) = rest.split_at_mut(end - payload_start);
2217            if b.space == 2 {
2218                let k = self.one_rtt.as_mut().unwrap();
2219                k.local.seal(b.pn, head, payload, tag);
2220                k.sealed += 1;
2221            } else {
2222                self.spaces[b.space].keys.as_ref().unwrap().local.packet.seal(b.pn, head, payload, tag);
2223            }
2224        }
2225        let hp: &dyn HeaderKey = if b.space == 2 {
2226            &*self.one_rtt.as_ref().unwrap().local_hp
2227        } else {
2228            &*self.spaces[b.space].keys.as_ref().unwrap().local.header
2229        };
2230        packet::protect(buf, b.start, b.pn_at, b.pn_len, hp);
2231        let size = buf.len() - b.start;
2232        let sp = &mut self.recovery.spaces[b.space];
2233        sp.next_pn = b.pn + 1;
2234        if b.space == 2 {
2235            // Skip a 1-RTT packet number now and then, at random, to catch optimistic ACKs
2236            // (RFC 9000 §21.4); on average one in PN_SKIP_PERIOD packets.
2237            if sp.next_pn >= sp.skip_at {
2238                if sp.skip_at != 0 {
2239                    sp.skipped.push_back(sp.next_pn);
2240                    if sp.skipped.len() > 4 {
2241                        sp.skipped.pop_front();
2242                    }
2243                    sp.next_pn += 1;
2244                }
2245                let mut r = [0u8; 2];
2246                self.cfg.provider.fill_random(&mut r);
2247                let jitter = u64::from(u16::from_le_bytes(r)) % PN_SKIP_PERIOD;
2248                sp.skip_at = sp.next_pn + PN_SKIP_PERIOD / 2 + jitter;
2249            }
2250        }
2251        if b.eliciting && !self.eliciting_since_recv {
2252            // The idle timer restarts on the first ack-eliciting packet after receiving.
2253            self.eliciting_since_recv = true;
2254            self.last_activity = now;
2255        }
2256        self.stats.sent_packets += 1;
2257        self.recovery.on_sent(
2258            b.space,
2259            SentPacket {
2260                pn: b.pn,
2261                time: now,
2262                size: size as u16,
2263                ack_eliciting: b.eliciting,
2264                in_flight: b.eliciting,
2265                frames: b.frames,
2266            },
2267        );
2268    }
2269}
2270
2271/// Stands in for the TLS session while the connection builds its transport parameters.
2272struct Placeholder;
2273
2274impl CryptoSession for Placeholder {
2275    fn read_handshake(&mut self, _: Level, _: &[u8]) -> Result<(), crate::crypto::CryptoError> {
2276        Ok(())
2277    }
2278    fn write_handshake(&mut self, _: &mut Vec<u8>) -> Option<KeyChange> {
2279        None
2280    }
2281    fn peer_transport_params(&self) -> Option<&[u8]> {
2282        None
2283    }
2284    fn alpn_protocol(&self) -> Option<&[u8]> {
2285        None
2286    }
2287    fn is_handshaking(&self) -> bool {
2288        true
2289    }
2290}
2291
2292impl SentPacket {
2293    fn mtu_probe_size(&self) -> usize {
2294        self.frames
2295            .iter()
2296            .find_map(|f| if let SentFrame::MtuProbe(s) = f { Some(*s as usize) } else { None })
2297            .unwrap_or(0)
2298    }
2299}
2300
2301#[cfg(test)]
2302mod tests {
2303    use crate::config::Config;
2304    use crate::crypto::null::NullProvider;
2305    use crate::sim::{Link, Pair};
2306    use std::sync::Arc;
2307    use std::time::Duration;
2308
2309    /// Regression (fuzz seed 7000098): a server whose handshake completed without an RTT
2310    /// sample (a client that never ACKs) had a PMTU probe "pending" that could not be built,
2311    /// so every `poll_transmit` at the same instant produced another ACK-only packet: an
2312    /// unbounded loop of datagrams and a busy event loop.
2313    #[test]
2314    fn unbuildable_mtu_probe_does_not_spin_ack_only_packets() {
2315        let cfg = |seed| Arc::new(Config::new(Arc::new(NullProvider::new(seed))));
2316        let mut p = Pair::new(cfg(1), cfg(2), Link::default(), 1);
2317        let c = p.connect();
2318        let ok = p.run_until(Duration::from_secs(30), |p| {
2319            p.client.conn(c).is_some_and(|x| x.is_established()) && p.server_conn().and_then(|s| p.server.conn(s)).is_some_and(|x| x.is_established())
2320        });
2321        assert!(ok);
2322        p.run_for(Duration::from_millis(200));
2323        let s = p.server_conn().unwrap();
2324        let now = p.now;
2325        let conn = p.server.conn_mut(s).unwrap();
2326        conn.recovery.rtt.has_sample = false;
2327        conn.mtu_probe = Some((1400, 0));
2328        conn.mtu_probe_inflight = false;
2329        // Something to acknowledge, so the first packet may be an ACK.
2330        conn.spaces[2].unacked_eliciting = 1;
2331        let mut buf = Vec::new();
2332        let mut sent = 0;
2333        while conn.poll_transmit(now, &mut buf, 1).is_some() {
2334            sent += 1;
2335            assert!(sent < 20, "poll_transmit keeps producing packets at one instant");
2336        }
2337    }
2338
2339    /// Handshake under loss (interop `handshakeloss`): when the client's ClientHello arrives
2340    /// again, the client's PTO fired, so the server's flight was probably lost; the server
2341    /// queues it again at once instead of waiting for its own backed-off PTO.
2342    #[test]
2343    fn duplicate_client_hello_resends_the_server_flight() {
2344        use std::cell::RefCell;
2345        use std::rc::Rc;
2346        let cfg = |seed| Arc::new(Config::new(Arc::new(NullProvider::new(seed))));
2347        let mut p = Pair::new(cfg(5), cfg(6), Link::default(), 5);
2348        // (client datagrams, server datagrams of at least 1200 bytes): everything the server
2349        // sends is dropped, so the client's PTO fires and it resends its ClientHello.
2350        let count: Rc<RefCell<(usize, usize)>> = Rc::default();
2351        let c2 = count.clone();
2352        p.tamper = Some(Box::new(move |to_server, d| {
2353            let mut c = c2.borrow_mut();
2354            if to_server {
2355                c.0 += 1;
2356            } else if d.len() >= 1200 {
2357                c.1 += 1;
2358            }
2359            to_server
2360        }));
2361        p.connect();
2362        p.run_until(Duration::from_millis(50), |p| p.server_conn().is_some());
2363        p.run_for(Duration::from_millis(20));
2364        let s = p.server_conn().expect("server connection");
2365        assert!(count.borrow().1 > 0, "the server sent its flight");
2366        // Push the server's own PTO far away, so only the repeated ClientHello can trigger a
2367        // resend; then let the client's PTO resend its Initial (with a new packet number).
2368        p.server.conn_mut(s).unwrap().recovery.pto_count = 12;
2369        let (clients, flights) = *count.borrow();
2370        let c3 = count.clone();
2371        assert!(p.run_until(Duration::from_secs(5), |_| c3.borrow().0 > clients), "the client resent its Initial");
2372        p.run_for(Duration::from_millis(30));
2373        assert!(count.borrow().1 > flights, "a repeated ClientHello makes the server resend its flight at once");
2374    }
2375
2376    /// The QUIC Interop Runner's rebind cases: after a NAT rebinding the first packet the
2377    /// server sends on the new path must carry PATH_CHALLENGE, even when the bytes still in
2378    /// flight on the old path fill the (reset) congestion window. Before the fix that packet
2379    /// was ACK-only and the challenge waited for the window.
2380    #[test]
2381    fn first_packet_on_a_new_path_carries_the_challenge_when_cwnd_is_full() {
2382        let cfg = |seed| Arc::new(Config::new(Arc::new(NullProvider::new(seed))));
2383        let mut p = Pair::new(cfg(3), cfg(4), Link::default(), 3);
2384        let c = p.connect();
2385        let ok = p.run_until(Duration::from_secs(30), |p| {
2386            p.client.conn(c).is_some_and(|x| x.is_established()) && p.server_conn().and_then(|s| p.server.conn(s)).is_some_and(|x| x.is_established())
2387        });
2388        assert!(ok);
2389        p.run_for(Duration::from_millis(200));
2390        let s = p.server_conn().unwrap();
2391        let now = p.now;
2392        let new: std::net::SocketAddr = "10.0.0.9:6000".parse().unwrap();
2393        let conn = p.server.conn_mut(s).unwrap();
2394        assert!(conn.handshake_confirmed);
2395        conn.migrate(now, new);
2396        // The old path's bytes in flight fill the window; an ACK is due.
2397        conn.recovery.cc.in_flight = conn.recovery.cc.cwnd;
2398        conn.spaces[2].ack_now = true;
2399        let mut buf = Vec::new();
2400        let t = conn.poll_transmit(now, &mut buf, 1).expect("a packet on the new path");
2401        assert_eq!(t.destination, new);
2402        assert!(!conn.path.challenge_pending, "the first packet on the new path carries PATH_CHALLENGE");
2403        let last = conn.recovery.spaces[2].sent.values().last().unwrap();
2404        assert!(last.ack_eliciting, "the packet is not ACK-only");
2405    }
2406}