1use std::{
2 cmp,
3 collections::{BTreeMap, VecDeque, btree_map},
4 convert::TryFrom,
5 fmt, io, mem,
6 net::SocketAddr,
7 num::{NonZeroU32, NonZeroUsize},
8 sync::Arc,
9};
10
11use bytes::{Bytes, BytesMut};
12use frame::StreamMetaVec;
13
14use rand::{RngExt, SeedableRng, rngs::StdRng};
15use rustc_hash::FxHashMap;
16use thiserror::Error;
17use tracing::{debug, error, trace, trace_span, warn};
18
19use crate::{
20 Dir, Duration, EndpointConfig, FourTuple, Frame, INITIAL_MTU, Instant, MAX_CID_SIZE,
21 MAX_STREAM_COUNT, MIN_INITIAL_SIZE, Side, StreamId, TIMER_GRANULARITY, TokenStore, Transmit,
22 TransportError, TransportErrorCode, VarInt,
23 cid_generator::ConnectionIdGenerator,
24 cid_queue::CidQueue,
25 config::{ServerConfig, TransportConfig},
26 congestion::Controller,
27 connection::{
28 paths::PathRetransmits,
29 qlog::{QlogRecvPacket, QlogSink},
30 spaces::LostPacket,
31 stats::PathStatsMap,
32 timer::{ConnTimer, PathTimer},
33 },
34 crypto::{self, Keys},
35 frame::{
36 self, Close, DataBlocked, Datagram, FrameStruct, NewToken, ObservedAddr, StreamDataBlocked,
37 StreamsBlocked,
38 },
39 n0_nat_traversal,
40 packet::{
41 FixedLengthConnectionIdParser, Header, InitialHeader, InitialPacket, LongType, Packet,
42 PacketNumber, PartialDecode, SpaceId,
43 },
44 range_set::ArrayRangeSet,
45 shared::{
46 ConnectionEvent, ConnectionEventInner, ConnectionId, DatagramConnectionEvent, EcnCodepoint,
47 EndpointEvent, EndpointEventInner,
48 },
49 token::{ResetToken, Token, TokenPayload},
50 transport_parameters::TransportParameters,
51};
52
53mod ack_frequency;
54use ack_frequency::AckFrequencyState;
55
56mod assembler;
57pub use assembler::Chunk;
58
59mod cid_state;
60use cid_state::CidState;
61
62mod datagrams;
63use datagrams::DatagramState;
64pub use datagrams::{Datagrams, SendDatagramError};
65
66mod mtud;
67mod pacing;
68
69mod packet_builder;
70use packet_builder::{PacketBuilder, PadDatagram};
71
72mod packet_crypto;
73use packet_crypto::CryptoState;
74pub(crate) use packet_crypto::EncryptionLevel;
75
76mod paths;
77pub use paths::{
78 ClosedPath, PathAbandonReason, PathEvent, PathId, PathStatus, RttEstimator, SetPathStatusError,
79};
80use paths::{PathData, PathState};
81
82pub(crate) mod qlog;
83pub(crate) mod send_buffer;
84
85pub(crate) mod spaces;
86#[cfg(fuzzing)]
87pub use spaces::Retransmits;
88#[cfg(not(fuzzing))]
89use spaces::Retransmits;
90pub(crate) use spaces::SpaceKind;
91use spaces::{OpenStatus, PacketSpace, SendableFrames, SentPacket, ThinRetransmits};
92
93mod stats;
94pub use stats::{ConnectionStats, FrameStats, PathStats, UdpStats};
95
96mod streams;
97#[cfg(fuzzing)]
98pub use streams::StreamsState;
99#[cfg(not(fuzzing))]
100use streams::StreamsState;
101pub use streams::{
102 Chunks, ClosedStream, FinishError, ReadError, ReadableError, RecvStream, SendStream,
103 ShouldTransmit, StreamEvent, Streams, WriteError,
104};
105
106pub(crate) mod timer;
107use timer::{Timer, TimerTable};
108
109mod transmit_buf;
110use transmit_buf::TransmitBuf;
111
112mod state;
113
114#[cfg(not(fuzzing))]
115use state::State;
116#[cfg(fuzzing)]
117pub use state::State;
118use state::StateType;
119
120pub struct Connection {
159 endpoint_config: Arc<EndpointConfig>,
160 config: Arc<TransportConfig>,
161 rng: StdRng,
162 crypto_state: CryptoState,
164 handshake_cid: ConnectionId,
166 remote_handshake_cid: ConnectionId,
168 paths: BTreeMap<PathId, PathState>,
174 path_generation_counter: u64,
185 allow_mtud: bool,
187 state: State,
188 side: ConnectionSide,
189 peer_params: TransportParameters,
191 original_remote_cid: ConnectionId,
193 initial_dst_cid: ConnectionId,
195 retry_src_cid: Option<ConnectionId>,
198 events: VecDeque<Event>,
200 endpoint_events: VecDeque<EndpointEventInner>,
201 spin_enabled: bool,
203 spin: bool,
205 spaces: [PacketSpace; 3],
207 highest_space: SpaceKind,
209 idle_timeout: Option<Duration>,
211 timers: TimerTable,
212 authentication_failures: u64,
214
215 connection_close_pending: bool,
219
220 ack_frequency: AckFrequencyState,
223
224 receiving_ecn: bool,
228 total_authed_packets: u64,
230
231 next_observed_addr_seq_no: VarInt,
235
236 streams: StreamsState,
237 remote_cids: FxHashMap<PathId, CidQueue>,
243 local_cid_state: FxHashMap<PathId, CidState>,
250 datagrams: DatagramState,
252 path_stats: PathStatsMap,
254 partial_stats: ConnectionStats,
260 version: u32,
262
263 max_concurrent_paths: NonZeroU32,
271 local_max_path_id: PathId,
286 remote_max_path_id: PathId,
292 max_path_id_with_cids: PathId,
298 abandoned_paths: AbandonedPaths,
304
305 n0_nat_traversal: n0_nat_traversal::State,
307 qlog: QlogSink,
308}
309
310impl Connection {
311 pub(crate) fn new(
312 endpoint_config: Arc<EndpointConfig>,
313 config: Arc<TransportConfig>,
314 init_cid: ConnectionId,
315 local_cid: ConnectionId,
316 remote_cid: ConnectionId,
317 network_path: FourTuple,
318 crypto: Box<dyn crypto::Session>,
319 cid_gen: &dyn ConnectionIdGenerator,
320 now: Instant,
321 version: u32,
322 allow_mtud: bool,
323 rng_seed: [u8; 32],
324 side_args: SideArgs,
325 qlog: QlogSink,
326 ) -> Self {
327 let pref_addr_cid = side_args.pref_addr_cid();
328 let path_validated = side_args.path_validated();
329 let connection_side = ConnectionSide::from(side_args);
330 let side = connection_side.side();
331 let mut rng = StdRng::from_seed(rng_seed);
332 let mut initial_space = PacketSpace::new(now, SpaceId::Initial, &mut rng);
333 let mut handshake_space = PacketSpace::new(now, SpaceId::Handshake, &mut rng);
334 #[cfg(test)]
335 let mut data_space = match config.deterministic_packet_numbers {
336 true => PacketSpace::new_deterministic(now, SpaceId::Data),
337 false => PacketSpace::new(now, SpaceId::Data, &mut rng),
338 };
339 #[cfg(not(test))]
340 let mut data_space = PacketSpace::new(now, SpaceId::Data, &mut rng);
341
342 initial_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
344 handshake_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
345 data_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
346
347 let state = State::handshake(state::Handshake {
348 remote_cid_set: side.is_server(),
349 expected_token: Bytes::new(),
350 client_hello: None,
351 allow_server_migration: side.is_client() && config.server_handshake_migration,
352 });
353 let local_cid_state = FxHashMap::from_iter([(
354 PathId::ZERO,
355 CidState::new(
356 cid_gen.cid_len(),
357 cid_gen.cid_lifetime(),
358 now,
359 if pref_addr_cid.is_some() { 2 } else { 1 },
360 ),
361 )]);
362
363 let mut this = Self {
364 endpoint_config,
365 crypto_state: CryptoState::new(crypto, init_cid, side, &mut rng),
366 handshake_cid: local_cid,
367 remote_handshake_cid: remote_cid,
368 local_cid_state,
369 paths: BTreeMap::from_iter([(
370 PathId::ZERO,
371 PathState {
372 data: PathData::new(network_path, allow_mtud, None, 0, now, &config),
373 prev: None,
374 },
375 )]),
376 path_generation_counter: 0,
377 allow_mtud,
378 state,
379 side: connection_side,
380 peer_params: TransportParameters::default(),
381 original_remote_cid: remote_cid,
382 initial_dst_cid: init_cid,
383 retry_src_cid: None,
384 events: VecDeque::new(),
385 endpoint_events: VecDeque::new(),
386 spin_enabled: config.allow_spin && rng.random_ratio(7, 8),
387 spin: false,
388 spaces: [initial_space, handshake_space, data_space],
389 highest_space: SpaceKind::Initial,
390 idle_timeout: match config.max_idle_timeout {
391 None | Some(VarInt(0)) => None,
392 Some(dur) => Some(Duration::from_millis(dur.0)),
393 },
394 timers: TimerTable::default(),
395 authentication_failures: 0,
396 connection_close_pending: false,
397
398 ack_frequency: AckFrequencyState::new(get_max_ack_delay(
399 &TransportParameters::default(),
400 )),
401
402 receiving_ecn: false,
403 total_authed_packets: 0,
404
405 next_observed_addr_seq_no: 0u32.into(),
406
407 streams: StreamsState::new(
408 side,
409 config.max_concurrent_uni_streams,
410 config.max_concurrent_bidi_streams,
411 config.send_window,
412 config.receive_window,
413 config.stream_receive_window,
414 ),
415 datagrams: DatagramState::default(),
416 config,
417 remote_cids: FxHashMap::from_iter([(PathId::ZERO, CidQueue::new(remote_cid))]),
418 rng,
419 path_stats: Default::default(),
420 partial_stats: ConnectionStats::default(),
421 version,
422
423 max_concurrent_paths: NonZeroU32::MIN,
425 local_max_path_id: PathId::ZERO,
426 remote_max_path_id: PathId::ZERO,
427 max_path_id_with_cids: PathId::ZERO,
428 abandoned_paths: Default::default(),
429
430 n0_nat_traversal: Default::default(),
431 qlog,
432 };
433 if path_validated {
434 this.on_path_validated(PathId::ZERO);
435 }
436 if side.is_client() {
437 this.write_crypto();
439 this.init_0rtt(now);
440 }
441 this.qlog
442 .emit_tuple_assigned(PathId::ZERO, network_path, now);
443 this
444 }
445
446 #[must_use]
454 pub fn poll_timeout(&self) -> Option<Instant> {
455 self.timers.peek()
456 }
457
458 #[cfg(test)]
463 pub(crate) fn timer_pending(&self, timer: Timer) -> Option<Instant> {
464 self.timers.get(timer)
465 }
466
467 #[must_use]
473 pub fn poll(&mut self) -> Option<Event> {
474 if let Some(x) = self.events.pop_front() {
475 return Some(x);
476 }
477
478 if let Some(event) = self.streams.poll() {
479 return Some(Event::Stream(event));
480 }
481
482 if let Some(reason) = self.state.take_error() {
483 return Some(Event::ConnectionLost { reason });
484 }
485
486 None
487 }
488
489 #[must_use]
491 pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent> {
492 self.endpoint_events.pop_front().map(EndpointEvent)
493 }
494
495 #[must_use]
497 pub fn streams(&mut self) -> Streams<'_> {
498 Streams {
499 state: &mut self.streams,
500 conn_state: &self.state,
501 }
502 }
503
504 #[must_use]
506 pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_> {
507 assert!(id.dir() == Dir::Bi || id.initiator() != self.side.side());
508 RecvStream {
509 id,
510 state: &mut self.streams,
511 pending: &mut self.spaces[SpaceId::Data].pending,
512 }
513 }
514
515 #[must_use]
517 pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_> {
518 assert!(id.dir() == Dir::Bi || id.initiator() == self.side.side());
519 SendStream {
520 id,
521 state: &mut self.streams,
522 pending: &mut self.spaces[SpaceId::Data].pending,
523 conn_state: &self.state,
524 }
525 }
526
527 pub fn open_path_ensure(
544 &mut self,
545 network_path: FourTuple,
546 initial_status: PathStatus,
547 now: Instant,
548 ) -> Result<(PathId, bool), PathError> {
549 let existing_open_path = self.paths.iter().find(|(id, path)| {
550 network_path.is_probably_same_path(&path.data.network_path)
551 && !self.abandoned_paths.contains(id)
552 });
553 match existing_open_path {
554 Some((path_id, _state)) => Ok((*path_id, true)),
555 None => Ok((self.open_path(network_path, initial_status, now)?, false)),
556 }
557 }
558
559 pub fn open_path(
565 &mut self,
566 network_path: FourTuple,
567 initial_status: PathStatus,
568 now: Instant,
569 ) -> Result<PathId, PathError> {
570 let Some(max_path_id) = self.max_path_id() else {
571 return Err(PathError::MultipathNotNegotiated);
572 };
573 if self.side().is_server() {
574 return Err(PathError::ServerSideNotAllowed);
575 }
576
577 let max_abandoned = self.abandoned_paths.max();
578 let max_used = self.paths.keys().last().copied();
579 let path_id = max_abandoned
580 .max(max_used)
581 .unwrap_or(PathId::ZERO)
582 .saturating_add(1u8);
583
584 if path_id > max_path_id {
585 self.spaces[SpaceId::Data].pending.paths_blocked = Some(self.remote_max_path_id);
586 return Err(PathError::MaxPathIdReached);
587 }
588 if !self.remote_cids.contains_key(&path_id) {
589 self.spaces[SpaceId::Data]
590 .pending
591 .path_cids_blocked
592 .insert(path_id, VarInt(0));
593 return Err(PathError::RemoteCidsExhausted);
594 }
595
596 let path = self.create_path(path_id, network_path, now, None);
597 path.status.local_update(initial_status);
598
599 Ok(path_id)
600 }
601
602 pub fn close_path(
608 &mut self,
609 now: Instant,
610 path_id: PathId,
611 error_code: VarInt,
612 ) -> Result<(), ClosePathError> {
613 self.close_path_inner(
614 now,
615 path_id,
616 PathAbandonReason::ApplicationClosed { error_code },
617 )
618 }
619
620 pub(crate) fn close_path_inner(
625 &mut self,
626 now: Instant,
627 path_id: PathId,
628 reason: PathAbandonReason,
629 ) -> Result<(), ClosePathError> {
630 if self.state.is_drained() {
631 return Ok(());
632 }
633
634 if !self.is_multipath_negotiated() {
635 return Err(ClosePathError::MultipathNotNegotiated);
636 }
637 if self.abandoned_paths.contains(&path_id)
638 || Some(path_id) > self.max_path_id()
639 || !self.paths.contains_key(&path_id)
640 {
641 return Err(ClosePathError::ClosedPath);
642 }
643
644 let is_last_path = !self
645 .paths
646 .keys()
647 .any(|id| *id != path_id && !self.abandoned_paths.contains(id));
648
649 if is_last_path && !reason.is_remote() {
650 return Err(ClosePathError::LastOpenPath);
651 }
652
653 self.abandon_path(now, path_id, reason);
654
655 if is_last_path {
659 let rtt = RttEstimator::new(self.config.initial_rtt);
663 let pto = rtt.pto_base() + self.ack_frequency.max_ack_delay_for_pto();
664 let grace = pto * 3;
665 self.timers.set(
666 Timer::Conn(ConnTimer::NoAvailablePath),
667 now + grace,
668 self.qlog.with_time(now),
669 );
670 }
671
672 Ok(())
673 }
674
675 fn abandon_path(&mut self, now: Instant, path_id: PathId, reason: PathAbandonReason) {
680 trace!(%path_id, ?reason, "abandoning path");
681
682 let pending_space = &mut self.spaces[SpaceId::Data].pending;
683 pending_space
685 .path_abandon
686 .insert(path_id, reason.error_code());
687
688 pending_space.new_cids.retain(|cid| cid.path_id != path_id);
690 pending_space.path_status.retain(|&id| id != path_id);
691
692 for space in self.spaces[SpaceId::Data].iter_paths_mut() {
695 for sent_packet in space.sent_packets.values_mut() {
696 if let Some(retransmits) = sent_packet.retransmits.get_mut() {
697 retransmits.new_cids.retain(|cid| cid.path_id != path_id);
698 retransmits.path_status.retain(|&id| id != path_id);
699 }
700 }
701 }
702
703 self.spaces[SpaceId::Data].for_path(path_id).loss_probes = 0;
708
709 debug_assert!(!self.state.is_drained()); self.endpoint_events
714 .push_back(EndpointEventInner::RetireResetToken(path_id));
715
716 self.abandoned_paths.insert(path_id);
717
718 for timer in PathTimer::VALUES {
719 let keep_timer = match timer {
721 PathTimer::PathValidationFailed | PathTimer::PathChallengeLost => false,
725 PathTimer::PathKeepAlive | PathTimer::PathIdle => false,
728 PathTimer::MaxAckDelay => false,
731 PathTimer::PathDrained => false,
734 PathTimer::LossDetection => true,
737 PathTimer::Pacing => true,
741 };
742
743 if !keep_timer {
744 let qlog = self.qlog.with_time(now);
745 self.timers.stop(Timer::PerPath(path_id, timer), qlog);
746 }
747 }
748
749 self.set_loss_detection_timer(now, path_id);
754
755 self.events.push_back(Event::Path(PathEvent::Abandoned {
757 id: path_id,
758 reason,
759 }));
760 }
761
762 #[track_caller]
766 fn path_data(&self, path_id: PathId) -> &PathData {
767 if let Some(data) = self.paths.get(&path_id) {
768 &data.data
769 } else {
770 panic!(
771 "unknown path: {path_id}, currently known paths: {:?}",
772 self.paths.keys().collect::<Vec<_>>()
773 );
774 }
775 }
776
777 #[track_caller]
781 fn path_data_mut(&mut self, path_id: PathId) -> &mut PathData {
782 &mut self.paths.get_mut(&path_id).expect("known path").data
783 }
784
785 fn path(&self, path_id: PathId) -> Option<&PathData> {
787 self.paths.get(&path_id).map(|path_state| &path_state.data)
788 }
789
790 fn path_mut(&mut self, path_id: PathId) -> Option<&mut PathData> {
792 self.paths
793 .get_mut(&path_id)
794 .map(|path_state| &mut path_state.data)
795 }
796
797 pub fn paths(&self) -> Vec<PathId> {
801 self.paths.keys().copied().collect()
802 }
803
804 pub fn path_status(&self, path_id: PathId) -> Result<PathStatus, ClosedPath> {
806 self.path(path_id)
807 .map(PathData::local_status)
808 .ok_or(ClosedPath { _private: () })
809 }
810
811 pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath> {
813 self.path(path_id)
814 .map(|path| path.network_path)
815 .ok_or(ClosedPath { _private: () })
816 }
817
818 pub fn set_path_status(
822 &mut self,
823 path_id: PathId,
824 status: PathStatus,
825 ) -> Result<PathStatus, SetPathStatusError> {
826 if !self.is_multipath_negotiated() {
827 return Err(SetPathStatusError::MultipathNotNegotiated);
828 }
829 let path = self
830 .path_mut(path_id)
831 .ok_or(SetPathStatusError::ClosedPath)?;
832 let prev = match path.status.local_update(status) {
833 Some(prev) => {
834 self.spaces[SpaceId::Data]
835 .pending
836 .path_status
837 .insert(path_id);
838 prev
839 }
840 None => path.local_status(),
841 };
842 Ok(prev)
843 }
844
845 pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus> {
850 self.path(path_id).and_then(|path| path.remote_status())
851 }
852
853 pub fn set_path_max_idle_timeout(
862 &mut self,
863 now: Instant,
864 path_id: PathId,
865 timeout: Option<Duration>,
866 ) -> Result<Option<Duration>, ClosedPath> {
867 let path = self
868 .paths
869 .get_mut(&path_id)
870 .ok_or(ClosedPath { _private: () })?;
871 let prev_timeout = mem::replace(&mut path.data.idle_timeout, timeout);
872
873 self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
881
882 Ok(prev_timeout)
883 }
884
885 fn rearm_path_max_idle_timer(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
893 let timer = Timer::PerPath(path_id, PathTimer::PathIdle);
894
895 if self.state.is_closed() || !self.is_multipath_negotiated() {
896 return self.timers.stop(timer, self.qlog.with_time(now));
897 }
898
899 if let Some(timeout) = self.path_data(path_id).idle_timeout {
900 let dt = cmp::max(timeout, 3 * self.pto(space, path_id));
901 self.timers.set(timer, now + dt, self.qlog.with_time(now));
902 } else {
903 self.timers.stop(timer, self.qlog.with_time(now));
904 }
905 }
906
907 pub fn set_path_keep_alive_interval(
913 &mut self,
914 path_id: PathId,
915 interval: Option<Duration>,
916 ) -> Result<Option<Duration>, ClosedPath> {
917 let path = self
918 .paths
919 .get_mut(&path_id)
920 .ok_or(ClosedPath { _private: () })?;
921 Ok(mem::replace(&mut path.data.keep_alive, interval))
922 }
923
924 fn find_validated_path_on_network_path(
928 &self,
929 network_path: FourTuple,
930 ) -> Option<(&PathId, &PathState)> {
931 self.paths.iter().find(|(path_id, path_state)| {
932 path_state.data.validated
933 && network_path.is_probably_same_path(&path_state.data.network_path)
935 && !self.abandoned_paths.contains(path_id)
936 })
937 }
942
943 fn create_path(
947 &mut self,
948 path_id: PathId,
949 network_path: FourTuple,
950 now: Instant,
951 pn: Option<u64>,
952 ) -> &mut PathData {
953 let valid_path = self.find_validated_path_on_network_path(network_path);
954 let validated = valid_path.is_some();
955 let initial_rtt = valid_path.map(|(_, path)| path.data.rtt.conservative());
956 let vacant_entry = match self.paths.entry(path_id) {
957 btree_map::Entry::Vacant(vacant_entry) => vacant_entry,
958 btree_map::Entry::Occupied(occupied_entry) => {
959 return &mut occupied_entry.into_mut().data;
960 }
961 };
962
963 debug!(%validated, %path_id, %network_path, "path added");
964
965 self.timers.stop(
967 Timer::Conn(ConnTimer::NoAvailablePath),
968 self.qlog.with_time(now),
969 );
970 let peer_max_udp_payload_size =
971 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
972 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
973 let mut data = PathData::new(
974 network_path,
975 self.allow_mtud,
976 Some(peer_max_udp_payload_size),
977 self.path_generation_counter,
978 now,
979 &self.config,
980 );
981
982 data.validated = validated;
983 if let Some(initial_rtt) = initial_rtt {
984 data.rtt.reset_initial_rtt(initial_rtt);
985 }
986
987 data.pending_challenge = true;
990 data.pending.observed_address = self
991 .config
992 .address_discovery_role
993 .should_report(&self.peer_params.address_discovery_role);
994
995 let path = vacant_entry.insert(PathState { data, prev: None });
996
997 let mut pn_space = spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng);
998 if let Some(pn) = pn {
999 pn_space.dedup.insert(pn);
1000 }
1001 self.spaces[SpaceId::Data]
1002 .number_spaces
1003 .insert(path_id, pn_space);
1004 self.qlog.emit_tuple_assigned(path_id, network_path, now);
1005
1006 if !self.remote_cids.contains_key(&path_id) {
1010 debug!(%path_id, "Remote opened path without issuing CIDs");
1011 self.spaces[SpaceId::Data]
1012 .pending
1013 .path_cids_blocked
1014 .insert(path_id, VarInt(0));
1015 }
1018
1019 &mut path.data
1020 }
1021
1022 #[must_use]
1032 pub fn poll_transmit(
1033 &mut self,
1034 now: Instant,
1035 max_datagrams: NonZeroUsize,
1036 buf: &mut Vec<u8>,
1037 ) -> Option<Transmit> {
1038 let max_datagrams = match self.config.enable_segmentation_offload {
1039 false => NonZeroUsize::MIN,
1040 true => max_datagrams,
1041 };
1042
1043 let connection_close_pending = match self.state.as_type() {
1049 StateType::Drained => {
1050 for path in self.paths.values_mut() {
1051 path.data.app_limited = true;
1052 }
1053 return None;
1054 }
1055 StateType::Draining | StateType::Closed => {
1056 if !self.connection_close_pending {
1059 for path in self.paths.values_mut() {
1060 path.data.app_limited = true;
1061 }
1062 return None;
1063 }
1064 true
1065 }
1066 _ => false,
1067 };
1068
1069 if let Some(config) = &self.config.ack_frequency_config {
1071 let rtt = self
1072 .paths
1073 .values()
1074 .map(|p| p.data.rtt.get())
1075 .min()
1076 .expect("one path exists");
1077 self.spaces[SpaceId::Data].pending.ack_frequency = self
1078 .ack_frequency
1079 .should_send_ack_frequency(rtt, config, &self.peer_params)
1080 && self.highest_space == SpaceKind::Data
1081 && self.peer_supports_ack_frequency();
1082 }
1083
1084 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1085 while let Some(path_id) = next_path_id {
1086 if !connection_close_pending
1087 && let Some(transmit) = self.poll_transmit_off_path(now, buf, path_id)
1088 {
1089 #[cfg(test)]
1090 {
1091 self.partial_stats.transmits_tx += 1;
1092 }
1093 return Some(transmit);
1094 }
1095
1096 let info = self.scheduling_info(path_id);
1097 if let Some(transmit) = self.poll_transmit_on_path(
1098 now,
1099 buf,
1100 path_id,
1101 max_datagrams,
1102 &info,
1103 connection_close_pending,
1104 ) {
1105 #[cfg(test)]
1106 {
1107 self.partial_stats.transmits_tx += 1;
1108 }
1109 return Some(transmit);
1110 }
1111
1112 debug_assert!(
1115 buf.is_empty(),
1116 "nothing to send on path but buffer not empty"
1117 );
1118
1119 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1120 }
1121
1122 debug_assert!(
1124 buf.is_empty(),
1125 "there was data in the buffer, but it was not sent"
1126 );
1127
1128 if self.state.is_established() {
1129 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1131 while let Some(path_id) = next_path_id {
1132 if let Some(transmit) = self.poll_transmit_mtu_probe(now, buf, path_id) {
1133 #[cfg(test)]
1134 {
1135 self.partial_stats.transmits_tx += 1;
1136 }
1137 return Some(transmit);
1138 }
1139 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1140 }
1141 }
1142
1143 None
1144 }
1145
1146 fn scheduling_info(&self, path_id: PathId) -> PathSchedulingInfo {
1164 let have_validated_status_available_space = self.paths.iter().any(|(path_id, path)| {
1166 self.remote_cids.contains_key(path_id)
1167 && !self.abandoned_paths.contains(path_id)
1168 && path.data.validated
1169 && path.data.local_status() == PathStatus::Available
1170 });
1171
1172 let have_validated_space = self.paths.iter().any(|(path_id, path)| {
1174 self.remote_cids.contains_key(path_id)
1175 && !self.abandoned_paths.contains(path_id)
1176 && path.data.validated
1177 });
1178
1179 let is_handshaking = self.is_handshaking();
1180 let has_cids = self.remote_cids.contains_key(&path_id);
1181 let is_abandoned = self.abandoned_paths.contains(&path_id);
1182 let path_data = self.path_data(path_id);
1183 let validated = path_data.validated;
1184 let status = path_data.local_status();
1185
1186 let may_send_data = has_cids
1189 && !is_abandoned
1190 && if is_handshaking {
1191 true
1195 } else if !validated {
1196 false
1203 } else {
1204 match status {
1205 PathStatus::Available => {
1206 true
1208 }
1209 PathStatus::Backup => {
1210 !have_validated_status_available_space
1212 }
1213 }
1214 };
1215
1216 let may_send_close = has_cids
1221 && !is_abandoned
1222 && if !validated && have_validated_status_available_space {
1223 false
1225 } else {
1226 true
1228 };
1229
1230 let may_self_abandon = has_cids && validated && !have_validated_space;
1234
1235 PathSchedulingInfo {
1236 is_abandoned,
1237 may_send_data,
1238 may_send_close,
1239 may_self_abandon,
1240 }
1241 }
1242
1243 fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit {
1244 debug_assert!(
1245 !transmit.is_empty(),
1246 "must not be called with an empty transmit buffer"
1247 );
1248
1249 let network_path = self.path_data(path_id).network_path;
1250 trace!(
1251 segment_size = transmit.segment_size(),
1252 last_datagram_len = transmit.len() % transmit.segment_size(),
1253 %network_path,
1254 "sending {} bytes in {} datagrams",
1255 transmit.len(),
1256 transmit.num_datagrams()
1257 );
1258 self.path_data_mut(path_id)
1259 .inc_total_sent(transmit.len() as u64);
1260
1261 self.path_stats
1262 .get_mut(path_id)
1263 .udp_tx
1264 .on_sent(transmit.num_datagrams() as u64, transmit.len());
1265
1266 Transmit {
1267 destination: network_path.remote,
1268 size: transmit.len(),
1269 ecn: if self.path_data(path_id).sending_ecn {
1270 Some(EcnCodepoint::Ect0)
1271 } else {
1272 None
1273 },
1274 segment_size: match transmit.num_datagrams() {
1275 1 => None,
1276 _ => Some(transmit.segment_size()),
1277 },
1278 src_ip: network_path.local_ip,
1279 }
1280 }
1281
1282 fn poll_transmit_off_path(
1284 &mut self,
1285 now: Instant,
1286 buf: &mut Vec<u8>,
1287 path_id: PathId,
1288 ) -> Option<Transmit> {
1289 if let Some(challenge) = self.send_prev_path_challenge(now, buf, path_id) {
1290 return Some(challenge);
1291 }
1292 if let Some(response) = self.send_off_path_path_response(now, buf, path_id) {
1293 return Some(response);
1294 }
1295 if let Some(challenge) = self.send_nat_traversal_path_challenge(now, buf, path_id) {
1296 return Some(challenge);
1297 }
1298 None
1299 }
1300
1301 #[must_use]
1308 fn poll_transmit_on_path(
1309 &mut self,
1310 now: Instant,
1311 buf: &mut Vec<u8>,
1312 path_id: PathId,
1313 max_datagrams: NonZeroUsize,
1314 scheduling_info: &PathSchedulingInfo,
1315 connection_close_pending: bool,
1316 ) -> Option<Transmit> {
1317 let Some(remote_cid) = self.remote_cids.get(&path_id).map(CidQueue::active) else {
1319 if !self.abandoned_paths.contains(&path_id) {
1320 debug!(%path_id, "no remote CIDs for path");
1321 }
1322 return None;
1323 };
1324
1325 let mut pad_datagram = PadDatagram::No;
1331
1332 let mut last_packet_number = None;
1336
1337 let mut send_blocked = false;
1340 let mut cwnd_blocked = false;
1343
1344 let path = self.path_data(path_id);
1345
1346 let controller_metrics = path.congestion.metrics();
1352 let max_datagrams = match controller_metrics.send_quantum {
1353 Some(send_quantum) => {
1354 let datagrams = send_quantum / u64::from(path.current_mtu());
1355 let datagrams = usize::try_from(datagrams).unwrap_or(usize::MAX);
1356 max_datagrams.min(NonZeroUsize::new(datagrams).unwrap_or(NonZeroUsize::MIN))
1357 }
1358 None => max_datagrams,
1359 };
1360
1361 let pmtu = path.current_mtu().into();
1363 let mut transmit = TransmitBuf::new(buf, max_datagrams, pmtu);
1364
1365 for space_id in SpaceId::iter() {
1367 if path_id != PathId::ZERO && space_id != SpaceId::Data {
1369 continue;
1370 }
1371 match self.poll_transmit_path_space(
1372 now,
1373 &mut transmit,
1374 path_id,
1375 space_id,
1376 remote_cid,
1377 scheduling_info,
1378 connection_close_pending,
1379 pad_datagram,
1380 ) {
1381 PollPathSpaceStatus::NothingToSend { path_blocked } => {
1382 match path_blocked {
1385 PathBlocked::No => {}
1386 PathBlocked::AntiAmplification => {
1387 send_blocked = true;
1388 }
1389 PathBlocked::Congestion => {
1390 cwnd_blocked = true;
1391 send_blocked = true;
1392 }
1393 PathBlocked::Pacing => send_blocked = true,
1394 }
1395 }
1396 PollPathSpaceStatus::WrotePacket {
1397 last_packet_number: pn,
1398 pad_datagram: pad,
1399 } => {
1400 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1401 last_packet_number = Some(pn);
1402 pad_datagram = pad;
1403 continue;
1408 }
1409 PollPathSpaceStatus::Send {
1410 last_packet_number: pn,
1411 } => {
1412 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1413 last_packet_number = Some(pn);
1414 break;
1415 }
1416 }
1417 }
1418
1419 if last_packet_number.is_some() || send_blocked {
1420 self.qlog.emit_recovery_metrics(
1421 path_id,
1422 &mut self
1423 .paths
1424 .get_mut(&path_id)
1425 .expect("path_id was iterated from self.paths above")
1426 .data,
1427 now,
1428 );
1429 }
1430
1431 let path = self.path_data_mut(path_id);
1432
1433 path.app_limited = last_packet_number.is_none() && !send_blocked;
1434
1435 if cwnd_blocked {
1436 path.congestion.on_cwnd_limited();
1437 }
1438
1439 match last_packet_number {
1440 Some(last_packet_number) => {
1441 self.path_data_mut(path_id).congestion.on_sent(
1444 now,
1445 transmit.len() as u64,
1446 last_packet_number,
1447 );
1448 Some(self.build_transmit(path_id, transmit))
1449 }
1450 None => None,
1451 }
1452 }
1453
1454 #[must_use]
1456 fn poll_transmit_path_space(
1457 &mut self,
1458 now: Instant,
1459 transmit: &mut TransmitBuf<'_>,
1460 path_id: PathId,
1461 space_id: SpaceId,
1462 remote_cid: ConnectionId,
1463 scheduling_info: &PathSchedulingInfo,
1464 connection_close_pending: bool,
1466 mut pad_datagram: PadDatagram,
1468 ) -> PollPathSpaceStatus {
1469 let mut last_packet_number = None;
1472
1473 loop {
1489 let max_packet_size = if transmit.datagram_remaining_mut() > 0 {
1491 transmit.datagram_remaining_mut()
1493 } else {
1494 transmit.segment_size()
1496 };
1497 let can_send =
1498 self.space_can_send(space_id, path_id, max_packet_size, connection_close_pending);
1499 let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1500 let space_will_send = {
1501 if scheduling_info.is_abandoned {
1502 scheduling_info.may_self_abandon
1507 && self.spaces[space_id]
1508 .pending
1509 .path_abandon
1510 .contains_key(&path_id)
1511 } else if can_send.close && scheduling_info.may_send_close {
1512 true
1514 } else if needs_loss_probe || can_send.space_specific {
1515 true
1518 } else {
1519 !can_send.is_empty() && scheduling_info.may_send_data
1522 }
1523 };
1524
1525 if !space_will_send {
1526 return match last_packet_number {
1529 Some(pn) => PollPathSpaceStatus::WrotePacket {
1530 last_packet_number: pn,
1531 pad_datagram,
1532 },
1533 None => {
1534 if self.crypto_state.has_keys(space_id.encryption_level())
1536 || (space_id == SpaceId::Data
1537 && self.crypto_state.has_keys(EncryptionLevel::ZeroRtt))
1538 {
1539 trace!(?space_id, %path_id, "nothing to send in space");
1540 }
1541 PollPathSpaceStatus::NothingToSend {
1542 path_blocked: PathBlocked::No,
1543 }
1544 }
1545 };
1546 }
1547
1548 if transmit.datagram_remaining_mut() == 0 {
1552 let path_blocked =
1553 self.path_congestion_check(space_id, path_id, transmit, &can_send, now);
1554 if path_blocked != PathBlocked::No {
1555 return match last_packet_number {
1557 Some(pn) => PollPathSpaceStatus::WrotePacket {
1558 last_packet_number: pn,
1559 pad_datagram,
1560 },
1561 None => PollPathSpaceStatus::NothingToSend { path_blocked },
1562 };
1563 }
1564
1565 if transmit.num_datagrams() >= transmit.max_datagrams().get() {
1568 return match last_packet_number {
1571 Some(pn) => PollPathSpaceStatus::WrotePacket {
1572 last_packet_number: pn,
1573 pad_datagram,
1574 },
1575 None => PollPathSpaceStatus::NothingToSend { path_blocked },
1576 };
1577 }
1578
1579 if needs_loss_probe {
1580 let request_immediate_ack =
1582 space_id == SpaceId::Data && self.peer_supports_ack_frequency();
1583 self.spaces[space_id].queue_tail_loss_probe(
1584 path_id,
1585 request_immediate_ack,
1586 &self.streams,
1587 );
1588
1589 self.spaces[space_id].for_path(path_id).loss_probes -= 1; transmit.start_new_datagram_with_size(cmp::min(
1595 usize::from(INITIAL_MTU),
1596 transmit.segment_size(),
1597 ));
1598 } else {
1599 transmit.start_new_datagram();
1600 }
1601 trace!(count = transmit.num_datagrams(), "new datagram started");
1602
1603 pad_datagram = PadDatagram::No;
1605 }
1606
1607 if transmit.datagram_start_offset() < transmit.len() {
1610 debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE);
1611 }
1612
1613 if self.crypto_state.has_keys(EncryptionLevel::Initial)
1618 && space_id == SpaceId::Handshake
1619 && self.side.is_client()
1620 {
1621 self.discard_space(now, SpaceKind::Initial);
1624 }
1625 if let Some(ref mut prev) = self.crypto_state.prev_crypto {
1626 prev.update_unacked = false;
1627 }
1628
1629 let Some(mut builder) =
1630 PacketBuilder::new(now, space_id, path_id, remote_cid, transmit, self)
1631 else {
1632 return PollPathSpaceStatus::NothingToSend {
1639 path_blocked: PathBlocked::No,
1640 };
1641 };
1642 last_packet_number = Some(builder.packet_number);
1643
1644 if space_id == SpaceId::Initial
1645 && (self.side.is_client() || can_send.is_ack_eliciting() || needs_loss_probe)
1646 {
1647 pad_datagram |= PadDatagram::ToMinMtu;
1649 }
1650 if space_id == SpaceId::Data && self.config.pad_to_mtu {
1651 pad_datagram |= PadDatagram::ToSegmentSize;
1652 }
1653
1654 if scheduling_info.may_send_close && can_send.close {
1655 trace!("sending CONNECTION_CLOSE");
1656 let is_multipath_negotiated = self.is_multipath_negotiated();
1661 for path_id in self.spaces[space_id]
1662 .number_spaces
1663 .iter()
1664 .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty())
1665 .map(|(&path_id, _)| path_id)
1666 .collect::<Vec<_>>()
1667 {
1668 Self::populate_acks(
1669 now,
1670 self.receiving_ecn,
1671 path_id,
1672 space_id,
1673 &mut self.spaces[space_id],
1674 is_multipath_negotiated,
1675 &mut builder,
1676 &mut self.path_stats.get_mut(path_id).frame_tx,
1677 self.crypto_state.has_keys(space_id.encryption_level()),
1678 );
1679 }
1680
1681 debug_assert!(
1689 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND,
1690 "ACKs should leave space for ConnectionClose"
1691 );
1692 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
1693 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() {
1694 let max_frame_size = builder.frame_space_remaining();
1695 let close: Close = match self.state.as_type() {
1696 StateType::Closed => {
1697 let reason: Close =
1698 self.state.as_closed().expect("checked").clone().into();
1699 if space_id == SpaceId::Data || reason.is_transport_layer() {
1700 reason
1701 } else {
1702 TransportError::APPLICATION_ERROR("").into()
1703 }
1704 }
1705 StateType::Draining => TransportError::NO_ERROR("").into(),
1706 _ => unreachable!(
1707 "tried to make a close packet when the connection wasn't closed"
1708 ),
1709 };
1710 builder.write_frame(close.encoder(max_frame_size), stats);
1711 }
1712 let last_pn = builder.packet_number;
1713 builder.finish_and_track(now, self, path_id, pad_datagram);
1714 if space_id.kind() == self.highest_space {
1715 self.connection_close_pending = false;
1718 }
1719 return PollPathSpaceStatus::WrotePacket {
1732 last_packet_number: last_pn,
1733 pad_datagram,
1734 };
1735 }
1736
1737 self.populate_packet(now, space_id, path_id, scheduling_info, &mut builder);
1738
1739 debug_assert!(
1746 !(builder.sent_frames().is_ack_only(&self.streams)
1747 && !can_send.acks
1748 && (can_send.other || can_send.space_specific)
1749 && builder.buf.segment_size()
1750 == self.path_data(path_id).current_mtu() as usize
1751 && self.datagrams.outgoing.is_empty()),
1752 "SendableFrames was {can_send:?}, but only ACKs have been written"
1753 );
1754 if builder.sent_frames().requires_padding {
1755 pad_datagram |= PadDatagram::ToMinMtu;
1756 }
1757
1758 for path_id in builder.sent_frames().largest_acked.keys() {
1759 self.spaces[space_id]
1760 .for_path(*path_id)
1761 .pending_acks
1762 .acks_sent();
1763 self.timers.stop(
1764 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
1765 self.qlog.with_time(now),
1766 );
1767 }
1768
1769 let max_packet_size = builder
1775 .buf
1776 .datagram_remaining_mut()
1777 .saturating_sub(builder.predict_packet_end());
1778 if builder.can_coalesce
1781 && path_id == PathId::ZERO
1782 && let Some(next_space_id) = space_id.next()
1783 && max_packet_size > MIN_PACKET_SPACE
1784 && self
1785 .space_can_send(space_id, path_id, max_packet_size, connection_close_pending)
1786 .is_empty()
1787 && self.has_pending_packet(next_space_id, max_packet_size, connection_close_pending)
1788 {
1789 trace!("will coalesce with next packet");
1792 let last_pn = builder.packet_number;
1793 builder.finish_and_track(now, self, path_id, PadDatagram::No);
1794 return PollPathSpaceStatus::WrotePacket {
1797 last_packet_number: last_pn,
1798 pad_datagram,
1799 };
1800 } else {
1801 if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) {
1807 const MAX_PADDING: usize = 32;
1815 if builder.buf.datagram_remaining_mut()
1816 > builder.predict_packet_end() + MAX_PADDING
1817 {
1818 trace!(
1819 "GSO truncated by demand for {} padding bytes",
1820 builder.buf.datagram_remaining_mut() - builder.predict_packet_end()
1821 );
1822 let last_pn = builder.packet_number;
1823 builder.finish_and_track(now, self, path_id, PadDatagram::No);
1824 return PollPathSpaceStatus::Send {
1825 last_packet_number: last_pn,
1826 };
1827 }
1828
1829 builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize);
1832 } else {
1833 builder.finish_and_track(now, self, path_id, pad_datagram);
1834 }
1835
1836 if transmit.num_datagrams() == 1 {
1839 transmit.clip_segment_size();
1840 }
1841 }
1842 }
1843 }
1844
1845 fn poll_transmit_mtu_probe(
1846 &mut self,
1847 now: Instant,
1848 buf: &mut Vec<u8>,
1849 path_id: PathId,
1850 ) -> Option<Transmit> {
1851 let (active_cid, probe_size) = self.get_mtu_probe_data(now, path_id)?;
1852
1853 let mut transmit = TransmitBuf::new(buf, NonZeroUsize::MIN, probe_size as usize);
1855 transmit.start_new_datagram_with_size(probe_size as usize);
1856
1857 let mut builder =
1858 PacketBuilder::new(now, SpaceId::Data, path_id, active_cid, &mut transmit, self)?;
1859
1860 trace!(?probe_size, "writing MTUD probe");
1862 builder.write_frame(frame::Ping, &mut self.path_stats.get_mut(path_id).frame_tx);
1863
1864 if self.peer_supports_ack_frequency() {
1866 builder.write_frame(
1867 frame::ImmediateAck,
1868 &mut self.path_stats.get_mut(path_id).frame_tx,
1869 );
1870 }
1871
1872 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size));
1873
1874 Some(self.build_transmit(path_id, transmit))
1875 }
1876
1877 fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> {
1885 let active_cid = self.remote_cids.get(&path_id).map(CidQueue::active)?;
1886 let is_eligible = self.path_data(path_id).validated
1887 && !self.path_data(path_id).is_validating_path()
1888 && !self.abandoned_paths.contains(&path_id);
1889
1890 if !is_eligible {
1891 return None;
1892 }
1893 let next_pn = self.spaces[SpaceId::Data]
1894 .for_path(path_id)
1895 .peek_tx_number();
1896 let probe_size = self
1897 .path_data_mut(path_id)
1898 .mtud
1899 .poll_transmit(now, next_pn)?;
1900
1901 Some((active_cid, probe_size))
1902 }
1903
1904 fn has_pending_packet(
1921 &mut self,
1922 current_space_id: SpaceId,
1923 max_packet_size: usize,
1924 connection_close_pending: bool,
1925 ) -> bool {
1926 let mut space_id = current_space_id;
1927 loop {
1928 let can_send = self.space_can_send(
1929 space_id,
1930 PathId::ZERO,
1931 max_packet_size,
1932 connection_close_pending,
1933 );
1934 if !can_send.is_empty() {
1935 return true;
1936 }
1937 match space_id.next() {
1938 Some(next_space_id) => space_id = next_space_id,
1939 None => break,
1940 }
1941 }
1942 false
1943 }
1944
1945 fn path_congestion_check(
1947 &mut self,
1948 space_id: SpaceId,
1949 path_id: PathId,
1950 transmit: &TransmitBuf<'_>,
1951 can_send: &SendableFrames,
1952 now: Instant,
1953 ) -> PathBlocked {
1954 if self.side().is_server()
1960 && self
1961 .path_data(path_id)
1962 .anti_amplification_blocked(transmit.len() as u64 + 1)
1963 {
1964 trace!(?space_id, %path_id, "blocked by anti-amplification");
1965 return PathBlocked::AntiAmplification;
1966 }
1967
1968 let bytes_to_send = transmit.segment_size() as u64;
1971 let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1972
1973 if can_send.other && !need_loss_probe && !can_send.close {
1974 let path = self.path_data(path_id);
1975 if path.in_flight.bytes + bytes_to_send >= path.congestion.window() {
1976 trace!(
1977 ?space_id,
1978 %path_id,
1979 in_flight=%path.in_flight.bytes,
1980 congestion_window=%path.congestion.window(),
1981 "blocked by congestion control",
1982 );
1983 return PathBlocked::Congestion;
1984 }
1985 }
1986
1987 if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) {
1989 let resume_time = now + delay;
1990 self.timers.set(
1991 Timer::PerPath(path_id, PathTimer::Pacing),
1992 resume_time,
1993 self.qlog.with_time(now),
1994 );
1995 trace!(?space_id, %path_id, ?delay, "blocked by pacing");
1998 return PathBlocked::Pacing;
1999 }
2000
2001 PathBlocked::No
2002 }
2003
2004 fn send_prev_path_challenge(
2009 &mut self,
2010 now: Instant,
2011 buf: &mut Vec<u8>,
2012 path_id: PathId,
2013 ) -> Option<Transmit> {
2014 let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?;
2015 if !prev_path.pending_challenge {
2016 return None;
2017 };
2018 prev_path.pending_challenge = false;
2019 let token = self.rng.random();
2020 let network_path = prev_path.network_path;
2021 prev_path.record_path_challenge_sent(now, token, network_path);
2022
2023 debug_assert_eq!(
2024 self.highest_space,
2025 SpaceKind::Data,
2026 "PATH_CHALLENGE queued without 1-RTT keys"
2027 );
2028 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2029 buf.start_new_datagram();
2030
2031 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, self)?;
2037 let challenge = frame::PathChallenge(token);
2038 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2039 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path"));
2040
2041 builder.pad_to(MIN_INITIAL_SIZE);
2046
2047 builder.finish(self, now);
2048 self.path_stats
2049 .get_mut(path_id)
2050 .udp_tx
2051 .on_sent(1, buf.len());
2052
2053 trace!(
2054 dst = ?network_path.remote,
2055 src = ?network_path.local_ip,
2056 len = buf.len(),
2057 "sending prev_path off-path challenge",
2058 );
2059 Some(Transmit {
2060 destination: network_path.remote,
2061 size: buf.len(),
2062 ecn: None,
2063 segment_size: None,
2064 src_ip: network_path.local_ip,
2065 })
2066 }
2067
2068 fn send_off_path_path_response(
2069 &mut self,
2070 now: Instant,
2071 buf: &mut Vec<u8>,
2072 path_id: PathId,
2073 ) -> Option<Transmit> {
2074 let network_path = self
2075 .paths
2076 .get_mut(&path_id)
2077 .map(|state| state.data.network_path)?;
2078 let cid_queue = self.remote_cids.get_mut(&path_id)?;
2079 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
2080 let (token, network_path) = pns.pending_path_responses.pop_off_path(network_path)?;
2081
2082 let cid = cid_queue.active();
2084
2085 let frame = frame::PathResponse(token);
2087
2088 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2089 buf.start_new_datagram();
2090
2091 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, buf, self)?;
2092 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2093 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)"));
2094
2095 if self
2102 .find_validated_path_on_network_path(network_path)
2103 .is_none()
2104 && self.n0_nat_traversal.client_side().is_ok()
2105 {
2106 let token = self.rng.random();
2107 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2108 builder.write_frame(frame::PathChallenge(token), stats);
2109 let ip_port = (network_path.remote.ip(), network_path.remote.port());
2110 self.n0_nat_traversal.mark_probe_sent(ip_port, token);
2111 }
2112
2113 builder.pad_to(MIN_INITIAL_SIZE);
2116 builder.finish(self, now);
2117
2118 let size = buf.len();
2119 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2120
2121 trace!(
2122 dst = ?network_path.remote,
2123 src = ?network_path.local_ip,
2124 len = buf.len(),
2125 "sending off-path PATH_RESPONSE",
2126 );
2127 Some(Transmit {
2128 destination: network_path.remote,
2129 size,
2130 ecn: None,
2131 segment_size: None,
2132 src_ip: network_path.local_ip,
2133 })
2134 }
2135
2136 fn send_nat_traversal_path_challenge(
2138 &mut self,
2139 now: Instant,
2140 buf: &mut Vec<u8>,
2141 path_id: PathId,
2142 ) -> Option<Transmit> {
2143 let remote = self.n0_nat_traversal.next_probe_addr()?;
2144
2145 if !self.paths.get(&path_id)?.data.validated {
2146 return None;
2148 }
2149
2150 let Some(cid) = self
2155 .remote_cids
2156 .get(&path_id)
2157 .map(|cid_queue| cid_queue.active())
2158 else {
2159 trace!(%path_id, "Not sending NAT traversal probe for path with no CIDs");
2160 return None;
2161 };
2162 let token = self.rng.random();
2163
2164 let frame = frame::PathChallenge(token);
2166
2167 let mut buf = TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2168 buf.start_new_datagram();
2169
2170 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, &mut buf, self)?;
2171 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2172 builder.write_frame_with_log_msg(frame, stats, Some("(nat-traversal)"));
2173 builder.finish(self, now);
2176
2177 self.n0_nat_traversal.mark_probe_sent(remote, token);
2179
2180 let size = buf.len();
2181 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2182
2183 trace!(dst = ?remote, len = buf.len(), "sending off-path NAT probe");
2184 Some(Transmit {
2185 destination: remote.into(),
2186 size,
2187 ecn: None,
2188 segment_size: None,
2189 src_ip: None,
2190 })
2191 }
2192
2193 fn space_can_send(
2201 &mut self,
2202 space_id: SpaceId,
2203 path_id: PathId,
2204 packet_size: usize,
2205 connection_close_pending: bool,
2206 ) -> SendableFrames {
2207 let space = &mut self.spaces[space_id];
2208 let space_has_crypto = self.crypto_state.has_keys(space_id.encryption_level());
2209
2210 if !space_has_crypto
2211 && (space_id != SpaceId::Data
2212 || !self.crypto_state.has_keys(EncryptionLevel::ZeroRtt)
2213 || self.side.is_server())
2214 {
2215 return SendableFrames::empty();
2217 }
2218
2219 let mut can_send = space.can_send(path_id, &self.streams);
2220
2221 if space_id == SpaceId::Data {
2223 let pn = space.for_path(path_id).peek_tx_number();
2224 let frame_space_1rtt =
2230 packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id));
2231 can_send |= self.can_send_1rtt(path_id, frame_space_1rtt);
2232 }
2233
2234 can_send.close = connection_close_pending && space_has_crypto;
2235
2236 can_send
2237 }
2238
2239 pub fn handle_event(&mut self, event: ConnectionEvent) {
2245 use ConnectionEventInner::*;
2246 match event.0 {
2247 Datagram(DatagramConnectionEvent {
2248 now,
2249 network_path,
2250 path_id,
2251 ecn,
2252 first_decode,
2253 remaining,
2254 }) => {
2255 let span = trace_span!("pkt", %path_id);
2256 let _guard = span.enter();
2257
2258 if self.early_discard_packet(network_path, path_id) {
2259 return;
2261 }
2262
2263 let was_anti_amplification_blocked = self
2264 .path(path_id)
2265 .map(|path| path.anti_amplification_blocked(1))
2266 .unwrap_or(false);
2269
2270 let rx = &mut self.path_stats.get_mut(path_id).udp_rx;
2271 rx.datagrams += 1;
2272 rx.bytes += first_decode.len() as u64;
2273 let data_len = first_decode.len();
2274
2275 self.handle_decode(now, network_path, path_id, ecn, first_decode);
2276 if let Some(path) = self.path_mut(path_id) {
2281 path.inc_total_recvd(data_len as u64);
2282 }
2283
2284 if let Some(data) = remaining {
2285 self.path_stats.get_mut(path_id).udp_rx.bytes += data.len() as u64;
2286 self.handle_coalesced(now, network_path, path_id, ecn, data);
2287 }
2288
2289 if let Some(path) = self.paths.get_mut(&path_id) {
2290 self.qlog
2291 .emit_recovery_metrics(path_id, &mut path.data, now);
2292 }
2293
2294 if was_anti_amplification_blocked {
2295 self.set_loss_detection_timer(now, path_id);
2299 }
2300 }
2301 NewIdentifiers(ids, now, cid_len, cid_lifetime) => {
2302 let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default();
2303 debug_assert!(ids.iter().all(|issued| issued.path_id == path_id));
2304
2305 if self.abandoned_paths.contains(&path_id) {
2308 if !self.state.is_drained() {
2309 for issued in &ids {
2310 self.endpoint_events
2311 .push_back(EndpointEventInner::RetireConnectionId(
2312 now,
2313 path_id,
2314 issued.sequence,
2315 false,
2316 ));
2317 }
2318 }
2319 return;
2320 }
2321
2322 let cid_state = self
2323 .local_cid_state
2324 .entry(path_id)
2325 .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0));
2326 cid_state.new_cids(&ids, now);
2327
2328 ids.into_iter().rev().for_each(|frame| {
2329 self.spaces[SpaceId::Data].pending.new_cids.push(frame);
2330 });
2331 self.reset_cid_retirement(now);
2333 }
2334 }
2335 }
2336
2337 fn early_discard_packet(&mut self, network_path: FourTuple, path_id: PathId) -> bool {
2345 if self.is_handshaking() && path_id != PathId::ZERO {
2346 debug!(%network_path, %path_id, "discarding multipath packet during handshake");
2347 return true;
2348 }
2349
2350 if !self.paths.contains_key(&path_id) && self.abandoned_paths.contains(&path_id) {
2351 trace!(%path_id, "discarding packet for discarded path");
2352 return true;
2353 }
2354
2355 let peer_may_probe = self.peer_may_probe();
2356 let local_ip_may_migrate = self.local_ip_may_migrate();
2357
2358 if let Some(known_path) = self.path_mut(path_id) {
2362 if network_path.remote != known_path.network_path.remote && !peer_may_probe {
2363 trace!(
2364 %path_id,
2365 %network_path,
2366 %known_path.network_path,
2367 "discarding packet from unrecognized peer"
2368 );
2369 return true;
2370 }
2371
2372 if known_path.network_path.local_ip.is_some()
2373 && network_path.local_ip.is_some()
2374 && known_path.network_path.local_ip != network_path.local_ip
2375 && !local_ip_may_migrate
2376 {
2377 trace!(
2378 %path_id,
2379 %network_path,
2380 %known_path.network_path,
2381 "discarding packet sent to incorrect interface"
2382 );
2383 return true;
2384 }
2385 }
2386 false
2387 }
2388
2389 fn peer_may_probe(&self) -> bool {
2400 match &self.side {
2401 ConnectionSide::Client { .. } => {
2402 if let Some(hs) = self.state.as_handshake() {
2403 hs.allow_server_migration
2404 } else {
2405 self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed()
2406 }
2407 }
2408 ConnectionSide::Server { server_config } => {
2409 self.is_handshake_confirmed()
2410 && (server_config.migration || self.n0_nat_traversal.is_negotiated())
2411 }
2412 }
2413 }
2414
2415 fn peer_may_migrate(&self) -> bool {
2427 match &self.side {
2428 ConnectionSide::Server { server_config } => {
2429 server_config.migration && self.is_handshake_confirmed()
2430 }
2431 ConnectionSide::Client { .. } => false,
2432 }
2433 }
2434
2435 fn local_ip_may_migrate(&self) -> bool {
2448 (self.side.is_client() || self.n0_nat_traversal.is_negotiated())
2449 && self.is_handshake_confirmed()
2450 }
2451 pub fn handle_timeout(&mut self, now: Instant) {
2461 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) {
2462 let span = match timer {
2463 Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer),
2464 Timer::PerPath(path_id, timer) => {
2465 trace_span!("timer_fired", scope="path", %path_id, ?timer)
2466 }
2467 };
2468 let _guard = span.enter();
2469 trace!("timeout");
2470 match timer {
2471 Timer::Conn(timer) => match timer {
2472 ConnTimer::Close => {
2473 self.state.move_to_drained(None, &mut self.endpoint_events);
2474 }
2475 ConnTimer::Idle => {
2476 self.kill(ConnectionError::TimedOut);
2477 }
2478 ConnTimer::KeepAlive => {
2479 self.ping();
2480 }
2481 ConnTimer::KeyDiscard => {
2482 self.crypto_state.discard_temporary_keys();
2483 }
2484 ConnTimer::PushNewCid => {
2485 while let Some((path_id, when)) = self.next_cid_retirement() {
2486 if when > now {
2487 break;
2488 }
2489 match self.local_cid_state.get_mut(&path_id) {
2490 None => error!(%path_id, "No local CID state for path"),
2491 Some(cid_state) => {
2492 let num_new_cid = cid_state.on_cid_timeout().into();
2494 if !self.state.is_closed() {
2495 trace!(
2496 "push a new CID to peer RETIRE_PRIOR_TO field {}",
2497 cid_state.retire_prior_to()
2498 );
2499 self.endpoint_events.push_back(
2500 EndpointEventInner::NeedIdentifiers(
2501 path_id,
2502 now,
2503 num_new_cid,
2504 ),
2505 );
2506 }
2507 }
2508 }
2509 }
2510 }
2511 ConnTimer::NoAvailablePath => {
2512 if self.state.is_closed() || self.state.is_drained() {
2517 error!("no viable path timer fired, but connection already closing");
2520 } else {
2521 trace!("no viable path grace period expired, closing connection");
2522 let err = TransportError::NO_VIABLE_PATH(
2523 "last path abandoned, no new path opened",
2524 );
2525 self.close_common();
2526 self.set_close_timer(now);
2527 self.connection_close_pending = true;
2528 self.state.move_to_closed(err);
2529 }
2530 }
2531 ConnTimer::NatTraversalProbeRetry => {
2532 self.n0_nat_traversal.queue_retries(self.is_ipv6());
2533 if let Some(delay) =
2534 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
2535 {
2536 self.timers.set(
2537 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
2538 now + delay,
2539 self.qlog.with_time(now),
2540 );
2541 trace!("re-queued NAT probes");
2542 } else {
2543 trace!("no more NAT probes remaining");
2544 }
2545 }
2546 },
2547 Timer::PerPath(path_id, timer) => {
2548 match timer {
2549 PathTimer::PathIdle => {
2550 if let Err(err) =
2551 self.close_path_inner(now, path_id, PathAbandonReason::TimedOut)
2552 {
2553 warn!(?err, "failed closing path");
2554 }
2555 }
2556
2557 PathTimer::PathKeepAlive => {
2558 self.ping_path(path_id).ok();
2559 }
2560 PathTimer::LossDetection => {
2561 self.on_loss_detection_timeout(now, path_id);
2562 if let Some(path) = self.paths.get_mut(&path_id) {
2563 self.qlog
2564 .emit_recovery_metrics(path_id, &mut path.data, now);
2565 } else {
2566 error!("LossDetection fired for unknown path");
2567 }
2568 }
2569 PathTimer::PathValidationFailed => {
2570 let Some(path) = self.paths.get_mut(&path_id) else {
2571 continue;
2572 };
2573 self.timers.stop(
2574 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2575 self.qlog.with_time(now),
2576 );
2577 debug!("path migration validation failed");
2578 path.data.reset_on_path_challenges();
2579 if let Some((_, prev)) = path.prev.take() {
2580 path.data = prev;
2581 self.set_loss_detection_timer(now, path_id);
2582 }
2583 }
2584 PathTimer::PathChallengeLost => {
2585 let Some(path) = self.paths.get_mut(&path_id) else {
2586 continue;
2587 };
2588 trace!(?path.data.lost_challenge_count, "path challenge deemed lost");
2589 path.data.pending_challenge = true;
2590 path.data.lost_challenge_count += 1;
2591 self.timers.set(
2592 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2593 now + path.data.on_path_challenge_pto(),
2594 self.qlog.with_time(now),
2595 );
2596 }
2597 PathTimer::Pacing => {}
2598 PathTimer::MaxAckDelay => {
2599 self.spaces[SpaceId::Data]
2601 .for_path(path_id)
2602 .pending_acks
2603 .on_max_ack_delay_timeout()
2604 }
2605 PathTimer::PathDrained => {
2606 self.timers.stop_per_path(path_id, self.qlog.with_time(now));
2609 if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) {
2610 debug_assert!(!self.state.is_drained()); let (min_seq, max_seq) = local_cid_state.active_seq();
2612 for seq in min_seq..=max_seq {
2613 self.endpoint_events.push_back(
2614 EndpointEventInner::RetireConnectionId(
2615 now, path_id, seq, false,
2616 ),
2617 );
2618 }
2619 }
2620 self.discard_path(path_id, now);
2621 }
2622 }
2623 }
2624 }
2625 }
2626 }
2627
2628 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) {
2640 self.close_inner(
2641 now,
2642 Close::Application(frame::ApplicationClose { error_code, reason }),
2643 )
2644 }
2645
2646 fn close_inner(&mut self, now: Instant, reason: Close) {
2662 let was_closed = self.state.is_closed();
2663 if !was_closed {
2664 self.close_common();
2665 self.set_close_timer(now);
2666 self.connection_close_pending = true;
2667 self.state.move_to_closed_local(reason);
2668 }
2669 }
2670
2671 pub fn datagrams(&mut self) -> Datagrams<'_> {
2673 Datagrams { conn: self }
2674 }
2675
2676 pub fn stats(&mut self) -> ConnectionStats {
2678 let mut stats = self.partial_stats.clone();
2679
2680 for path_stats in self.path_stats.iter_stats() {
2681 stats += *path_stats;
2686 }
2687
2688 stats
2689 }
2690
2691 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> {
2693 let path = self.paths.get(&path_id)?;
2694 let mut stats = self.path_stats.get(path_id).unwrap_or_default();
2695 stats.rtt = path.data.rtt.get();
2696 stats.cwnd = path.data.congestion.window();
2697 stats.current_mtu = path.data.mtud.current_mtu();
2698 Some(stats)
2699 }
2700
2701 pub fn ping(&mut self) {
2705 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() {
2708 path_data.pending_ping = true;
2709 }
2710 }
2711
2712 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> {
2716 let path_data = self.spaces[self.highest_space]
2717 .number_spaces
2718 .get_mut(&path)
2719 .ok_or(ClosedPath { _private: () })?;
2720 path_data.pending_ping = true;
2721 Ok(())
2722 }
2723
2724 pub fn force_key_update(&mut self) {
2728 if !self.state.is_established() {
2729 debug!("ignoring forced key update in illegal state");
2730 return;
2731 }
2732 if self.crypto_state.prev_crypto.is_some() {
2733 debug!("ignoring redundant forced key update");
2736 return;
2737 }
2738 self.crypto_state.update_keys(None, false);
2739 }
2740
2741 pub fn crypto_session(&self) -> &dyn crypto::Session {
2743 self.crypto_state.session.as_ref()
2744 }
2745
2746 pub fn is_handshaking(&self) -> bool {
2756 self.state.is_handshake()
2757 }
2758
2759 pub fn is_closed(&self) -> bool {
2770 self.state.is_closed()
2771 }
2772
2773 pub fn is_drained(&self) -> bool {
2778 self.state.is_drained()
2779 }
2780
2781 pub fn accepted_0rtt(&self) -> bool {
2785 self.crypto_state.accepted_0rtt
2786 }
2787
2788 pub fn has_0rtt(&self) -> bool {
2790 self.crypto_state.zero_rtt_enabled
2791 }
2792
2793 pub fn has_pending_retransmits(&self) -> bool {
2795 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams)
2796 }
2797
2798 pub fn side(&self) -> Side {
2800 self.side.side()
2801 }
2802
2803 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> {
2805 self.path(path_id)
2806 .map(|path_data| {
2807 path_data
2808 .last_observed_addr_report
2809 .as_ref()
2810 .map(|observed| observed.socket_addr())
2811 })
2812 .ok_or(ClosedPath { _private: () })
2813 }
2814
2815 pub fn rtt(&self, path_id: PathId) -> Option<Duration> {
2817 self.path(path_id).map(|d| d.rtt.get())
2818 }
2819
2820 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> {
2822 self.path(path_id).map(|d| d.congestion.as_ref())
2823 }
2824
2825 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) {
2830 self.streams.set_max_concurrent(dir, count);
2831 let pending = &mut self.spaces[SpaceId::Data].pending;
2834 self.streams.queue_max_stream_id(pending);
2835 }
2836
2837 pub fn set_max_concurrent_paths(
2847 &mut self,
2848 now: Instant,
2849 count: NonZeroU32,
2850 ) -> Result<(), MultipathNotNegotiated> {
2851 if !self.is_multipath_negotiated() {
2852 return Err(MultipathNotNegotiated { _private: () });
2853 }
2854 self.max_concurrent_paths = count;
2855
2856 let in_use_count = self
2857 .local_max_path_id
2858 .next()
2859 .saturating_sub(self.abandoned_paths.len())
2860 .as_u32();
2861 let extra_needed = count.get().saturating_sub(in_use_count);
2862 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed);
2863
2864 self.set_max_path_id(now, new_max_path_id);
2865
2866 Ok(())
2867 }
2868
2869 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) {
2871 if max_path_id <= self.local_max_path_id {
2872 return;
2873 }
2874
2875 self.local_max_path_id = max_path_id;
2876 self.spaces[SpaceId::Data].pending.max_path_id = true;
2877
2878 self.issue_first_path_cids(now);
2879 }
2880
2881 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 {
2888 self.streams.max_concurrent(dir)
2889 }
2890
2891 pub fn set_send_window(&mut self, send_window: u64) {
2893 self.streams.set_send_window(send_window);
2894 }
2895
2896 pub fn set_receive_window(&mut self, receive_window: VarInt) {
2898 if self.streams.set_receive_window(receive_window) {
2899 self.spaces[SpaceId::Data].pending.max_data = true;
2900 }
2901 }
2902
2903 pub fn is_multipath_negotiated(&self) -> bool {
2908 !self.is_handshaking()
2909 && self.config.max_concurrent_multipath_paths.is_some()
2910 && self.peer_params.initial_max_path_id.is_some()
2911 }
2912
2913 fn on_ack_received(
2914 &mut self,
2915 now: Instant,
2916 space: SpaceId,
2917 ack: frame::Ack,
2918 ) -> Result<(), TransportError> {
2919 let path = PathId::ZERO;
2921 self.inner_on_ack_received(now, space, path, ack)
2922 }
2923
2924 fn on_path_ack_received(
2925 &mut self,
2926 now: Instant,
2927 space: SpaceId,
2928 path_ack: frame::PathAck,
2929 ) -> Result<(), TransportError> {
2930 let (ack, path) = path_ack.into_ack();
2931 self.inner_on_ack_received(now, space, path, ack)
2932 }
2933
2934 fn inner_on_ack_received(
2936 &mut self,
2937 now: Instant,
2938 space: SpaceId,
2939 path: PathId,
2940 ack: frame::Ack,
2941 ) -> Result<(), TransportError> {
2942 if !self.spaces[space].number_spaces.contains_key(&path) {
2943 if self.abandoned_paths.contains(&path) {
2944 trace!("silently ignoring PATH_ACK on discarded path");
2950 return Ok(());
2951 } else {
2952 return Err(TransportError::PROTOCOL_VIOLATION(
2953 "received PATH_ACK with path ID never used",
2954 ));
2955 }
2956 }
2957 if ack.largest >= self.spaces[space].for_path(path).next_packet_number {
2958 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked"));
2959 }
2960 let new_largest_pn = {
2962 let space = &mut self.spaces[space].for_path(path);
2963 if space
2964 .largest_acked_packet_pn
2965 .is_none_or(|pn| ack.largest > pn)
2966 {
2967 space.largest_acked_packet_pn = Some(ack.largest);
2968 if let Some(info) = space.sent_packets.get(ack.largest) {
2969 space.largest_acked_packet_send_time = info.time_sent;
2973 }
2974 Some(ack.largest)
2975 } else {
2976 None
2977 }
2978 };
2979
2980 if self.detect_spurious_loss(&ack, space, path) {
2981 self.path_stats.get_mut(path).spurious_congestion_events += 1;
2982 self.path_data_mut(path)
2983 .congestion
2984 .on_spurious_congestion_event();
2985 }
2986
2987 let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new();
2989 for range in ack.iter() {
2990 self.spaces[space].for_path(path).check_ack(range.clone())?;
2991 for (pn, _) in self.spaces[space]
2992 .for_path(path)
2993 .sent_packets
2994 .iter_range(range)
2995 {
2996 newly_acked.insert_one(pn);
2997 }
2998 }
2999
3000 if newly_acked.is_empty() {
3001 return Ok(());
3002 }
3003
3004 let mut ack_eliciting_acked = false;
3005 for packet in newly_acked.elts() {
3006 if let Some(info) = self.spaces[space].for_path(path).take(packet) {
3007 for (acked_path_id, acked_pn) in info.largest_acked.iter() {
3008 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) {
3014 pns.pending_acks.subtract_below(*acked_pn);
3015 }
3016 }
3017 ack_eliciting_acked |= info.ack_eliciting;
3018
3019 let path_data = self.path_data_mut(path);
3021 let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size);
3022 if mtu_updated {
3023 path_data
3024 .congestion
3025 .on_mtu_update(path_data.mtud.current_mtu());
3026 }
3027
3028 self.ack_frequency.on_acked(path, packet);
3031
3032 self.on_packet_acked(now, path, packet, info);
3033 }
3034 }
3035
3036 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn;
3037 let path_data = self.path_data_mut(path);
3038 let app_limited = path_data.app_limited;
3039 let in_flight = path_data.in_flight.bytes;
3040
3041 path_data
3042 .congestion
3043 .on_end_acks(now, in_flight, app_limited, largest_ackd);
3044
3045 if new_largest_pn.is_some() && ack_eliciting_acked {
3046 let ack_delay = if space != SpaceId::Data {
3047 Duration::from_micros(0)
3048 } else {
3049 cmp::min(
3050 self.ack_frequency.peer_max_ack_delay,
3051 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0),
3052 )
3053 };
3054 let rtt = now.saturating_duration_since(
3055 self.spaces[space]
3056 .for_path(path)
3057 .largest_acked_packet_send_time,
3058 );
3059
3060 let next_pn = self.spaces[space].for_path(path).next_packet_number;
3061 let path_data = self.path_data_mut(path);
3062 path_data.rtt.update(ack_delay, rtt);
3064 if path_data.first_packet_after_rtt_sample.is_none() {
3065 path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn));
3066 }
3067 }
3068
3069 self.detect_lost_packets(now, space, path, true);
3071
3072 if self.peer_completed_handshake_address_validation() {
3077 self.path_data_mut(path).pto_count = 0;
3078 }
3079
3080 if self.path_data(path).sending_ecn {
3085 if let Some(ecn) = ack.ecn {
3086 if let Some(largest_sent_pn) = new_largest_pn {
3091 let sent = self.spaces[space]
3092 .for_path(path)
3093 .largest_acked_packet_send_time;
3094 self.process_ecn(
3095 now,
3096 space,
3097 path,
3098 newly_acked.range_count() as u64,
3099 ecn,
3100 sent,
3101 largest_sent_pn,
3102 );
3103 }
3104 } else {
3105 debug!("ECN not acknowledged by peer");
3108 self.path_data_mut(path).sending_ecn = false;
3109 }
3110 }
3111
3112 self.set_loss_detection_timer(now, path);
3113 Ok(())
3114 }
3115
3116 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool {
3117 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3118
3119 if lost_packets.is_empty() {
3120 return false;
3121 }
3122
3123 for range in ack.iter() {
3124 let spurious_losses: Vec<u64> = lost_packets
3125 .iter_range(range.clone())
3126 .map(|(pn, _info)| pn)
3127 .collect();
3128
3129 for pn in spurious_losses {
3130 lost_packets.remove(pn);
3131 }
3132 }
3133
3134 lost_packets.is_empty()
3139 }
3140
3141 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) {
3146 let two_pto = 2 * self.path_data(path).rtt.pto_base();
3147
3148 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3149 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto);
3150 }
3151
3152 fn process_ecn(
3154 &mut self,
3155 now: Instant,
3156 space: SpaceId,
3157 path: PathId,
3158 newly_acked_pn: u64,
3159 ecn: frame::EcnCounts,
3160 largest_sent_time: Instant,
3161 largest_sent_pn: u64,
3162 ) {
3163 match self.spaces[space]
3164 .for_path(path)
3165 .detect_ecn(newly_acked_pn, ecn)
3166 {
3167 Err(e) => {
3168 debug!("halting ECN due to verification failure: {}", e);
3169
3170 self.path_data_mut(path).sending_ecn = false;
3171 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO;
3174 }
3175 Ok(false) => {}
3176 Ok(true) => {
3177 self.path_stats.get_mut(path).congestion_events += 1;
3178 self.path_data_mut(path).congestion.on_congestion_event(
3179 now,
3180 largest_sent_time,
3181 false,
3182 true,
3183 0,
3184 largest_sent_pn,
3185 );
3186 }
3187 }
3188 }
3189
3190 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, pn: u64, info: SentPacket) {
3193 let path = self.path_data_mut(path_id);
3194 let app_limited = path.app_limited;
3195 path.remove_in_flight(&info);
3196 if info.ack_eliciting && info.path_generation == path.generation() {
3197 let rtt = path.rtt;
3201 path.congestion
3202 .on_ack(now, info.time_sent, info.size.into(), pn, app_limited, &rtt);
3203 }
3204
3205 if let Some(retransmits) = info.retransmits.get() {
3207 for (id, _) in retransmits.reset_stream.iter() {
3208 self.streams.reset_acked(*id);
3209 }
3210 }
3211
3212 for frame in info.stream_frames {
3213 self.streams.received_ack_of(frame);
3214 }
3215 }
3216
3217 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) {
3218 let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) {
3219 now
3220 } else {
3221 self.crypto_state
3222 .prev_crypto
3223 .as_ref()
3224 .expect("no previous keys")
3225 .end_packet
3226 .as_ref()
3227 .expect("update not acknowledged yet")
3228 .1
3229 };
3230
3231 self.timers.set(
3233 Timer::Conn(ConnTimer::KeyDiscard),
3234 start + self.max_pto_for_space(space) * 3,
3235 self.qlog.with_time(now),
3236 );
3237 }
3238
3239 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) {
3252 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) {
3253 self.detect_lost_packets(now, pn_space, path_id, false);
3255 self.set_loss_detection_timer(now, path_id);
3256 return;
3257 }
3258
3259 let Some((_, space)) = self.pto_time_and_space(now, path_id) else {
3260 debug!(%path_id, "PTO expired while unset");
3261 return;
3262 };
3263 trace!(
3264 in_flight = self.path_data(path_id).in_flight.bytes,
3265 count = self.path_data(path_id).pto_count,
3266 ?space,
3267 %path_id,
3268 "PTO fired"
3269 );
3270
3271 let count = match self.path_data(path_id).in_flight.ack_eliciting {
3272 0 => {
3275 debug_assert!(!self.peer_completed_handshake_address_validation());
3276 1
3277 }
3278 _ => 2,
3280 };
3281 let pns = self.spaces[space].for_path(path_id);
3282 pns.loss_probes = pns.loss_probes.saturating_add(count);
3283 let path_data = self.path_data_mut(path_id);
3284 path_data.pto_count = path_data.pto_count.saturating_add(1);
3285 self.set_loss_detection_timer(now, path_id);
3286 }
3287
3288 fn detect_lost_packets(
3305 &mut self,
3306 now: Instant,
3307 pn_space: SpaceId,
3308 path_id: PathId,
3309 due_to_ack: bool,
3310 ) {
3311 let mut lost_packets = Vec::<u64>::new();
3312 let mut lost_mtu_probe = None;
3313 let mut in_persistent_congestion = false;
3314 let mut size_of_lost_packets = 0u64;
3315 self.spaces[pn_space].for_path(path_id).loss_time = None;
3316
3317 let path = self.path_data(path_id);
3320 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3321 let loss_delay = path
3322 .rtt
3323 .conservative()
3324 .mul_f32(self.config.time_threshold)
3325 .max(TIMER_GRANULARITY);
3326 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample;
3327
3328 let largest_acked_packet_pn = self.spaces[pn_space]
3329 .for_path(path_id)
3330 .largest_acked_packet_pn
3331 .expect("detect_lost_packets only to be called if path received at least one ACK");
3332 let packet_threshold = self.config.packet_threshold as u64;
3333
3334 let congestion_period = self
3338 .pto(SpaceKind::Data, path_id)
3339 .saturating_mul(self.config.persistent_congestion_threshold);
3340 let mut persistent_congestion_start: Option<Instant> = None;
3341 let mut prev_packet = None;
3342 let space = self.spaces[pn_space].for_path(path_id);
3343
3344 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) {
3345 if prev_packet != Some(packet.wrapping_sub(1)) {
3346 persistent_congestion_start = None;
3348 }
3349
3350 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay;
3354 if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold {
3355 if Some(packet) == in_flight_mtu_probe {
3357 lost_mtu_probe = in_flight_mtu_probe;
3362 } else {
3363 lost_packets.push(packet);
3364 size_of_lost_packets += info.size as u64;
3365 if info.ack_eliciting && due_to_ack {
3366 match persistent_congestion_start {
3367 Some(start) if info.time_sent - start > congestion_period => {
3370 in_persistent_congestion = true;
3371 }
3372 None if first_packet_after_rtt_sample
3374 .is_some_and(|x| x < (pn_space.kind(), packet)) =>
3375 {
3376 persistent_congestion_start = Some(info.time_sent);
3377 }
3378 _ => {}
3379 }
3380 }
3381 }
3382 } else {
3383 if space.loss_time.is_none() {
3385 space.loss_time = Some(info.time_sent + loss_delay);
3388 }
3389 persistent_congestion_start = None;
3390 }
3391
3392 prev_packet = Some(packet);
3393 }
3394
3395 self.handle_lost_packets(
3396 pn_space,
3397 path_id,
3398 now,
3399 lost_packets,
3400 lost_mtu_probe,
3401 loss_delay,
3402 in_persistent_congestion,
3403 size_of_lost_packets,
3404 );
3405 }
3406
3407 fn discard_path(&mut self, path_id: PathId, now: Instant) {
3409 trace!(%path_id, "dropping path state");
3410 let path = self.path_data(path_id);
3411 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3412
3413 let mut size_of_lost_packets = 0u64; let lost_pns: Vec<_> = self.spaces[SpaceId::Data]
3415 .for_path(path_id)
3416 .sent_packets
3417 .iter()
3418 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe)
3419 .map(|(pn, info)| {
3420 size_of_lost_packets += info.size as u64;
3421 pn
3422 })
3423 .collect();
3424
3425 if !lost_pns.is_empty() {
3426 trace!(
3427 %path_id,
3428 count = lost_pns.len(),
3429 lost_bytes = size_of_lost_packets,
3430 "packets lost on path abandon"
3431 );
3432 self.handle_lost_packets(
3433 SpaceId::Data,
3434 path_id,
3435 now,
3436 lost_pns,
3437 in_flight_mtu_probe,
3438 Duration::ZERO,
3439 false,
3440 size_of_lost_packets,
3441 );
3442 }
3443 let path_stats = self.path_stats(path_id).unwrap_or_default();
3446 self.path_stats.discard(&path_id);
3447 self.partial_stats += path_stats;
3448 self.paths.remove(&path_id);
3449 self.spaces[SpaceId::Data].number_spaces.remove(&path_id);
3450
3451 self.events.push_back(
3452 PathEvent::Discarded {
3453 id: path_id,
3454 path_stats: Box::new(path_stats),
3455 }
3456 .into(),
3457 );
3458 }
3459
3460 fn handle_lost_packets(
3461 &mut self,
3462 pn_space: SpaceId,
3463 path_id: PathId,
3464 now: Instant,
3465 lost_packets: Vec<u64>,
3466 lost_mtu_probe: Option<u64>,
3467 loss_delay: Duration,
3468 in_persistent_congestion: bool,
3469 size_of_lost_packets: u64,
3470 ) {
3471 debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted");
3472
3473 self.drain_lost_packets(now, pn_space, path_id);
3474
3475 if let Some(largest_lost) = lost_packets.last().cloned() {
3477 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes;
3478 let largest_lost_sent = self.spaces[pn_space]
3479 .for_path(path_id)
3480 .sent_packets
3481 .get(largest_lost)
3482 .unwrap()
3483 .time_sent;
3484 let path_stats = self.path_stats.get_mut(path_id);
3485 path_stats.lost_packets += lost_packets.len() as u64;
3486 path_stats.lost_bytes += size_of_lost_packets;
3487 trace!(
3488 %path_id,
3489 count = lost_packets.len(),
3490 lost_bytes = size_of_lost_packets,
3491 "packets lost",
3492 );
3493
3494 for &packet in &lost_packets {
3495 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else {
3496 continue;
3497 };
3498 self.qlog
3499 .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now);
3500 self.paths
3501 .get_mut(&path_id)
3502 .unwrap()
3503 .remove_in_flight(&info);
3504
3505 for frame in info.stream_frames {
3506 self.streams.retransmit(frame);
3507 }
3508 self.spaces[pn_space].pending |= info.retransmits;
3509 let path = self.path_data_mut(path_id);
3510 path.pending |= info.path_retransmits;
3511 path.mtud.on_non_probe_lost(packet, info.size);
3512 path.congestion.on_packet_lost(info.size, packet, now);
3513
3514 self.spaces[pn_space].for_path(path_id).lost_packets.insert(
3515 packet,
3516 LostPacket {
3517 time_sent: info.time_sent,
3518 },
3519 );
3520 }
3521
3522 let path = self.path_data_mut(path_id);
3523 if path.mtud.black_hole_detected(now) {
3524 path.congestion.on_mtu_update(path.mtud.current_mtu());
3525 if let Some(max_datagram_size) = self.datagrams().max_size()
3526 && self.datagrams.drop_oversized(max_datagram_size)
3527 && self.datagrams.send_blocked
3528 {
3529 self.datagrams.send_blocked = false;
3530 self.events.push_back(Event::DatagramsUnblocked);
3531 }
3532 self.path_stats.get_mut(path_id).black_holes_detected += 1;
3533 }
3534
3535 let lost_ack_eliciting =
3537 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes;
3538
3539 if lost_ack_eliciting {
3540 self.path_stats.get_mut(path_id).congestion_events += 1;
3541 self.path_data_mut(path_id).congestion.on_congestion_event(
3542 now,
3543 largest_lost_sent,
3544 in_persistent_congestion,
3545 false,
3546 size_of_lost_packets,
3547 largest_lost,
3548 );
3549 }
3550 }
3551
3552 if let Some(packet) = lost_mtu_probe {
3554 let info = self.spaces[SpaceId::Data]
3555 .for_path(path_id)
3556 .take(packet)
3557 .unwrap(); self.paths
3560 .get_mut(&path_id)
3561 .unwrap()
3562 .remove_in_flight(&info);
3563 self.path_data_mut(path_id).mtud.on_probe_lost();
3564 let path_stats = self.path_stats.get_mut(path_id);
3565 path_stats.lost_plpmtud_probes += 1;
3566 path_stats.lost_packets += 1;
3569 path_stats.lost_bytes += info.size as u64;
3570 }
3571 }
3572
3573 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> {
3579 SpaceId::iter()
3580 .filter_map(|id| {
3581 self.spaces[id]
3582 .number_spaces
3583 .get(&path_id)
3584 .and_then(|pns| pns.loss_time)
3585 .map(|time| (time, id))
3586 })
3587 .min_by_key(|&(time, _)| time)
3588 }
3589
3590 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> {
3598 let path = self.path(path_id)?;
3599 let pto_count = path.pto_count;
3600
3601 let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD {
3603 (path.rtt.get() * 3) / 2
3605 } else if let Some(idle) = path.idle_timeout.or(self.idle_timeout)
3606 && idle <= MIN_IDLE_FOR_FAST_PTO
3607 {
3608 MAX_PTO_FAST_INTERVAL
3611 } else {
3612 MAX_PTO_INTERVAL
3614 };
3615
3616 if path_id == PathId::ZERO
3617 && path.in_flight.ack_eliciting == 0
3618 && !self.peer_completed_handshake_address_validation()
3619 {
3620 let space = match self.highest_space {
3626 SpaceKind::Handshake => SpaceId::Handshake,
3627 _ => SpaceId::Initial,
3628 };
3629
3630 let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT));
3631 let duration = path.rtt.pto_base() * backoff;
3632 let duration = duration.min(max_interval);
3633 return Some((now + duration, space));
3634 }
3635
3636 let mut result = None;
3637 for space in SpaceId::iter() {
3638 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else {
3639 continue;
3640 };
3641
3642 if space == SpaceId::Data && !self.is_handshake_confirmed() {
3643 continue;
3647 }
3648
3649 if !pns.has_in_flight() {
3650 continue;
3651 }
3652
3653 let duration = {
3658 let max_ack_delay = if space == SpaceId::Data {
3659 self.ack_frequency.max_ack_delay_for_pto()
3660 } else {
3661 Duration::ZERO
3662 };
3663 let pto_base = path.rtt.pto_base() + max_ack_delay;
3664 let mut duration = pto_base;
3665 for i in 1..=pto_count {
3666 let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT));
3667 let max_duration = duration + max_interval;
3668 duration = exponential_duration.min(max_duration);
3669 }
3670 duration
3671 };
3672
3673 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else {
3674 continue;
3675 };
3676 let pto = last_ack_eliciting + duration;
3679 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) {
3680 if path.anti_amplification_blocked(1) {
3681 continue;
3683 }
3684 if path.in_flight.ack_eliciting == 0 {
3685 continue;
3687 }
3688 result = Some((pto, space));
3689 }
3690 }
3691 result
3692 }
3693
3694 fn peer_completed_handshake_address_validation(&self) -> bool {
3696 if self.side.is_server() || self.state.is_closed() {
3697 return true;
3698 }
3699 self.spaces[SpaceId::Handshake]
3703 .path_space(PathId::ZERO)
3704 .and_then(|pns| pns.largest_acked_packet_pn)
3705 .is_some()
3706 || self.spaces[SpaceId::Data]
3707 .path_space(PathId::ZERO)
3708 .and_then(|pns| pns.largest_acked_packet_pn)
3709 .is_some()
3710 || (self.crypto_state.has_keys(EncryptionLevel::OneRtt)
3711 && !self.crypto_state.has_keys(EncryptionLevel::Handshake))
3712 }
3713
3714 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) {
3722 if self.state.is_closed() {
3723 return;
3727 }
3728
3729 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) {
3730 self.timers.set(
3732 Timer::PerPath(path_id, PathTimer::LossDetection),
3733 loss_time,
3734 self.qlog.with_time(now),
3735 );
3736 return;
3737 }
3738
3739 if !self.abandoned_paths.contains(&path_id)
3742 && let Some((timeout, _)) = self.pto_time_and_space(now, path_id)
3743 {
3744 self.timers.set(
3745 Timer::PerPath(path_id, PathTimer::LossDetection),
3746 timeout,
3747 self.qlog.with_time(now),
3748 );
3749 } else {
3750 self.timers.stop(
3751 Timer::PerPath(path_id, PathTimer::LossDetection),
3752 self.qlog.with_time(now),
3753 );
3754 }
3755 }
3756
3757 fn max_pto_for_space(&self, space: SpaceKind) -> Duration {
3761 self.paths
3762 .keys()
3763 .map(|path_id| self.pto(space, *path_id))
3764 .max()
3765 .unwrap_or_else(|| {
3766 let rtt = self.config.initial_rtt;
3770 let max_ack_delay = match space {
3771 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3772 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3773 };
3774 rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay
3775 })
3776 }
3777
3778 fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration {
3783 let max_ack_delay = match space {
3784 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3785 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3786 };
3787 self.path_data(path_id).rtt.pto_base() + max_ack_delay
3788 }
3789
3790 fn on_packet_authenticated(
3791 &mut self,
3792 now: Instant,
3793 space_id: SpaceKind,
3794 path_id: PathId,
3795 ecn: Option<EcnCodepoint>,
3796 packet_number: Option<u64>,
3797 spin: bool,
3798 is_1rtt: bool,
3799 remote: &FourTuple,
3800 ) {
3801 let is_on_path = self
3808 .path_data(path_id)
3809 .network_path
3810 .is_probably_same_path(remote);
3811
3812 self.total_authed_packets += 1;
3813 self.reset_keep_alive(path_id, now);
3814 self.reset_idle_timeout(now, space_id, path_id);
3815 self.path_data_mut(path_id).permit_idle_reset = true;
3816
3817 if is_on_path {
3820 self.receiving_ecn |= ecn.is_some();
3821 if let Some(x) = ecn {
3822 let space = &mut self.spaces[space_id];
3823 space.for_path(path_id).ecn_counters += x;
3824
3825 if x.is_ce() {
3826 space
3827 .for_path(path_id)
3828 .pending_acks
3829 .set_immediate_ack_required();
3830 }
3831 }
3832 }
3833
3834 let Some(packet_number) = packet_number else {
3835 return;
3836 };
3837 match &self.side {
3838 ConnectionSide::Client { .. } => {
3839 if space_id == SpaceKind::Handshake
3843 && let Some(hs) = self.state.as_handshake_mut()
3844 {
3845 hs.allow_server_migration = false;
3846 }
3847 }
3848 ConnectionSide::Server { .. } => {
3849 if self.crypto_state.has_keys(EncryptionLevel::Initial)
3850 && space_id == SpaceKind::Handshake
3851 {
3852 self.discard_space(now, SpaceKind::Initial);
3855 }
3856 if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt {
3857 self.set_key_discard_timer(now, space_id)
3859 }
3860 }
3861 }
3862 let space = self.spaces[space_id].for_path(path_id);
3863
3864 space.pending_acks.insert_one(packet_number, now);
3865 if packet_number >= space.largest_received_packet_number.unwrap_or_default() {
3866 space.largest_received_packet_number = Some(packet_number);
3867
3868 if is_on_path {
3870 self.spin = self.side.is_client() ^ spin;
3871 }
3872 }
3873 }
3874
3875 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
3880 if let Some(timeout) = self.idle_timeout {
3882 if self.state.is_closed() {
3883 self.timers
3884 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now));
3885 } else {
3886 let dt = cmp::max(timeout, 3 * self.max_pto_for_space(space));
3887 self.timers.set(
3888 Timer::Conn(ConnTimer::Idle),
3889 now + dt,
3890 self.qlog.with_time(now),
3891 );
3892 }
3893 }
3894
3895 self.rearm_path_max_idle_timer(now, space, path_id);
3897 }
3898
3899 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) {
3901 if !self.state.is_established() {
3902 return;
3903 }
3904
3905 if let Some(interval) = self.config.keep_alive_interval {
3906 self.timers.set(
3907 Timer::Conn(ConnTimer::KeepAlive),
3908 now + interval,
3909 self.qlog.with_time(now),
3910 );
3911 }
3912
3913 if let Some(interval) = self.path_data(path_id).keep_alive {
3914 self.timers.set(
3915 Timer::PerPath(path_id, PathTimer::PathKeepAlive),
3916 now + interval,
3917 self.qlog.with_time(now),
3918 );
3919 }
3920 }
3921
3922 fn reset_cid_retirement(&mut self, now: Instant) {
3924 if let Some((_path, t)) = self.next_cid_retirement() {
3925 self.timers.set(
3926 Timer::Conn(ConnTimer::PushNewCid),
3927 t,
3928 self.qlog.with_time(now),
3929 );
3930 }
3931 }
3932
3933 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> {
3935 self.local_cid_state
3936 .iter()
3937 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t)))
3938 .min_by_key(|(_path_id, timeout)| *timeout)
3939 }
3940
3941 pub(crate) fn handle_first_packet(
3946 &mut self,
3947 now: Instant,
3948 network_path: FourTuple,
3949 ecn: Option<EcnCodepoint>,
3950 packet_number: u64,
3951 packet: InitialPacket,
3952 remaining: Option<BytesMut>,
3953 ) -> Result<(), ConnectionError> {
3954 let span = trace_span!("first recv");
3955 let _guard = span.enter();
3956 debug_assert!(self.side.is_server());
3957 let len = packet.header_data.len() + packet.payload.len();
3958 let path_id = PathId::ZERO;
3959 self.path_data_mut(path_id).total_recvd = len as u64;
3960
3961 if let Some(hs) = self.state.as_handshake_mut() {
3962 hs.expected_token = packet.header.token.clone();
3963 } else {
3964 unreachable!("first packet must be delivered in Handshake state");
3965 }
3966
3967 self.on_packet_authenticated(
3969 now,
3970 SpaceKind::Initial,
3971 path_id,
3972 ecn,
3973 Some(packet_number),
3974 false,
3975 false,
3976 &network_path,
3977 );
3978
3979 let packet: Packet = packet.into();
3980
3981 let mut qlog = QlogRecvPacket::new(len);
3982 qlog.header(&packet.header, Some(packet_number), path_id);
3983
3984 self.process_decrypted_packet(
3985 now,
3986 network_path,
3987 path_id,
3988 Some(packet_number),
3989 packet,
3990 &mut qlog,
3991 )?;
3992 self.qlog.emit_packet_received(qlog, now);
3993 if let Some(data) = remaining {
3994 self.handle_coalesced(now, network_path, path_id, ecn, data);
3995 }
3996
3997 self.qlog.emit_recovery_metrics(
3998 path_id,
3999 &mut self
4000 .paths
4001 .get_mut(&path_id)
4002 .expect("path_id was supplied by the caller for an active path")
4003 .data,
4004 now,
4005 );
4006
4007 Ok(())
4008 }
4009
4010 fn init_0rtt(&mut self, now: Instant) {
4011 let Some((header, packet)) = self.crypto_state.session.early_crypto() else {
4012 return;
4013 };
4014 if self.side.is_client() {
4015 match self.crypto_state.session.transport_parameters() {
4016 Ok(params) => {
4017 let params = params
4018 .expect("crypto layer didn't supply transport parameters with ticket");
4019 let params = TransportParameters {
4021 initial_src_cid: None,
4022 original_dst_cid: None,
4023 preferred_address: None,
4024 retry_src_cid: None,
4025 stateless_reset_token: None,
4026 min_ack_delay: None,
4027 ack_delay_exponent: TransportParameters::default().ack_delay_exponent,
4028 max_ack_delay: TransportParameters::default().max_ack_delay,
4029 initial_max_path_id: None,
4030 ..params
4031 };
4032 self.set_peer_params(params);
4033 self.qlog.emit_peer_transport_params_restored(self, now);
4034 }
4035 Err(e) => {
4036 error!("session ticket has malformed transport parameters: {}", e);
4037 return;
4038 }
4039 }
4040 }
4041 trace!("0-RTT enabled");
4042 self.crypto_state.enable_zero_rtt(header, packet);
4043 }
4044
4045 fn read_crypto(
4046 &mut self,
4047 space: SpaceId,
4048 crypto: &frame::Crypto,
4049 payload_len: usize,
4050 ) -> Result<(), TransportError> {
4051 let expected = if !self.state.is_handshake() {
4052 SpaceId::Data
4053 } else if self.highest_space == SpaceKind::Initial {
4054 SpaceId::Initial
4055 } else {
4056 SpaceId::Handshake
4059 };
4060 debug_assert!(space <= expected, "received out-of-order CRYPTO data");
4064
4065 let end = crypto.offset + crypto.data.len() as u64;
4066 if space < expected
4067 && end
4068 > self.crypto_state.spaces[space.kind()]
4069 .crypto_stream
4070 .bytes_read()
4071 {
4072 warn!(
4073 "received new {:?} CRYPTO data when expecting {:?}",
4074 space, expected
4075 );
4076 return Err(TransportError::PROTOCOL_VIOLATION(
4077 "new data at unexpected encryption level",
4078 ));
4079 }
4080
4081 let crypto_space = &mut self.crypto_state.spaces[space.kind()];
4082 let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read());
4083 if max > self.config.crypto_buffer_size as u64 {
4084 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED(""));
4085 }
4086
4087 crypto_space
4088 .crypto_stream
4089 .insert(crypto.offset, crypto.data.clone(), payload_len);
4090 while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) {
4091 trace!("consumed {} CRYPTO bytes", chunk.bytes.len());
4092 if self.crypto_state.session.read_handshake(&chunk.bytes)? {
4093 self.events.push_back(Event::HandshakeDataReady);
4094 }
4095 }
4096
4097 Ok(())
4098 }
4099
4100 fn write_crypto(&mut self) {
4101 loop {
4102 let space = self.highest_space;
4103 let mut outgoing = Vec::new();
4104 if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) {
4105 match space {
4106 SpaceKind::Initial => {
4107 self.upgrade_crypto(SpaceKind::Handshake, crypto);
4108 }
4109 SpaceKind::Handshake => {
4110 self.upgrade_crypto(SpaceKind::Data, crypto);
4111 }
4112 SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"),
4113 }
4114 }
4115 if outgoing.is_empty() {
4116 if space == self.highest_space {
4117 break;
4118 } else {
4119 continue;
4121 }
4122 }
4123 let offset = self.crypto_state.spaces[space].crypto_offset;
4124 let outgoing = Bytes::from(outgoing);
4125 if let Some(hs) = self.state.as_handshake_mut()
4126 && space == SpaceKind::Initial
4127 && offset == 0
4128 && self.side.is_client()
4129 {
4130 hs.client_hello = Some(outgoing.clone());
4131 }
4132 self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64;
4133 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space);
4134 self.spaces[space].pending.crypto.push_back(frame::Crypto {
4135 offset,
4136 data: outgoing,
4137 });
4138 }
4139 }
4140
4141 fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) {
4143 debug_assert!(
4144 !self.crypto_state.has_keys(space.encryption_level()),
4145 "already reached packet space {space:?}"
4146 );
4147 trace!("{:?} keys ready", space);
4148 if space == SpaceKind::Data {
4149 self.crypto_state.next_crypto = Some(
4151 self.crypto_state
4152 .session
4153 .next_1rtt_keys()
4154 .expect("handshake should be complete"),
4155 );
4156 }
4157
4158 self.crypto_state.spaces[space].keys = Some(crypto);
4159 debug_assert!(space > self.highest_space);
4160 self.highest_space = space;
4161 if space == SpaceKind::Data && self.side.is_client() {
4162 self.crypto_state.discard_zero_rtt();
4164 }
4165 }
4166
4167 fn discard_space(&mut self, now: Instant, space: SpaceKind) {
4168 debug_assert!(space != SpaceKind::Data);
4169 trace!("discarding {:?} keys", space);
4170 if space == SpaceKind::Initial {
4171 if let ConnectionSide::Client { token, .. } = &mut self.side {
4173 *token = Bytes::new();
4174 }
4175 }
4176 self.crypto_state.spaces[space].keys = None;
4177 let space = &mut self.spaces[space];
4178 let pns = space.for_path(PathId::ZERO);
4179 pns.time_of_last_ack_eliciting_packet = None;
4180 pns.loss_time = None;
4181 pns.loss_probes = 0;
4182 let sent_packets = mem::take(&mut pns.sent_packets);
4183 let path = self
4184 .paths
4185 .get_mut(&PathId::ZERO)
4186 .expect("PathId::ZERO is alive while Initial/Handshake spaces exist");
4187 for (_, packet) in sent_packets.into_iter() {
4188 path.data.remove_in_flight(&packet);
4189 }
4190
4191 self.set_loss_detection_timer(now, PathId::ZERO)
4192 }
4193
4194 fn handle_coalesced(
4195 &mut self,
4196 now: Instant,
4197 network_path: FourTuple,
4198 path_id: PathId,
4199 ecn: Option<EcnCodepoint>,
4200 data: BytesMut,
4201 ) {
4202 let Some(path) = self.paths.get_mut(&path_id) else {
4203 trace!(%path_id, "discarding coalesced datagram tail for unknown path");
4204 return;
4205 };
4206 path.data.inc_total_recvd(data.len() as u64);
4207 let mut remaining = Some(data);
4208 let cid_len = self
4209 .local_cid_state
4210 .values()
4211 .map(|cid_state| cid_state.cid_len())
4212 .next()
4213 .expect("one cid_state must exist");
4214 while let Some(data) = remaining {
4215 match PartialDecode::new(
4216 data,
4217 &FixedLengthConnectionIdParser::new(cid_len),
4218 &[self.version],
4219 self.endpoint_config.grease_quic_bit,
4220 ) {
4221 Ok((partial_decode, rest)) => {
4222 remaining = rest;
4223 self.handle_decode(now, network_path, path_id, ecn, partial_decode);
4224 }
4225 Err(e) => {
4226 trace!("malformed header: {}", e);
4227 return;
4228 }
4229 }
4230 }
4231 }
4232
4233 fn handle_decode(
4239 &mut self,
4240 now: Instant,
4241 network_path: FourTuple,
4242 path_id: PathId,
4243 ecn: Option<EcnCodepoint>,
4244 partial_decode: PartialDecode,
4245 ) {
4246 let qlog = QlogRecvPacket::new(partial_decode.len());
4247 if let Some(decoded) = self
4248 .crypto_state
4249 .unprotect_header(partial_decode, self.peer_params.stateless_reset_token)
4250 {
4251 self.handle_packet(
4252 now,
4253 network_path,
4254 path_id,
4255 ecn,
4256 decoded.packet,
4257 decoded.stateless_reset,
4258 qlog,
4259 );
4260 }
4261 }
4262
4263 fn handle_packet(
4270 &mut self,
4271 now: Instant,
4272 network_path: FourTuple,
4273 path_id: PathId,
4274 ecn: Option<EcnCodepoint>,
4275 packet: Option<Packet>,
4276 stateless_reset: bool,
4277 mut qlog: QlogRecvPacket,
4278 ) {
4279 if let Some(ref packet) = packet {
4280 trace!(
4281 "got {:?} packet ({} bytes) from {} using id {}",
4282 packet.header.space(),
4283 packet.payload.len() + packet.header_data.len(),
4284 network_path,
4285 packet.header.dst_cid(),
4286 );
4287 }
4288
4289 let was_closed = self.state.is_closed();
4290 let was_drained = self.state.is_drained();
4291
4292 let decrypted = match packet {
4294 None => Err(None),
4295 Some(mut packet) => self
4296 .decrypt_packet(now, path_id, &mut packet)
4297 .map(move |number| (packet, number)),
4298 };
4299 let result = match decrypted {
4300 _ if stateless_reset => {
4301 debug!("got stateless reset");
4302 Err(ConnectionError::Reset)
4303 }
4304 Err(Some(e)) => {
4305 warn!("illegal packet: {}", e);
4306 Err(e.into())
4307 }
4308 Err(None) => {
4309 debug!("failed to authenticate packet");
4310 self.authentication_failures += 1;
4311 let integrity_limit = self
4312 .crypto_state
4313 .integrity_limit(self.highest_space)
4314 .unwrap();
4315 if self.authentication_failures > integrity_limit {
4316 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into())
4317 } else {
4318 return;
4319 }
4320 }
4321 Ok((packet, pn)) => {
4322 qlog.header(&packet.header, pn, path_id);
4324 let span = match pn {
4325 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn),
4326 None => trace_span!("recv", space = ?packet.header.space()),
4327 };
4328 let _guard = span.enter();
4329
4330 if self.is_handshaking()
4338 && self
4339 .path(path_id)
4340 .map(|path_data| {
4341 !path_data.network_path.is_probably_same_path(&network_path)
4342 })
4343 .unwrap_or(false)
4344 {
4345 if let Some(hs) = self.state.as_handshake()
4346 && hs.allow_server_migration
4347 {
4348 trace!(
4349 %network_path,
4350 prev = %self.path_data(path_id).network_path,
4351 "server migrated to new remote",
4352 );
4353 self.path_data_mut(path_id).network_path = network_path;
4354 self.qlog.emit_tuple_assigned(path_id, network_path, now);
4355 } else {
4356 debug!(
4357 recv_path = %network_path,
4358 expected_path = %self.path_data_mut(path_id).network_path,
4359 "discarding packet with unexpected remote during handshake",
4360 );
4361 return;
4362 }
4363 }
4364
4365 let dedup = self.spaces[packet.header.space()]
4366 .path_space_mut(path_id)
4367 .map(|pns| &mut pns.dedup);
4368 if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) {
4369 debug!("discarding possible duplicate packet");
4370 self.qlog.emit_packet_received(qlog, now);
4371 return;
4372 } else if self.state.is_handshake() && packet.header.is_short() {
4373 trace!("dropping short packet during handshake");
4375 self.qlog.emit_packet_received(qlog, now);
4376 return;
4377 } else {
4378 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header
4379 && let Some(hs) = self.state.as_handshake()
4380 && self.side.is_server()
4381 && token != &hs.expected_token
4382 {
4383 warn!("discarding Initial with invalid retry token");
4387 self.qlog.emit_packet_received(qlog, now);
4388 return;
4389 }
4390
4391 if !self.state.is_closed() {
4392 let spin = match packet.header {
4393 Header::Short { spin, .. } => spin,
4394 _ => false,
4395 };
4396
4397 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) {
4398 self.create_path(path_id, network_path, now, pn);
4400 }
4401 if self.paths.contains_key(&path_id) {
4402 self.on_packet_authenticated(
4403 now,
4404 packet.header.space(),
4405 path_id,
4406 ecn,
4407 pn,
4408 spin,
4409 packet.header.is_1rtt(),
4410 &network_path,
4411 );
4412 }
4413 }
4414
4415 let res = self.process_decrypted_packet(
4416 now,
4417 network_path,
4418 path_id,
4419 pn,
4420 packet,
4421 &mut qlog,
4422 );
4423
4424 self.qlog.emit_packet_received(qlog, now);
4425 res
4426 }
4427 }
4428 };
4429
4430 if let Err(conn_err) = result {
4432 match conn_err {
4433 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason),
4434 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason),
4435 ConnectionError::Reset
4436 | ConnectionError::TransportError(TransportError {
4437 code: TransportErrorCode::AEAD_LIMIT_REACHED,
4438 ..
4439 }) => {
4440 if !self.state.is_drained() {
4441 self.state
4442 .move_to_drained(Some(conn_err), &mut self.endpoint_events);
4443 }
4444 }
4445 ConnectionError::TimedOut => {
4446 unreachable!("timeouts aren't generated by packet processing");
4447 }
4448 ConnectionError::TransportError(err) => {
4449 debug!("closing connection due to transport error: {}", err);
4450 self.state.move_to_closed(err);
4451 }
4452 ConnectionError::VersionMismatch => {
4453 self.state
4454 .move_to_draining(Some(conn_err), &mut self.endpoint_events);
4455 }
4456 ConnectionError::LocallyClosed => {
4457 unreachable!("LocallyClosed isn't generated by packet processing");
4458 }
4459 ConnectionError::CidsExhausted => {
4460 unreachable!("CidsExhausted isn't generated by packet processing");
4461 }
4462 };
4463 }
4464
4465 if !was_closed && self.state.is_closed() {
4466 self.close_common();
4467 if !self.state.is_drained() {
4468 self.set_close_timer(now);
4469 }
4470 }
4471 if !was_drained && self.state.is_drained() {
4472 self.timers
4475 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now));
4476 }
4477
4478 if matches!(self.state.as_type(), StateType::Closed) {
4485 if self
4503 .paths
4504 .get(&path_id)
4505 .map(|p| p.data.validated && p.data.network_path == network_path)
4506 .unwrap_or(false)
4507 {
4508 self.connection_close_pending = true;
4509 }
4510 }
4511 }
4512
4513 fn process_decrypted_packet(
4514 &mut self,
4515 now: Instant,
4516 network_path: FourTuple,
4517 path_id: PathId,
4518 number: Option<u64>,
4519 packet: Packet,
4520 qlog: &mut QlogRecvPacket,
4521 ) -> Result<(), ConnectionError> {
4522 if !self.paths.contains_key(&path_id) {
4523 trace!(%path_id, ?number, "discarding packet for unknown path");
4527 return Ok(());
4528 }
4529 let state = match self.state.as_type() {
4530 StateType::Established => {
4531 match packet.header.space() {
4532 SpaceKind::Data => self.process_payload(
4533 now,
4534 network_path,
4535 path_id,
4536 number.unwrap(),
4537 packet,
4538 qlog,
4539 )?,
4540 _ if packet.header.has_frames() => {
4541 self.process_early_payload(now, path_id, packet, qlog)?
4542 }
4543 _ => {
4544 trace!("discarding unexpected pre-handshake packet");
4545 }
4546 }
4547 return Ok(());
4548 }
4549 StateType::Closed => {
4550 for result in frame::Iter::new(packet.payload.freeze())? {
4551 let frame = match result {
4552 Ok(frame) => frame,
4553 Err(err) => {
4554 debug!("frame decoding error: {err:?}");
4555 continue;
4556 }
4557 };
4558 qlog.frame(&frame);
4559
4560 if let Frame::Padding = frame {
4561 continue;
4562 };
4563
4564 trace!(?frame, "processing frame in closed state");
4565
4566 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4567
4568 if let Frame::Close(_error) = frame {
4569 self.state.move_to_draining(None, &mut self.endpoint_events);
4570 break;
4571 }
4572 }
4573 return Ok(());
4574 }
4575 StateType::Draining | StateType::Drained => return Ok(()),
4576 StateType::Handshake => self.state.as_handshake_mut().expect("checked"),
4577 };
4578
4579 match packet.header {
4580 Header::Retry {
4581 src_cid: remote_cid,
4582 ..
4583 } => {
4584 debug_assert_eq!(path_id, PathId::ZERO);
4585 if self.side.is_server() {
4586 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into());
4587 }
4588
4589 let is_valid_retry = self
4590 .remote_cids
4591 .get(&path_id)
4592 .map(|cids| cids.active())
4593 .map(|orig_dst_cid| {
4594 self.crypto_state.session.is_valid_retry(
4595 orig_dst_cid,
4596 &packet.header_data,
4597 &packet.payload,
4598 )
4599 })
4600 .unwrap_or_default();
4601 if self.total_authed_packets > 1
4602 || packet.payload.len() <= 16 || !is_valid_retry
4604 {
4605 trace!("discarding invalid Retry");
4606 return Ok(());
4612 }
4613
4614 trace!("retrying with CID {}", remote_cid);
4615 let client_hello = state.client_hello.take().unwrap();
4616 self.retry_src_cid = Some(remote_cid);
4617 self.remote_cids
4618 .get_mut(&path_id)
4619 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false")
4620 .update_initial_cid(remote_cid);
4621 self.remote_handshake_cid = remote_cid;
4622
4623 let space = &mut self.spaces[SpaceId::Initial];
4624 if let Some(info) = space.for_path(PathId::ZERO).take(0) {
4625 self.on_packet_acked(now, PathId::ZERO, 0, info);
4626 };
4627
4628 self.discard_space(now, SpaceKind::Initial); let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial];
4631 crypto_space.keys = Some(
4632 self.crypto_state
4633 .session
4634 .initial_keys(remote_cid, self.side.side()),
4635 );
4636 crypto_space.crypto_offset = client_hello.len() as u64;
4637
4638 let next_pn = self.spaces[SpaceId::Initial]
4639 .for_path(path_id)
4640 .next_packet_number;
4641 self.spaces[SpaceId::Initial] = {
4642 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng);
4643 space.for_path(path_id).next_packet_number = next_pn;
4644 space.pending.crypto.push_back(frame::Crypto {
4645 offset: 0,
4646 data: client_hello,
4647 });
4648 space
4649 };
4650
4651 let zero_rtt = mem::take(
4653 &mut self.spaces[SpaceId::Data]
4654 .for_path(PathId::ZERO)
4655 .sent_packets,
4656 );
4657 for (_, info) in zero_rtt.into_iter() {
4658 self.paths
4659 .get_mut(&PathId::ZERO)
4660 .unwrap()
4661 .remove_in_flight(&info);
4662 self.spaces[SpaceId::Data].pending |= info.retransmits;
4663 }
4664 self.streams.retransmit_all_for_0rtt();
4665
4666 let token_len = packet.payload.len() - 16;
4667 let ConnectionSide::Client { ref mut token, .. } = self.side else {
4668 unreachable!("we already short-circuited if we're server");
4669 };
4670 *token = packet.payload.freeze().split_to(token_len);
4671
4672 self.state = State::handshake(state::Handshake {
4673 expected_token: Bytes::new(),
4674 remote_cid_set: false,
4675 client_hello: None,
4676 allow_server_migration: self.config.server_handshake_migration,
4677 });
4678 Ok(())
4679 }
4680 Header::Long {
4681 ty: LongType::Handshake,
4682 src_cid: remote_cid,
4683 dst_cid: local_cid,
4684 ..
4685 } => {
4686 debug_assert_eq!(path_id, PathId::ZERO);
4687 if remote_cid != self.remote_handshake_cid {
4688 debug!(
4689 "discarding packet with mismatched remote CID: {} != {}",
4690 self.remote_handshake_cid, remote_cid
4691 );
4692 return Ok(());
4693 }
4694 self.on_path_validated(path_id);
4695
4696 self.process_early_payload(now, path_id, packet, qlog)?;
4697 if self.state.is_closed() {
4698 return Ok(());
4699 }
4700
4701 if self.crypto_state.session.is_handshaking() {
4702 trace!("handshake ongoing");
4703 return Ok(());
4704 }
4705
4706 if self.side.is_client() {
4707 let params = self
4709 .crypto_state
4710 .session
4711 .transport_parameters()?
4712 .ok_or_else(|| {
4713 TransportError::new(
4714 TransportErrorCode::crypto(0x6d),
4715 "transport parameters missing".to_owned(),
4716 )
4717 })?;
4718
4719 if self.has_0rtt() {
4720 if !self.crypto_state.session.early_data_accepted().unwrap() {
4721 debug_assert!(self.side.is_client());
4722 debug!("0-RTT rejected");
4723 self.crypto_state.accepted_0rtt = false;
4724 self.streams.zero_rtt_rejected();
4725
4726 self.spaces[SpaceId::Data].pending = Retransmits::default();
4728
4729 let sent_packets = mem::take(
4731 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets,
4732 );
4733 for (_, packet) in sent_packets.into_iter() {
4734 self.paths
4735 .get_mut(&path_id)
4736 .unwrap()
4737 .remove_in_flight(&packet);
4738 }
4739 } else {
4740 self.crypto_state.accepted_0rtt = true;
4741 params.validate_resumption_from(&self.peer_params)?;
4742 }
4743 }
4744 if let Some(token) = params.stateless_reset_token {
4745 let remote = self.path_data(path_id).network_path.remote;
4746 debug_assert!(!self.state.is_drained()); self.endpoint_events
4748 .push_back(EndpointEventInner::ResetToken(path_id, remote, token));
4749 }
4750 self.handle_peer_params(params, local_cid, remote_cid, now)?;
4751 self.issue_first_cids(now);
4752 } else {
4753 self.spaces[SpaceId::Data].pending.handshake_done = true;
4755 self.discard_space(now, SpaceKind::Handshake);
4756 self.events.push_back(Event::HandshakeConfirmed);
4757 trace!("handshake confirmed");
4758 }
4759
4760 self.events.push_back(Event::Connected);
4761 self.state.move_to_established();
4762 trace!("established");
4763
4764 self.issue_first_path_cids(now);
4767 self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
4768 Ok(())
4769 }
4770 Header::Initial(InitialHeader {
4771 src_cid: remote_cid,
4772 dst_cid: local_cid,
4773 ..
4774 }) => {
4775 debug_assert_eq!(path_id, PathId::ZERO);
4776 if !state.remote_cid_set {
4777 trace!("switching remote CID to {}", remote_cid);
4778 let mut state = state.clone();
4779 self.remote_cids
4780 .get_mut(&path_id)
4781 .expect("PathId::ZERO not yet abandoned")
4782 .update_initial_cid(remote_cid);
4783 self.remote_handshake_cid = remote_cid;
4784 self.original_remote_cid = remote_cid;
4785 state.remote_cid_set = true;
4786 self.state.move_to_handshake(state);
4787 } else if remote_cid != self.remote_handshake_cid {
4788 debug!(
4789 "discarding packet with mismatched remote CID: {} != {}",
4790 self.remote_handshake_cid, remote_cid
4791 );
4792 return Ok(());
4793 }
4794
4795 let starting_space = self.highest_space;
4796 self.process_early_payload(now, path_id, packet, qlog)?;
4797
4798 if self.side.is_server()
4799 && starting_space == SpaceKind::Initial
4800 && self.highest_space != SpaceKind::Initial
4801 {
4802 let params = self
4803 .crypto_state
4804 .session
4805 .transport_parameters()?
4806 .ok_or_else(|| {
4807 TransportError::new(
4808 TransportErrorCode::crypto(0x6d),
4809 "transport parameters missing".to_owned(),
4810 )
4811 })?;
4812 self.handle_peer_params(params, local_cid, remote_cid, now)?;
4813 self.issue_first_cids(now);
4814 self.init_0rtt(now);
4815 }
4816 Ok(())
4817 }
4818 Header::Long {
4819 ty: LongType::ZeroRtt,
4820 ..
4821 } => {
4822 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?;
4823 Ok(())
4824 }
4825 Header::VersionNegotiate { .. } => {
4826 if self.total_authed_packets > 1 {
4827 return Ok(());
4828 }
4829 let supported = packet
4830 .payload
4831 .chunks(4)
4832 .any(|x| match <[u8; 4]>::try_from(x) {
4833 Ok(version) => self.version == u32::from_be_bytes(version),
4834 Err(_) => false,
4835 });
4836 if supported {
4837 return Ok(());
4838 }
4839 debug!("remote doesn't support our version");
4840 Err(ConnectionError::VersionMismatch)
4841 }
4842 Header::Short { .. } => unreachable!(
4843 "short packets received during handshake are discarded in handle_packet"
4844 ),
4845 }
4846 }
4847
4848 fn process_early_payload(
4850 &mut self,
4851 now: Instant,
4852 path_id: PathId,
4853 packet: Packet,
4854 #[allow(unused)] qlog: &mut QlogRecvPacket,
4855 ) -> Result<(), TransportError> {
4856 debug_assert_ne!(packet.header.space(), SpaceKind::Data);
4857 debug_assert_eq!(path_id, PathId::ZERO);
4858 let payload_len = packet.payload.len();
4859 let mut ack_eliciting = false;
4860 for result in frame::Iter::new(packet.payload.freeze())? {
4861 let frame = result?;
4862 qlog.frame(&frame);
4863 let span = match frame {
4864 Frame::Padding => continue,
4865 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)),
4866 };
4867
4868 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4869
4870 let _guard = span.as_ref().map(|x| x.enter());
4871 ack_eliciting |= frame.is_ack_eliciting();
4872
4873 if frame.is_1rtt() && packet.header.space() != SpaceKind::Data {
4875 return Err(TransportError::PROTOCOL_VIOLATION(
4876 "illegal frame type in handshake",
4877 ));
4878 }
4879
4880 match frame {
4881 Frame::Padding | Frame::Ping => {}
4882 Frame::Crypto(frame) => {
4883 self.read_crypto(packet.header.space().into(), &frame, payload_len)?;
4884 }
4885 Frame::Ack(ack) => {
4886 self.on_ack_received(now, packet.header.space().into(), ack)?;
4887 }
4888 Frame::PathAck(ack) => {
4889 span.as_ref()
4890 .map(|span| span.record("path", tracing::field::display(&ack.path_id)));
4891 self.on_path_ack_received(now, packet.header.space().into(), ack)?;
4892 }
4893 Frame::Close(reason) => {
4894 self.state
4895 .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
4896 return Ok(());
4897 }
4898 _ => {
4899 let mut err =
4900 TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake");
4901 err.frame = frame::MaybeFrame::Known(frame.ty());
4902 return Err(err);
4903 }
4904 }
4905 }
4906
4907 if ack_eliciting {
4908 self.spaces[packet.header.space()]
4910 .for_path(path_id)
4911 .pending_acks
4912 .set_immediate_ack_required();
4913 }
4914
4915 self.write_crypto();
4916 Ok(())
4917 }
4918
4919 fn process_payload(
4921 &mut self,
4922 now: Instant,
4923 network_path: FourTuple,
4924 path_id: PathId,
4925 number: u64,
4926 packet: Packet,
4927 #[allow(unused)] qlog: &mut QlogRecvPacket,
4928 ) -> Result<(), TransportError> {
4929 let payload = packet.payload.freeze();
4930 let mut is_probing_packet = true;
4931 let mut close = None;
4932 let payload_len = payload.len();
4933 let mut ack_eliciting = false;
4934 let mut migration_observed_addr = None;
4937 for result in frame::Iter::new(payload)? {
4938 let frame = result?;
4939 qlog.frame(&frame);
4940 let span = match frame {
4941 Frame::Padding => continue,
4942 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty),
4943 };
4944
4945 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4946 match &frame {
4949 Frame::Crypto(f) => {
4950 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO");
4951 }
4952 Frame::Stream(f) => {
4953 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM");
4954 }
4955 Frame::Datagram(f) => {
4956 trace!(len = f.data.len(), "got frame DATAGRAM");
4957 }
4958 f => {
4959 trace!("got frame {f}");
4960 }
4961 }
4962
4963 let _guard = span.enter();
4964 if packet.header.is_0rtt() {
4965 match frame {
4966 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => {
4967 return Err(TransportError::PROTOCOL_VIOLATION(
4968 "illegal frame type in 0-RTT",
4969 ));
4970 }
4971 _ => {
4972 if frame.is_1rtt() {
4973 return Err(TransportError::PROTOCOL_VIOLATION(
4974 "illegal frame type in 0-RTT",
4975 ));
4976 }
4977 }
4978 }
4979 }
4980 ack_eliciting |= frame.is_ack_eliciting();
4981
4982 match frame {
4984 Frame::Padding
4985 | Frame::PathChallenge(_)
4986 | Frame::PathResponse(_)
4987 | Frame::NewConnectionId(_)
4988 | Frame::ObservedAddr(_) => {}
4989 _ => {
4990 is_probing_packet = false;
4991 }
4992 }
4993
4994 match frame {
4995 Frame::Crypto(frame) => {
4996 self.read_crypto(SpaceId::Data, &frame, payload_len)?;
4997 }
4998 Frame::Stream(frame) => {
4999 if self.streams.received(frame, payload_len)?.should_transmit() {
5000 self.spaces[SpaceId::Data].pending.max_data = true;
5001 }
5002 }
5003 Frame::Ack(ack) => {
5004 self.on_ack_received(now, SpaceId::Data, ack)?;
5005 }
5006 Frame::PathAck(ack) => {
5007 if !self.is_multipath_negotiated() {
5008 return Err(TransportError::PROTOCOL_VIOLATION(
5009 "received PATH_ACK frame when multipath was not negotiated",
5010 ));
5011 }
5012 span.record("path", tracing::field::display(&ack.path_id));
5013 self.on_path_ack_received(now, SpaceId::Data, ack)?;
5014 }
5015 Frame::Padding | Frame::Ping => {}
5016 Frame::Close(reason) => {
5017 close = Some(reason);
5018 }
5019 Frame::PathChallenge(challenge) => {
5020 self.spaces[SpaceKind::Data]
5021 .for_path(path_id)
5022 .pending_path_responses
5023 .push(number, challenge.0, network_path);
5024 let path = &mut self
5028 .path_mut(path_id)
5029 .expect("payload is processed only after the path becomes known");
5030 if network_path.remote == path.network_path.remote {
5031 match self.peer_supports_ack_frequency() {
5039 true => self.immediate_ack(path_id),
5040 false => {
5041 self.ping_path(path_id).ok();
5042 }
5043 }
5044 }
5045 }
5046 Frame::PathResponse(response) => {
5047 if self
5049 .n0_nat_traversal
5050 .handle_path_response(network_path, response.0)
5051 {
5052 self.open_nat_traversed_paths(now);
5053 } else {
5054 self.handle_path_response_on_path(now, response, path_id);
5056 }
5057 }
5058 Frame::MaxData(frame::MaxData(bytes)) => {
5059 self.streams.received_max_data(bytes);
5060 }
5061 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => {
5062 self.streams.received_max_stream_data(id, offset)?;
5063 }
5064 Frame::MaxStreams(frame::MaxStreams { dir, count }) => {
5065 self.streams.received_max_streams(dir, count)?;
5066 }
5067 Frame::ResetStream(frame) => {
5068 if self.streams.received_reset(frame)?.should_transmit() {
5069 self.spaces[SpaceId::Data].pending.max_data = true;
5070 }
5071 }
5072 Frame::DataBlocked(DataBlocked(offset)) => {
5073 debug!(offset, "peer claims to be blocked at connection level");
5074 }
5075 Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => {
5076 if id.initiator() == self.side.side() && id.dir() == Dir::Uni {
5077 debug!("got STREAM_DATA_BLOCKED on send-only {}", id);
5078 return Err(TransportError::STREAM_STATE_ERROR(
5079 "STREAM_DATA_BLOCKED on send-only stream",
5080 ));
5081 }
5082 debug!(
5083 stream = %id,
5084 offset, "peer claims to be blocked at stream level"
5085 );
5086 }
5087 Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => {
5088 if limit > MAX_STREAM_COUNT {
5089 return Err(TransportError::FRAME_ENCODING_ERROR(
5090 "unrepresentable stream limit",
5091 ));
5092 }
5093 debug!(
5094 "peer claims to be blocked opening more than {} {} streams",
5095 limit, dir
5096 );
5097 }
5098 Frame::StopSending(frame::StopSending { id, error_code }) => {
5099 if id.initiator() != self.side.side() {
5100 if id.dir() == Dir::Uni {
5101 debug!("got STOP_SENDING on recv-only {}", id);
5102 return Err(TransportError::STREAM_STATE_ERROR(
5103 "STOP_SENDING on recv-only stream",
5104 ));
5105 }
5106 } else if self.streams.is_local_unopened(id) {
5107 return Err(TransportError::STREAM_STATE_ERROR(
5108 "STOP_SENDING on unopened stream",
5109 ));
5110 }
5111 self.streams.received_stop_sending(id, error_code);
5112 }
5113 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => {
5114 if let Some(ref path_id) = path_id {
5115 span.record("path", tracing::field::display(&path_id));
5116 }
5117 let path_id = path_id.unwrap_or_default();
5118 match self.local_cid_state.get_mut(&path_id) {
5119 None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"),
5120 Some(cid_state) => {
5121 let allow_more_cids = cid_state
5122 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?;
5123
5124 let has_path = !self.abandoned_paths.contains(&path_id);
5128 let allow_more_cids = allow_more_cids && has_path;
5129
5130 debug_assert!(!self.state.is_drained()); self.endpoint_events
5132 .push_back(EndpointEventInner::RetireConnectionId(
5133 now,
5134 path_id,
5135 sequence,
5136 allow_more_cids,
5137 ));
5138 }
5139 }
5140 }
5141 Frame::NewConnectionId(frame) => {
5142 let path_id = if let Some(path_id) = frame.path_id {
5143 if !self.is_multipath_negotiated() {
5144 return Err(TransportError::PROTOCOL_VIOLATION(
5145 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated",
5146 ));
5147 }
5148 if path_id > self.local_max_path_id {
5149 return Err(TransportError::PROTOCOL_VIOLATION(
5150 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max",
5151 ));
5152 }
5153 path_id
5154 } else {
5155 PathId::ZERO
5156 };
5157
5158 if let Some(ref path_id) = frame.path_id {
5159 span.record("path", tracing::field::display(&path_id));
5160 }
5161
5162 if self.abandoned_paths.contains(&path_id) {
5163 trace!("ignoring issued CID for abandoned path");
5164 continue;
5165 }
5166 let remote_cids = self
5167 .remote_cids
5168 .entry(path_id)
5169 .or_insert_with(|| CidQueue::new(frame.id));
5170 if remote_cids.active().is_empty() {
5171 return Err(TransportError::PROTOCOL_VIOLATION(
5172 "NEW_CONNECTION_ID when CIDs aren't in use",
5173 ));
5174 }
5175 if frame.retire_prior_to > frame.sequence {
5176 return Err(TransportError::PROTOCOL_VIOLATION(
5177 "NEW_CONNECTION_ID retiring unissued CIDs",
5178 ));
5179 }
5180
5181 use crate::cid_queue::InsertError;
5182 match remote_cids.insert(frame) {
5183 Ok(None) => {
5184 self.open_nat_traversed_paths(now);
5185 }
5186 Ok(Some((retired, reset_token))) => {
5187 let pending_retired =
5188 &mut self.spaces[SpaceId::Data].pending.retire_cids;
5189 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10;
5192 if (pending_retired.len() as u64)
5195 .saturating_add(retired.end.saturating_sub(retired.start))
5196 > MAX_PENDING_RETIRED_CIDS
5197 {
5198 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(
5199 "queued too many retired CIDs",
5200 ));
5201 }
5202 pending_retired.extend(retired.map(|seq| (path_id, seq)));
5203 self.set_reset_token(path_id, network_path.remote, reset_token);
5204 self.open_nat_traversed_paths(now);
5205 }
5206 Err(InsertError::ExceedsLimit) => {
5207 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(""));
5208 }
5209 Err(InsertError::Retired) => {
5210 trace!("discarding already-retired");
5211 self.spaces[SpaceId::Data]
5215 .pending
5216 .retire_cids
5217 .push((path_id, frame.sequence));
5218 continue;
5219 }
5220 };
5221
5222 if self.side.is_server()
5223 && path_id == PathId::ZERO
5224 && self
5225 .remote_cids
5226 .get(&PathId::ZERO)
5227 .map(|cids| cids.active_seq() == 0)
5228 .unwrap_or_default()
5229 {
5230 self.update_remote_cid(PathId::ZERO);
5233 }
5234 }
5235 Frame::NewToken(NewToken { token }) => {
5236 let ConnectionSide::Client {
5237 token_store,
5238 server_name,
5239 ..
5240 } = &self.side
5241 else {
5242 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN"));
5243 };
5244 if token.is_empty() {
5245 return Err(TransportError::FRAME_ENCODING_ERROR("empty token"));
5246 }
5247 trace!("got new token");
5248 token_store.insert(server_name, token);
5249 }
5250 Frame::Datagram(datagram) => {
5251 if self
5252 .datagrams
5253 .received(datagram, &self.config.datagram_receive_buffer_size)?
5254 {
5255 self.events.push_back(Event::DatagramReceived);
5256 }
5257 }
5258 Frame::AckFrequency(ack_frequency) => {
5259 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? {
5262 continue;
5265 }
5266
5267 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() {
5269 space.pending_acks.set_ack_frequency_params(&ack_frequency);
5270
5271 if !self.abandoned_paths.contains(path_id)
5275 && let Some(timeout) = space
5276 .pending_acks
5277 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay)
5278 {
5279 self.timers.set(
5280 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
5281 timeout,
5282 self.qlog.with_time(now),
5283 );
5284 }
5285 }
5286 }
5287 Frame::ImmediateAck => {
5288 for pns in self.spaces[SpaceId::Data].iter_paths_mut() {
5290 pns.pending_acks.set_immediate_ack_required();
5291 }
5292 }
5293 Frame::HandshakeDone => {
5294 if self.side.is_server() {
5295 return Err(TransportError::PROTOCOL_VIOLATION(
5296 "client sent HANDSHAKE_DONE",
5297 ));
5298 }
5299 if self.crypto_state.has_keys(EncryptionLevel::Handshake) {
5300 self.discard_space(now, SpaceKind::Handshake);
5301 self.events.push_back(Event::HandshakeConfirmed);
5302 trace!("handshake confirmed");
5303 }
5304 }
5305 Frame::ObservedAddr(observed) => {
5306 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port);
5308 if !self
5309 .peer_params
5310 .address_discovery_role
5311 .should_report(&self.config.address_discovery_role)
5312 {
5313 return Err(TransportError::PROTOCOL_VIOLATION(
5314 "received OBSERVED_ADDRESS frame when not negotiated",
5315 ));
5316 }
5317 if packet.header.space() != SpaceKind::Data {
5319 return Err(TransportError::PROTOCOL_VIOLATION(
5320 "OBSERVED_ADDRESS frame outside data space",
5321 ));
5322 }
5323
5324 let space_open_status =
5325 self.spaces[SpaceKind::Data].for_path(path_id).open_status;
5326 let path = self.path_data_mut(path_id);
5327 if path.network_path.remote == network_path.remote {
5328 if let Some(updated) = path.update_observed_addr_report(observed)
5329 && space_open_status == OpenStatus::Informed
5330 {
5331 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5332 id: path_id,
5333 addr: updated,
5334 }));
5335 }
5337 } else {
5338 migration_observed_addr = Some(observed)
5340 }
5341 }
5342 Frame::PathAbandon(frame::PathAbandon {
5343 path_id,
5344 error_code,
5345 }) => {
5346 span.record("path", tracing::field::display(&path_id));
5347 match self.close_path_inner(
5348 now,
5349 path_id,
5350 PathAbandonReason::RemoteAbandoned {
5351 error_code: error_code.into(),
5352 },
5353 ) {
5354 Ok(()) => {
5355 trace!("peer abandoned path");
5356 }
5357 Err(ClosePathError::ClosedPath) => {
5358 trace!("peer abandoned already closed path");
5359 }
5360 Err(ClosePathError::MultipathNotNegotiated) => {
5361 return Err(TransportError::PROTOCOL_VIOLATION(
5362 "received PATH_ABANDON frame when multipath was not negotiated",
5363 ));
5364 }
5365 Err(ClosePathError::LastOpenPath) => {
5366 error!(
5369 "peer abandoned last path but close_path_inner returned LastOpenPath"
5370 );
5371 }
5372 };
5373
5374 if let Some(path) = self.paths.get_mut(&path_id)
5376 && !mem::replace(&mut path.data.draining, true)
5377 {
5378 let ack_delay = self.ack_frequency.max_ack_delay_for_pto();
5379 let pto = path.data.rtt.pto_base() + ack_delay;
5380 self.timers.set(
5381 Timer::PerPath(path_id, PathTimer::PathDrained),
5382 now + 3 * pto,
5383 self.qlog.with_time(now),
5384 );
5385
5386 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8));
5387 }
5388 }
5389 Frame::PathStatusAvailable(info) => {
5390 span.record("path", tracing::field::display(&info.path_id));
5391 if self.is_multipath_negotiated() {
5392 self.on_path_status(
5393 info.path_id,
5394 PathStatus::Available,
5395 info.status_seq_no,
5396 );
5397 } else {
5398 return Err(TransportError::PROTOCOL_VIOLATION(
5399 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated",
5400 ));
5401 }
5402 }
5403 Frame::PathStatusBackup(info) => {
5404 span.record("path", tracing::field::display(&info.path_id));
5405 if self.is_multipath_negotiated() {
5406 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no);
5407 } else {
5408 return Err(TransportError::PROTOCOL_VIOLATION(
5409 "received PATH_STATUS_BACKUP frame when multipath was not negotiated",
5410 ));
5411 }
5412 }
5413 Frame::MaxPathId(frame::MaxPathId(path_id)) => {
5414 span.record("path", tracing::field::display(&path_id));
5415 if !self.is_multipath_negotiated() {
5416 return Err(TransportError::PROTOCOL_VIOLATION(
5417 "received MAX_PATH_ID frame when multipath was not negotiated",
5418 ));
5419 }
5420 if path_id > self.remote_max_path_id {
5422 self.remote_max_path_id = path_id;
5423 self.issue_first_path_cids(now);
5424 self.open_nat_traversed_paths(now);
5425 }
5426 }
5427 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => {
5428 if self.is_multipath_negotiated() {
5433 if max_path_id > self.local_max_path_id {
5434 return Err(TransportError::PROTOCOL_VIOLATION(
5435 "PATHS_BLOCKED maximum path identifier was larger than local maximum",
5436 ));
5437 }
5438 } else {
5439 return Err(TransportError::PROTOCOL_VIOLATION(
5440 "received PATHS_BLOCKED frame when not multipath was not negotiated",
5441 ));
5442 }
5443 }
5444 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => {
5445 if self.is_multipath_negotiated() {
5454 if path_id > self.local_max_path_id {
5455 return Err(TransportError::PROTOCOL_VIOLATION(
5456 "PATH_CIDS_BLOCKED path identifier was larger than local maximum",
5457 ));
5458 }
5459 if self
5460 .local_cid_state
5461 .get(&path_id)
5462 .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1)
5466 {
5467 return Err(TransportError::PROTOCOL_VIOLATION(
5468 "PATH_CIDS_BLOCKED next sequence number larger than in local state",
5469 ));
5470 }
5471 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED");
5472 } else {
5473 return Err(TransportError::PROTOCOL_VIOLATION(
5474 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated",
5475 ));
5476 }
5477 }
5478 Frame::AddAddress(addr) => {
5479 let client_state = match self.n0_nat_traversal.client_side_mut() {
5480 Ok(state) => state,
5481 Err(err) => {
5482 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5483 "Nat traversal(ADD_ADDRESS): {err}"
5484 )));
5485 }
5486 };
5487
5488 if !client_state.check_remote_address(&addr) {
5489 warn!(?addr, "server sent illegal ADD_ADDRESS frame");
5491 }
5492
5493 match client_state.add_remote_address(addr) {
5494 Ok(maybe_added) => {
5495 if let Some(added) = maybe_added {
5496 self.events.push_back(Event::NatTraversal(
5497 n0_nat_traversal::Event::AddressAdded(added),
5498 ));
5499 }
5500 }
5501 Err(e) => {
5502 warn!(%e, "failed to add remote address")
5503 }
5504 }
5505 }
5506 Frame::RemoveAddress(addr) => {
5507 let client_state = match self.n0_nat_traversal.client_side_mut() {
5508 Ok(state) => state,
5509 Err(err) => {
5510 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5511 "Nat traversal(REMOVE_ADDRESS): {err}"
5512 )));
5513 }
5514 };
5515 if let Some(removed_addr) = client_state.remove_remote_address(addr) {
5516 self.events.push_back(Event::NatTraversal(
5517 n0_nat_traversal::Event::AddressRemoved(removed_addr),
5518 ));
5519 }
5520 }
5521 Frame::ReachOut(reach_out) => {
5522 let ipv6 = self.is_ipv6();
5523 let server_state = match self.n0_nat_traversal.server_side_mut() {
5524 Ok(state) => state,
5525 Err(err) => {
5526 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5527 "Nat traversal(REACH_OUT): {err}"
5528 )));
5529 }
5530 };
5531
5532 let round_before = server_state.current_round();
5533
5534 if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) {
5535 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5536 "Nat traversal(REACH_OUT): {err}"
5537 )));
5538 }
5539
5540 if server_state.current_round() > round_before {
5541 if let Some(delay) =
5543 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
5544 {
5545 self.timers.set(
5546 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
5547 now + delay,
5548 self.qlog.with_time(now),
5549 );
5550 }
5551 }
5552 }
5553 }
5554 }
5555
5556 let space = self.spaces[SpaceId::Data].for_path(path_id);
5557 if space
5558 .pending_acks
5559 .packet_received(now, number, ack_eliciting, &space.dedup)
5560 {
5561 if self.abandoned_paths.contains(&path_id) {
5562 space.pending_acks.set_immediate_ack_required();
5565 } else {
5566 self.timers.set(
5567 Timer::PerPath(path_id, PathTimer::MaxAckDelay),
5568 now + self.ack_frequency.max_ack_delay,
5569 self.qlog.with_time(now),
5570 );
5571 }
5572 }
5573
5574 let pending = &mut self.spaces[SpaceId::Data].pending;
5579 self.streams.queue_max_stream_id(pending);
5580
5581 if let Some(reason) = close {
5582 self.state
5583 .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
5584 self.connection_close_pending = true;
5585 }
5586
5587 let migrate_on_any_packet =
5590 self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated();
5591
5592 let is_largest_received_pn = Some(number)
5594 == self.spaces[SpaceId::Data]
5595 .for_path(path_id)
5596 .largest_received_packet_number;
5597
5598 if (migrate_on_any_packet || !is_probing_packet)
5603 && is_largest_received_pn
5604 && self.local_ip_may_migrate()
5605 && let Some(new_local_ip) = network_path.local_ip
5606 {
5607 let path_data = self.path_data_mut(path_id);
5608 if path_data
5609 .network_path
5610 .local_ip
5611 .is_some_and(|ip| ip != new_local_ip)
5612 {
5613 debug!(
5614 %path_id,
5615 new_4tuple = %network_path,
5616 prev_4tuple = %path_data.network_path,
5617 "local address passive migration"
5618 );
5619 }
5620 path_data.network_path.local_ip = Some(new_local_ip)
5621 }
5622
5623 if self.peer_may_migrate()
5625 && (migrate_on_any_packet || !is_probing_packet)
5626 && is_largest_received_pn
5627 && network_path.remote != self.path_data(path_id).network_path.remote
5628 {
5629 self.migrate(path_id, now, network_path, migration_observed_addr);
5630 self.update_remote_cid(path_id);
5632 self.spin = false;
5633 }
5634
5635 Ok(())
5636 }
5637
5638 fn handle_path_response_on_path(
5642 &mut self,
5643 now: Instant,
5644 response: frame::PathResponse,
5645 path_id: PathId,
5646 ) {
5647 let is_multipath_negotiated = self.is_multipath_negotiated();
5648 let path = self
5649 .paths
5650 .get_mut(&path_id)
5651 .expect("payload is processed only after the path becomes known");
5652 match path.data.on_path_response_received(now, response.0) {
5653 paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => {
5654 let qlog = self.qlog.with_time(now);
5655 self.timers.stop(
5656 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5657 qlog.clone(),
5658 );
5659 let next_challenge = path
5660 .data
5661 .earliest_on_path_expiring_challenge()
5662 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto());
5663 self.timers.set_or_stop(
5664 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
5665 next_challenge,
5666 qlog,
5667 );
5668 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
5669 if !matches!(pns.open_status, OpenStatus::Informed) {
5670 if is_multipath_negotiated {
5671 self.events
5672 .push_back(Event::Path(PathEvent::Established { id: path_id }));
5673 }
5674 pns.open_status = OpenStatus::Informed;
5675 if let Some(observed) = path.data.last_observed_addr_report.as_ref() {
5676 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5677 id: path_id,
5678 addr: observed.socket_addr(),
5679 }));
5680 }
5681 }
5682 if let Some((_, ref mut prev)) = path.prev {
5683 prev.reset_on_path_challenges();
5688 }
5689 }
5690 paths::OnPathResponseReceived::OnPath => {
5691 trace!(
5692 %response,
5693 "ignoring PATH_RESPONSE received after path is abandoned"
5694 );
5695 }
5696 paths::OnPathResponseReceived::Unknown => {
5697 debug!(%response, "ignoring invalid PATH_RESPONSE");
5698 }
5699 paths::OnPathResponseReceived::Ignored {
5700 sent_on,
5701 current_path,
5702 } => {
5703 debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE");
5704 }
5705 }
5706 }
5707
5708 fn open_nat_traversed_paths(&mut self, now: Instant) {
5710 while let Some(network_path) = self
5711 .n0_nat_traversal
5712 .client_side_mut()
5713 .ok()
5714 .and_then(|s| s.pop_pending_path_open())
5715 {
5716 match self.open_path_ensure(network_path, PathStatus::Backup, now) {
5717 Ok((path_id, already_existed)) => {
5718 debug!(
5719 %path_id,
5720 ?network_path,
5721 new_path = !already_existed,
5722 "Opened NAT traversal path",
5723 );
5724 }
5725 Err(err) => match err {
5726 PathError::MultipathNotNegotiated
5727 | PathError::ServerSideNotAllowed
5728 | PathError::ValidationFailed
5729 | PathError::InvalidRemoteAddress(_) => {
5730 error!(
5731 ?err,
5732 ?network_path,
5733 "Failed to open path for successful NAT traversal"
5734 );
5735 }
5736 PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => {
5737 self.n0_nat_traversal
5739 .client_side_mut()
5740 .map(|s| s.push_pending_path_open(network_path))
5741 .ok();
5742 debug!(
5743 ?err,
5744 ?network_path,
5745 "Blocked opening NAT traversal path, enqueued"
5746 );
5747 return;
5748 }
5749 },
5750 }
5751 }
5752 }
5753
5754 fn migrate(
5759 &mut self,
5760 path_id: PathId,
5761 now: Instant,
5762 network_path: FourTuple,
5763 observed_addr: Option<ObservedAddr>,
5764 ) {
5765 trace!(
5766 new_4tuple = %network_path,
5767 prev_4tuple = %self.path_data(path_id).network_path,
5768 %path_id,
5769 "migration initiated",
5770 );
5771 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
5772 let prev_pto = self.pto(SpaceKind::Data, path_id);
5779 let path = self.paths.get_mut(&path_id).expect("known path");
5780 let mut new_path_data = if network_path.remote.is_ipv4()
5781 && network_path.remote.ip() == path.data.network_path.remote.ip()
5782 {
5783 PathData::from_previous(network_path, &path.data, self.path_generation_counter, now)
5784 } else {
5785 let peer_max_udp_payload_size =
5786 u16::try_from(self.peer_params.max_udp_payload_size.into_inner())
5787 .unwrap_or(u16::MAX);
5788 PathData::new(
5789 network_path,
5790 self.allow_mtud,
5791 Some(peer_max_udp_payload_size),
5792 self.path_generation_counter,
5793 now,
5794 &self.config,
5795 )
5796 };
5797 new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone();
5798 if let Some(report) = observed_addr
5799 && let Some(updated) = new_path_data.update_observed_addr_report(report)
5800 {
5801 tracing::info!("adding observed addr event from migration");
5802 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5803 id: path_id,
5804 addr: updated,
5805 }));
5806 }
5807 new_path_data.pending_challenge = true;
5808 new_path_data.pending.observed_address = self
5809 .config
5810 .address_discovery_role
5811 .should_report(&self.peer_params.address_discovery_role);
5812
5813 let mut prev_path_data = mem::replace(&mut path.data, new_path_data);
5814
5815 if !prev_path_data.validated
5824 && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active)
5825 {
5826 prev_path_data.pending_challenge = true;
5827 path.prev = Some((cid, prev_path_data));
5830 }
5831
5832 self.qlog.emit_tuple_assigned(path_id, network_path, now);
5834
5835 self.timers.set(
5836 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5837 now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto),
5838 self.qlog.with_time(now),
5839 );
5840 }
5841
5842 pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) {
5859 debug!("network changed");
5860 if self.state.is_drained() {
5861 return;
5862 }
5863 if self.highest_space < SpaceKind::Data {
5864 for path in self.paths.values_mut() {
5865 path.data.network_path.local_ip = None;
5867 }
5868
5869 self.update_remote_cid(PathId::ZERO);
5870 self.ping();
5871
5872 return;
5873 }
5874
5875 let mut non_recoverable_paths = Vec::default();
5878 let mut recoverable_paths = Vec::default();
5879 let mut open_paths = 0;
5880
5881 let is_multipath_negotiated = self.is_multipath_negotiated();
5882 let is_client = self.side().is_client();
5883 let immediate_ack_allowed = self.peer_supports_ack_frequency();
5884
5885 for (path_id, path) in self.paths.iter_mut() {
5886 if self.abandoned_paths.contains(path_id) {
5887 continue;
5888 }
5889 open_paths += 1;
5890
5891 let network_path = path.data.network_path;
5894
5895 path.data.network_path.local_ip = None;
5898 let remote = network_path.remote;
5899
5900 let attempt_to_recover = if is_multipath_negotiated {
5904 hint.map(|h| h.is_path_recoverable(*path_id, network_path))
5908 .unwrap_or(!is_client)
5909 } else {
5910 true
5912 };
5913
5914 if attempt_to_recover {
5915 recoverable_paths.push((*path_id, remote));
5916 } else {
5917 non_recoverable_paths.push((*path_id, remote, path.data.local_status()))
5918 }
5919 }
5920
5921 let open_first = open_paths == non_recoverable_paths.len();
5930
5931 for (path_id, remote, status) in non_recoverable_paths.into_iter() {
5932 let network_path = FourTuple {
5933 remote,
5934 local_ip: None, };
5936
5937 if open_first && let Err(e) = self.open_path(network_path, status, now) {
5938 if self.side().is_client() {
5939 debug!(%e, "Failed to open new path for network change");
5940 }
5941 recoverable_paths.push((path_id, remote));
5943 continue;
5944 }
5945
5946 if let Err(e) =
5947 self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange)
5948 {
5949 debug!(%e,"Failed to close unrecoverable path after network change");
5950 recoverable_paths.push((path_id, remote));
5951 continue;
5952 }
5953
5954 if !open_first && let Err(e) = self.open_path(network_path, status, now) {
5955 debug!(%e,"Failed to open new path for network change");
5959 }
5960 }
5961
5962 for (path_id, remote) in recoverable_paths.into_iter() {
5965 if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) {
5967 path_space.pending_ping = true;
5968
5969 if immediate_ack_allowed {
5970 path_space.pending_immediate_ack = true;
5971 }
5972 }
5973
5974 if let Some(path) = self.paths.get_mut(&path_id) {
5979 path.data.pto_count = 0;
5980 }
5981 self.set_loss_detection_timer(now, path_id);
5982
5983 let Some((reset_token, retired)) =
5984 self.remote_cids.get_mut(&path_id).and_then(CidQueue::next)
5985 else {
5986 continue;
5987 };
5988
5989 self.spaces[SpaceId::Data]
5991 .pending
5992 .retire_cids
5993 .extend(retired.map(|seq| (path_id, seq)));
5994
5995 debug_assert!(!self.state.is_drained()); self.endpoint_events
5997 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
5998 }
5999 }
6000
6001 fn update_remote_cid(&mut self, path_id: PathId) {
6003 let Some((reset_token, retired)) = self
6004 .remote_cids
6005 .get_mut(&path_id)
6006 .and_then(|cids| cids.next())
6007 else {
6008 return;
6009 };
6010
6011 self.spaces[SpaceId::Data]
6013 .pending
6014 .retire_cids
6015 .extend(retired.map(|seq| (path_id, seq)));
6016 let remote = self.path_data(path_id).network_path.remote;
6017 self.set_reset_token(path_id, remote, reset_token);
6018 }
6019
6020 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) {
6029 debug_assert!(!self.state.is_drained()); self.endpoint_events
6031 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
6032
6033 if path_id == PathId::ZERO {
6039 self.peer_params.stateless_reset_token = Some(reset_token);
6040 }
6041 }
6042
6043 fn issue_first_cids(&mut self, now: Instant) {
6045 if self
6046 .local_cid_state
6047 .get(&PathId::ZERO)
6048 .expect("PathId::ZERO exists when the connection is created")
6049 .cid_len()
6050 == 0
6051 {
6052 return;
6053 }
6054
6055 let mut n = self.peer_params.issue_cids_limit() - 1;
6057 if let ConnectionSide::Server { server_config } = &self.side
6058 && server_config.has_preferred_address()
6059 {
6060 n -= 1;
6062 }
6063 debug_assert!(!self.state.is_drained()); self.endpoint_events
6065 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6066 }
6067
6068 fn issue_first_path_cids(&mut self, now: Instant) {
6072 if let Some(max_path_id) = self.max_path_id() {
6073 let mut path_id = self.max_path_id_with_cids.next();
6074 while path_id <= max_path_id {
6075 self.endpoint_events
6076 .push_back(EndpointEventInner::NeedIdentifiers(
6077 path_id,
6078 now,
6079 self.peer_params.issue_cids_limit(),
6080 ));
6081 path_id = path_id.next();
6082 }
6083 self.max_path_id_with_cids = max_path_id;
6084 }
6085 }
6086
6087 fn populate_packet<'a, 'b>(
6095 &mut self,
6096 now: Instant,
6097 space_id: SpaceId,
6098 path_id: PathId,
6099 scheduling_info: &PathSchedulingInfo,
6100 builder: &mut PacketBuilder<'a, 'b>,
6101 ) {
6102 let is_multipath_negotiated = self.is_multipath_negotiated();
6103 let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level());
6104 let is_0rtt = space_id == SpaceId::Data && !space_has_keys;
6105 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
6106 let space = &mut self.spaces[space_id];
6107 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6108 space
6109 .for_path(path_id)
6110 .pending_acks
6111 .maybe_ack_non_eliciting();
6112
6113 if !is_0rtt
6115 && !scheduling_info.is_abandoned
6116 && scheduling_info.may_send_data
6117 && mem::replace(&mut space.pending.handshake_done, false)
6118 {
6119 builder.write_frame(frame::HandshakeDone, stats);
6120 }
6121
6122 if !scheduling_info.is_abandoned
6124 && mem::replace(&mut space.for_path(path_id).pending_ping, false)
6125 {
6126 builder.write_frame(frame::Ping, stats);
6127 }
6128
6129 if !scheduling_info.is_abandoned
6131 && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false)
6132 {
6133 debug_assert_eq!(
6134 space_id,
6135 SpaceId::Data,
6136 "immediate acks must be sent in the data space"
6137 );
6138 builder.write_frame(frame::ImmediateAck, stats);
6139 }
6140
6141 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6143 for path_id in space
6144 .number_spaces
6145 .iter_mut()
6146 .filter(|(_, pns)| pns.pending_acks.can_send())
6147 .map(|(&path_id, _)| path_id)
6148 .collect::<Vec<_>>()
6149 {
6150 Self::populate_acks(
6151 now,
6152 self.receiving_ecn,
6153 path_id,
6154 space_id,
6155 space,
6156 is_multipath_negotiated,
6157 builder,
6158 stats,
6159 space_has_keys,
6160 );
6161 }
6162 }
6163
6164 if !scheduling_info.is_abandoned
6166 && scheduling_info.may_send_data
6167 && mem::replace(&mut space.pending.ack_frequency, false)
6168 {
6169 let sequence_number = self.ack_frequency.next_sequence_number();
6170
6171 let config = self.config.ack_frequency_config.as_ref().unwrap();
6173
6174 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay(
6176 path.rtt.get(),
6177 config,
6178 &self.peer_params,
6179 );
6180
6181 let frame = frame::AckFrequency {
6182 sequence: sequence_number,
6183 ack_eliciting_threshold: config.ack_eliciting_threshold,
6184 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX),
6185 reordering_threshold: config.reordering_threshold,
6186 };
6187 builder.write_frame(frame, stats);
6188
6189 self.ack_frequency
6190 .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay);
6191 path.congestion.on_ack_frequency_update(
6192 config.ack_eliciting_threshold.into_inner(),
6193 max_ack_delay,
6194 );
6195 }
6196
6197 if !scheduling_info.is_abandoned
6199 && space_id == SpaceId::Data
6200 && path.pending_challenge
6201 && !self.state.is_closed()
6203 && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND
6204 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6207 {
6208 path.pending_challenge = false;
6209
6210 let token = self.rng.random();
6211 path.record_path_challenge_sent(now, token, path.network_path);
6212 let challenge = frame::PathChallenge(token);
6214 builder.write_frame(challenge, stats);
6215 builder.require_padding();
6216
6217 self.timers.set(
6222 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
6223 now + path.on_path_challenge_pto(),
6224 self.qlog.with_time(now),
6225 );
6226
6227 if is_multipath_negotiated && !path.validated && path.pending_challenge {
6228 space.pending.path_status.insert(path_id);
6230 }
6231
6232 path.pending.observed_address = self
6235 .config
6236 .address_discovery_role
6237 .should_report(&self.peer_params.address_discovery_role);
6238 }
6239
6240 if !scheduling_info.is_abandoned
6242 && space_id == SpaceId::Data
6243 && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND
6244 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6247 && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path)
6248 {
6249 let response = frame::PathResponse(token);
6250 builder.write_frame(response, stats);
6251 builder.require_padding();
6252
6253 path.pending.observed_address = self
6257 .config
6258 .address_discovery_role
6259 .should_report(&self.peer_params.address_discovery_role);
6260 }
6261
6262 while space_id == SpaceId::Data
6264 && !scheduling_info.is_abandoned
6265 && scheduling_info.may_send_data
6266 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining()
6267 {
6268 if let Some(added_address) = space.pending.add_address.pop_last() {
6269 builder.write_frame(added_address, stats);
6270 } else {
6271 break;
6272 }
6273 }
6274
6275 while space_id == SpaceId::Data
6277 && !scheduling_info.is_abandoned
6278 && scheduling_info.may_send_data
6279 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining()
6280 {
6281 if let Some(removed_address) = space.pending.remove_address.pop_last() {
6282 builder.write_frame(removed_address, stats);
6283 } else {
6284 break;
6285 }
6286 }
6287
6288 while !scheduling_info.is_abandoned
6290 && scheduling_info.may_send_data
6291 && let Some(reach_out) = space
6292 .pending
6293 .reach_out
6294 .pop_if(|frame| builder.frame_space_remaining() >= frame.size())
6295 {
6296 builder.write_frame(reach_out, stats);
6297 }
6298
6299 if space_id == SpaceId::Data
6301 && scheduling_info.is_abandoned
6302 && scheduling_info.may_self_abandon
6303 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6304 && let Some(error_code) = space.pending.path_abandon.remove(&path_id)
6305 {
6306 let frame = frame::PathAbandon {
6307 path_id,
6308 error_code,
6309 };
6310 builder.write_frame(frame, stats);
6311
6312 self.remote_cids.remove(&path_id);
6315 }
6316 while space_id == SpaceId::Data
6317 && scheduling_info.may_send_data
6318 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6319 && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first()
6320 {
6321 let frame = frame::PathAbandon {
6322 path_id: abandoned_path_id,
6323 error_code,
6324 };
6325 builder.write_frame(frame, stats);
6326
6327 self.remote_cids.remove(&abandoned_path_id);
6330 }
6331
6332 if !scheduling_info.is_abandoned
6334 && space_id == SpaceId::Data
6335 && path.pending.observed_address
6336 {
6337 let frame = ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no);
6338 if builder.frame_space_remaining() > frame.size() {
6339 builder.write_frame(frame, stats);
6340
6341 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8);
6342 path.pending.observed_address = false;
6343 }
6344 }
6345
6346 while !is_0rtt
6348 && !scheduling_info.is_abandoned
6349 && scheduling_info.may_send_data
6350 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND
6351 {
6352 let Some(mut frame) = space.pending.crypto.pop_front() else {
6353 break;
6354 };
6355
6356 let max_crypto_data_size = builder.frame_space_remaining()
6361 - 1 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) })
6363 - 2; let len = frame
6366 .data
6367 .len()
6368 .min(2usize.pow(14) - 1)
6369 .min(max_crypto_data_size);
6370
6371 let data = frame.data.split_to(len);
6372 let offset = frame.offset;
6373 let truncated = frame::Crypto { offset, data };
6374 builder.write_frame(truncated, stats);
6375
6376 if !frame.data.is_empty() {
6377 frame.offset += len as u64;
6378 space.pending.crypto.push_front(frame);
6379 }
6380 }
6381
6382 while space_id == SpaceId::Data
6384 && !scheduling_info.is_abandoned
6385 && scheduling_info.may_send_data
6386 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining()
6387 {
6388 let Some(path_id) = space.pending.path_status.pop_first() else {
6389 break;
6390 };
6391 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else {
6392 trace!(%path_id, "discarding queued path status for unknown path");
6393 continue;
6394 };
6395
6396 let seq = path.status.seq();
6397 match path.local_status() {
6398 PathStatus::Available => {
6399 let frame = frame::PathStatusAvailable {
6400 path_id,
6401 status_seq_no: seq,
6402 };
6403 builder.write_frame(frame, stats);
6404 }
6405 PathStatus::Backup => {
6406 let frame = frame::PathStatusBackup {
6407 path_id,
6408 status_seq_no: seq,
6409 };
6410 builder.write_frame(frame, stats);
6411 }
6412 }
6413 }
6414
6415 if space_id == SpaceId::Data
6417 && !scheduling_info.is_abandoned
6418 && scheduling_info.may_send_data
6419 && space.pending.max_path_id
6420 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining()
6421 {
6422 let frame = frame::MaxPathId(self.local_max_path_id);
6423 builder.write_frame(frame, stats);
6424 space.pending.max_path_id = false;
6425 }
6426
6427 if space_id == SpaceId::Data
6429 && !scheduling_info.is_abandoned
6430 && scheduling_info.may_send_data
6431 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6432 && let Some(remote_max_path_id) = space.pending.paths_blocked.take()
6433 {
6434 let frame = frame::PathsBlocked(remote_max_path_id);
6435 builder.write_frame(frame, stats);
6436 }
6437
6438 while space_id == SpaceId::Data
6440 && !scheduling_info.is_abandoned
6441 && scheduling_info.may_send_data
6442 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6443 {
6444 let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else {
6445 break;
6446 };
6447 let frame = frame::PathCidsBlocked { path_id, next_seq };
6448 builder.write_frame(frame, stats);
6449 }
6450
6451 if space_id == SpaceId::Data
6453 && !scheduling_info.is_abandoned
6454 && scheduling_info.may_send_data
6455 {
6456 self.streams
6457 .write_control_frames(builder, &mut space.pending, stats);
6458 }
6459
6460 let cid_len = self
6462 .local_cid_state
6463 .values()
6464 .map(|cid_state| cid_state.cid_len())
6465 .max()
6466 .expect("some local CID state must exist");
6467 let new_cid_size_bound =
6468 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len);
6469 while !scheduling_info.is_abandoned
6470 && scheduling_info.may_send_data
6471 && builder.frame_space_remaining() > new_cid_size_bound
6472 {
6473 let Some(issued) = space.pending.new_cids.pop() else {
6474 break;
6475 };
6476 let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else {
6478 debug!(
6479 path = %issued.path_id, seq = issued.sequence,
6480 "dropping queued NEW_CONNECTION_ID for discarded path",
6481 );
6482 continue;
6483 };
6484 let retire_prior_to = cid_state.retire_prior_to();
6485
6486 let cid_path_id = match is_multipath_negotiated {
6487 true => Some(issued.path_id),
6488 false => {
6489 debug_assert_eq!(issued.path_id, PathId::ZERO);
6490 None
6491 }
6492 };
6493 let frame = frame::NewConnectionId {
6494 path_id: cid_path_id,
6495 sequence: issued.sequence,
6496 retire_prior_to,
6497 id: issued.id,
6498 reset_token: issued.reset_token,
6499 };
6500 builder.write_frame(frame, stats);
6501 }
6502
6503 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated);
6505 while !scheduling_info.is_abandoned
6506 && scheduling_info.may_send_data
6507 && builder.frame_space_remaining() > retire_cid_bound
6508 {
6509 let (path_id, sequence) = match space.pending.retire_cids.pop() {
6510 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq),
6511 Some((path_id, seq)) => (Some(path_id), seq),
6512 None => break,
6513 };
6514 let frame = frame::RetireConnectionId { path_id, sequence };
6515 builder.write_frame(frame, stats);
6516 }
6517
6518 let mut sent_datagrams = false;
6520 while !scheduling_info.is_abandoned
6521 && scheduling_info.may_send_data
6522 && builder.frame_space_remaining() > Datagram::SIZE_BOUND
6523 && space_id == SpaceId::Data
6524 {
6525 match self.datagrams.write(builder, stats) {
6526 true => {
6527 sent_datagrams = true;
6528 }
6529 false => break,
6530 }
6531 }
6532 if self.datagrams.send_blocked && sent_datagrams {
6533 self.events.push_back(Event::DatagramsUnblocked);
6534 self.datagrams.send_blocked = false;
6535 }
6536
6537 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6538
6539 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6541 while let Some(network_path) = space.pending.new_tokens.pop() {
6542 debug_assert_eq!(space_id, SpaceId::Data);
6543 let ConnectionSide::Server { server_config } = &self.side else {
6544 panic!("NEW_TOKEN frames should not be enqueued by clients");
6545 };
6546
6547 if !network_path.is_probably_same_path(&path.network_path) {
6548 continue;
6553 }
6554
6555 let token = Token::new(
6556 TokenPayload::Validation {
6557 ip: network_path.remote.ip(),
6558 issued: server_config.time_source.now(),
6559 },
6560 &mut self.rng,
6561 );
6562 let new_token = NewToken {
6563 token: token.encode(&*server_config.token_key).into(),
6564 };
6565
6566 if builder.frame_space_remaining() < new_token.size() {
6567 space.pending.new_tokens.push(network_path);
6568 break;
6569 }
6570
6571 builder.write_frame(new_token, stats);
6572 builder.retransmits_mut().new_tokens.push(network_path);
6573 }
6574 }
6575
6576 if !scheduling_info.is_abandoned
6578 && scheduling_info.may_send_data
6579 && space_id == SpaceId::Data
6580 {
6581 self.streams
6582 .write_stream_frames(builder, self.config.send_fairness, stats);
6583 }
6584 }
6585
6586 fn populate_acks<'a, 'b>(
6588 now: Instant,
6589 receiving_ecn: bool,
6590 path_id: PathId,
6591 space_id: SpaceId,
6592 space: &mut PacketSpace,
6593 is_multipath_negotiated: bool,
6594 builder: &mut PacketBuilder<'a, 'b>,
6595 stats: &mut FrameStats,
6596 space_has_keys: bool,
6597 ) {
6598 debug_assert!(space_has_keys, "tried to send ACK in 0-RTT");
6600
6601 debug_assert!(
6602 is_multipath_negotiated || path_id == PathId::ZERO,
6603 "Only PathId::ZERO allowed without multipath (have {path_id:?})"
6604 );
6605 if is_multipath_negotiated {
6606 debug_assert!(
6607 space_id == SpaceId::Data || path_id == PathId::ZERO,
6608 "path acks must be sent in 1RTT space (have {space_id:?})"
6609 );
6610 }
6611
6612 let pns = space.for_path(path_id);
6613 let ranges = pns.pending_acks.ranges();
6614 debug_assert!(!ranges.is_empty(), "can not send empty ACK range");
6615 let ecn = if receiving_ecn {
6616 Some(&pns.ecn_counters)
6617 } else {
6618 None
6619 };
6620
6621 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64;
6622 let ack_delay_exp = TransportParameters::default().ack_delay_exponent;
6624 let delay = delay_micros >> ack_delay_exp.into_inner();
6625
6626 if is_multipath_negotiated && space_id == SpaceId::Data {
6627 if !ranges.is_empty() {
6628 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn);
6629 builder.write_frame(frame, stats);
6630 }
6631 } else {
6632 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats);
6633 }
6634 }
6635
6636 fn close_common(&mut self) {
6637 trace!("connection closed");
6638 self.timers.reset();
6639 }
6640
6641 fn set_close_timer(&mut self, now: Instant) {
6642 let pto_max = self.max_pto_for_space(self.highest_space);
6645 self.timers.set(
6646 Timer::Conn(ConnTimer::Close),
6647 now + 3 * pto_max,
6648 self.qlog.with_time(now),
6649 );
6650 }
6651
6652 fn handle_peer_params(
6657 &mut self,
6658 params: TransportParameters,
6659 local_cid: ConnectionId,
6660 remote_cid: ConnectionId,
6661 now: Instant,
6662 ) -> Result<(), TransportError> {
6663 if Some(self.original_remote_cid) != params.initial_src_cid
6664 || (self.side.is_client()
6665 && (Some(self.initial_dst_cid) != params.original_dst_cid
6666 || self.retry_src_cid != params.retry_src_cid))
6667 {
6668 return Err(TransportError::TRANSPORT_PARAMETER_ERROR(
6669 "CID authentication failure",
6670 ));
6671 }
6672 if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) {
6673 return Err(TransportError::PROTOCOL_VIOLATION(
6674 "multipath must not use zero-length CIDs",
6675 ));
6676 }
6677
6678 self.set_peer_params(params);
6679 self.qlog.emit_peer_transport_params_received(self, now);
6680
6681 Ok(())
6682 }
6683
6684 fn set_peer_params(&mut self, params: TransportParameters) {
6685 self.streams.set_params(¶ms);
6686 self.idle_timeout =
6687 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout));
6688 trace!("negotiated max idle timeout {:?}", self.idle_timeout);
6689
6690 if let Some(ref info) = params.preferred_address {
6691 self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId {
6693 path_id: None,
6694 sequence: 1,
6695 id: info.connection_id,
6696 reset_token: info.stateless_reset_token,
6697 retire_prior_to: 0,
6698 })
6699 .expect(
6700 "preferred address CID is the first received, and hence is guaranteed to be legal",
6701 );
6702 let remote = self.path_data(PathId::ZERO).network_path.remote;
6703 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token);
6704 }
6705 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(¶ms);
6706
6707 let mut multipath_enabled = false;
6708 if let (Some(local_max_path_id), Some(remote_max_path_id)) = (
6709 self.config.get_initial_max_path_id(),
6710 params.initial_max_path_id,
6711 ) {
6712 self.local_max_path_id = local_max_path_id;
6714 self.remote_max_path_id = remote_max_path_id;
6715 let initial_max_path_id = local_max_path_id.min(remote_max_path_id);
6716 debug!(%initial_max_path_id, "multipath negotiated");
6717 multipath_enabled = true;
6718 }
6719
6720 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) =
6721 self.config
6722 .max_remote_nat_traversal_addresses
6723 .zip(params.max_remote_nat_traversal_addresses)
6724 {
6725 if multipath_enabled {
6726 let max_local_addresses = max_remotely_allowed_remote_addresses.get();
6727 let max_remote_addresses = max_locally_allowed_remote_addresses.get();
6728 self.n0_nat_traversal = n0_nat_traversal::State::new(
6729 max_remote_addresses,
6730 max_local_addresses,
6731 self.side(),
6732 );
6733 debug!(
6734 %max_remote_addresses, %max_local_addresses,
6735 "n0's nat traversal negotiated"
6736 );
6737 } else {
6738 debug!("n0 nat traversal enabled for both endpoints, but multipath is missing")
6739 }
6740 }
6741
6742 self.peer_params = params;
6743 let peer_max_udp_payload_size =
6744 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
6745 let address_discovery_negotiated = self
6746 .config
6747 .address_discovery_role
6748 .should_report(&self.peer_params.address_discovery_role);
6749
6750 let path = self.path_data_mut(PathId::ZERO);
6751 path.pending.observed_address = address_discovery_negotiated;
6752 path.mtud
6753 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size);
6754 }
6755
6756 fn decrypt_packet(
6758 &mut self,
6759 now: Instant,
6760 path_id: PathId,
6761 packet: &mut Packet,
6762 ) -> Result<Option<u64>, Option<TransportError>> {
6763 let result = self
6764 .crypto_state
6765 .decrypt_packet_body(packet, path_id, &self.spaces)?;
6766
6767 let Some(result) = result else {
6768 return Ok(None);
6769 };
6770
6771 if result.outgoing_key_update_acked
6772 && let Some(prev) = self.crypto_state.prev_crypto.as_mut()
6773 {
6774 prev.end_packet = Some((result.packet_number, now));
6775 self.set_key_discard_timer(now, packet.header.space());
6776 }
6777
6778 if result.incoming_key_update {
6779 trace!("key update authenticated");
6780 self.crypto_state
6781 .update_keys(Some((result.packet_number, now)), true);
6782 self.set_key_discard_timer(now, packet.header.space());
6783 }
6784
6785 Ok(Some(result.packet_number))
6786 }
6787
6788 fn peer_supports_ack_frequency(&self) -> bool {
6789 self.peer_params.min_ack_delay.is_some()
6790 }
6791
6792 pub(crate) fn immediate_ack(&mut self, path_id: PathId) {
6797 debug_assert_eq!(
6798 self.highest_space,
6799 SpaceKind::Data,
6800 "immediate ack must be written in the data space"
6801 );
6802 self.spaces[SpaceId::Data]
6803 .for_path(path_id)
6804 .pending_immediate_ack = true;
6805 }
6806
6807 #[cfg(test)]
6809 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> {
6810 let ConnectionEventInner::Datagram(DatagramConnectionEvent {
6811 path_id,
6812 first_decode,
6813 remaining,
6814 ..
6815 }) = &event.0
6816 else {
6817 return None;
6818 };
6819
6820 if remaining.is_some() {
6821 panic!("Packets should never be coalesced in tests");
6822 }
6823
6824 let decrypted_header = self
6825 .crypto_state
6826 .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?;
6827
6828 let mut packet = decrypted_header.packet?;
6829 self.crypto_state
6830 .decrypt_packet_body(&mut packet, *path_id, &self.spaces)
6831 .ok()?;
6832
6833 Some(packet.payload.to_vec())
6834 }
6835
6836 #[cfg(test)]
6839 pub(crate) fn bytes_in_flight(&self) -> u64 {
6840 self.path_data(PathId::ZERO).in_flight.bytes
6842 }
6843
6844 #[cfg(test)]
6846 pub(crate) fn congestion_window(&self) -> u64 {
6847 let path = self.path_data(PathId::ZERO);
6848 path.congestion
6849 .window()
6850 .saturating_sub(path.in_flight.bytes)
6851 }
6852
6853 #[cfg(test)]
6855 pub(crate) fn is_idle(&self) -> bool {
6856 let current_timers = self.timers.values();
6857 current_timers
6858 .into_iter()
6859 .filter(|(timer, _)| {
6860 !matches!(
6861 timer,
6862 Timer::Conn(ConnTimer::KeepAlive)
6863 | Timer::PerPath(_, PathTimer::PathKeepAlive)
6864 | Timer::Conn(ConnTimer::PushNewCid)
6865 | Timer::Conn(ConnTimer::KeyDiscard)
6866 )
6867 })
6868 .min_by_key(|(_, time)| *time)
6869 .is_none_or(|(timer, _)| {
6870 matches!(
6871 timer,
6872 Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle)
6873 )
6874 })
6875 }
6876
6877 #[cfg(test)]
6879 pub(crate) fn using_ecn(&self) -> bool {
6880 self.path_data(PathId::ZERO).sending_ecn
6881 }
6882
6883 #[cfg(test)]
6885 pub(crate) fn total_recvd(&self) -> u64 {
6886 self.path_data(PathId::ZERO).total_recvd
6887 }
6888
6889 #[cfg(test)]
6890 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) {
6891 self.local_cid_state
6892 .get(&PathId::ZERO)
6893 .unwrap()
6894 .active_seq()
6895 }
6896
6897 #[cfg(test)]
6898 #[track_caller]
6899 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) {
6900 self.local_cid_state
6901 .get(&PathId(path_id))
6902 .unwrap()
6903 .active_seq()
6904 }
6905
6906 #[cfg(test)]
6909 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) {
6910 let n = self
6911 .local_cid_state
6912 .get_mut(&PathId::ZERO)
6913 .unwrap()
6914 .assign_retire_seq(v);
6915 debug_assert!(!self.state.is_drained()); self.endpoint_events
6917 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6918 }
6919
6920 #[cfg(test)]
6922 pub(crate) fn active_remote_cid_seq(&self) -> u64 {
6923 self.remote_cids.get(&PathId::ZERO).unwrap().active_seq()
6924 }
6925
6926 #[cfg(test)]
6928 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 {
6929 self.path_data(path_id).current_mtu()
6930 }
6931
6932 #[cfg(test)]
6934 pub(crate) fn trigger_path_validation(&mut self) {
6935 for path in self.paths.values_mut() {
6936 path.data.pending_challenge = true;
6937 }
6938 }
6939
6940 #[cfg(test)]
6942 pub fn simulate_protocol_violation(&mut self, now: Instant) {
6943 if !self.state.is_closed() {
6944 self.state
6945 .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation"));
6946 self.close_common();
6947 if !self.state.is_drained() {
6948 self.set_close_timer(now);
6949 }
6950 self.connection_close_pending = true;
6951 }
6952 }
6953
6954 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames {
6965 let network_path = self.path_data(path_id).network_path;
6966 let space_specific = self
6967 .paths
6968 .get(&path_id)
6969 .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty())
6970 || self.spaces[SpaceKind::Data]
6971 .number_spaces
6972 .get(&path_id)
6973 .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path));
6974
6975 let other = self.streams.can_send_stream_data()
6977 || self
6978 .datagrams
6979 .outgoing
6980 .front()
6981 .is_some_and(|x| x.size(true) <= max_size);
6982
6983 SendableFrames {
6985 acks: false,
6986 close: false,
6987 space_specific,
6988 other,
6989 }
6990 }
6991
6992 fn kill(&mut self, reason: ConnectionError) {
6994 self.close_common();
6995 self.state
6996 .move_to_drained(Some(reason), &mut self.endpoint_events);
6997 }
6998
6999 pub fn current_mtu(&self) -> u16 {
7006 self.paths
7007 .iter()
7008 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id))
7009 .map(|(_path_id, path_state)| path_state.data.current_mtu())
7010 .min()
7011 .unwrap_or(INITIAL_MTU)
7012 }
7013
7014 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize {
7021 let pn_len = PacketNumber::new(
7022 pn,
7023 self.spaces[SpaceId::Data]
7024 .for_path(path)
7025 .largest_acked_packet_pn
7026 .unwrap_or(0),
7027 )
7028 .len();
7029
7030 1 + self
7032 .remote_cids
7033 .get(&path)
7034 .map(|cids| cids.active().len())
7035 .unwrap_or(20) + pn_len
7037 + self.tag_len_1rtt()
7038 }
7039
7040 fn predict_1rtt_overhead_no_pn(&self) -> usize {
7041 let pn_len = 4;
7042
7043 let cid_len = self
7044 .remote_cids
7045 .values()
7046 .map(|cids| cids.active().len())
7047 .max()
7048 .unwrap_or(20); 1 + cid_len + pn_len + self.tag_len_1rtt()
7052 }
7053
7054 fn tag_len_1rtt(&self) -> usize {
7055 let packet_crypto = self
7057 .crypto_state
7058 .encryption_keys(SpaceKind::Data, self.side.side())
7059 .map(|(_header, packet, _level)| packet);
7060 packet_crypto.map_or(16, |x| x.tag_len())
7064 }
7065
7066 fn on_path_validated(&mut self, path_id: PathId) {
7068 self.path_data_mut(path_id).validated = true;
7069 let ConnectionSide::Server { server_config } = &self.side else {
7070 return;
7071 };
7072 let network_path = self.path_data(path_id).network_path;
7073 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens;
7074 new_tokens.clear();
7075 for _ in 0..server_config.validation_token.sent {
7076 new_tokens.push(network_path);
7077 }
7078 }
7079
7080 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) {
7082 if let Some(path) = self.paths.get_mut(&path_id) {
7083 path.data.status.remote_update(status, status_seq_no);
7084 } else {
7085 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id);
7086 }
7087 self.events.push_back(
7088 PathEvent::RemoteStatus {
7089 id: path_id,
7090 status,
7091 }
7092 .into(),
7093 );
7094 }
7095
7096 fn max_path_id(&self) -> Option<PathId> {
7105 if self.is_multipath_negotiated() {
7106 Some(self.remote_max_path_id.min(self.local_max_path_id))
7107 } else {
7108 None
7109 }
7110 }
7111
7112 pub(crate) fn is_ipv6(&self) -> bool {
7117 self.paths
7118 .values()
7119 .any(|p| p.data.network_path.remote.is_ipv6())
7120 }
7121
7122 pub fn add_nat_traversal_address(
7124 &mut self,
7125 address: SocketAddr,
7126 ) -> Result<(), n0_nat_traversal::Error> {
7127 if let Some(added) = self.n0_nat_traversal.add_local_address(address)? {
7128 self.spaces[SpaceId::Data].pending.add_address.insert(added);
7129 };
7130 Ok(())
7131 }
7132
7133 pub fn remove_nat_traversal_address(
7137 &mut self,
7138 address: SocketAddr,
7139 ) -> Result<(), n0_nat_traversal::Error> {
7140 if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? {
7141 self.spaces[SpaceId::Data]
7142 .pending
7143 .remove_address
7144 .insert(removed);
7145 }
7146 Ok(())
7147 }
7148
7149 pub fn get_local_nat_traversal_addresses(
7151 &self,
7152 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7153 self.n0_nat_traversal.get_local_nat_traversal_addresses()
7154 }
7155
7156 pub fn get_remote_nat_traversal_addresses(
7158 &self,
7159 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7160 Ok(self
7161 .n0_nat_traversal
7162 .client_side()?
7163 .get_remote_nat_traversal_addresses())
7164 }
7165
7166 pub fn initiate_nat_traversal_round(
7178 &mut self,
7179 now: Instant,
7180 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7181 if self.state.is_closed() {
7182 return Err(n0_nat_traversal::Error::Closed);
7183 }
7184
7185 let ipv6 = self.is_ipv6();
7186 let client_state = self.n0_nat_traversal.client_side_mut()?;
7187 let (mut reach_out_frames, probed_addrs) =
7188 client_state.initiate_nat_traversal_round(ipv6)?;
7189 if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) {
7190 self.timers.set(
7191 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
7192 now + delay,
7193 self.qlog.with_time(now),
7194 );
7195 }
7196
7197 self.spaces[SpaceId::Data]
7198 .pending
7199 .reach_out
7200 .append(&mut reach_out_frames);
7201
7202 Ok(probed_addrs)
7203 }
7204
7205 fn is_handshake_confirmed(&self) -> bool {
7214 !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake)
7215 }
7216}
7217
7218impl fmt::Debug for Connection {
7219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7220 f.debug_struct("Connection")
7221 .field("handshake_cid", &self.handshake_cid)
7222 .finish()
7223 }
7224}
7225
7226#[derive(Debug, Default)]
7232struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>);
7233
7234const ABANDONED_PATH_INLINE_RANGES: usize = 16;
7239
7240impl AbandonedPaths {
7241 fn len(&self) -> u32 {
7243 self.0.elts_count()
7244 }
7245
7246 fn max(&self) -> Option<PathId> {
7248 self.0.max().map(PathId::from)
7249 }
7250
7251 fn contains(&self, val: &PathId) -> bool {
7253 self.0.contains(val.as_u32())
7254 }
7255
7256 fn insert(&mut self, val: PathId) {
7258 self.0.insert_one(val.as_u32());
7259 }
7260}
7261
7262pub trait NetworkChangeHint: fmt::Debug + 'static {
7264 fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool;
7273}
7274
7275#[derive(Debug)]
7277enum PollPathSpaceStatus {
7278 NothingToSend {
7280 path_blocked: PathBlocked,
7283 },
7284 WrotePacket {
7286 last_packet_number: u64,
7288 pad_datagram: PadDatagram,
7302 },
7303 Send {
7310 last_packet_number: u64,
7312 },
7313}
7314
7315#[derive(Debug, Copy, Clone)]
7321struct PathSchedulingInfo {
7322 is_abandoned: bool,
7328 may_send_data: bool,
7346 may_send_close: bool,
7352 may_self_abandon: bool,
7353}
7354
7355#[derive(Debug, Copy, Clone, PartialEq, Eq)]
7356enum PathBlocked {
7357 No,
7358 AntiAmplification,
7359 Congestion,
7360 Pacing,
7361}
7362
7363enum ConnectionSide {
7365 Client {
7366 token: Bytes,
7368 token_store: Arc<dyn TokenStore>,
7369 server_name: String,
7370 },
7371 Server {
7372 server_config: Arc<ServerConfig>,
7373 },
7374}
7375
7376impl ConnectionSide {
7377 fn is_client(&self) -> bool {
7378 self.side().is_client()
7379 }
7380
7381 fn is_server(&self) -> bool {
7382 self.side().is_server()
7383 }
7384
7385 fn side(&self) -> Side {
7386 match *self {
7387 Self::Client { .. } => Side::Client,
7388 Self::Server { .. } => Side::Server,
7389 }
7390 }
7391}
7392
7393impl From<SideArgs> for ConnectionSide {
7394 fn from(side: SideArgs) -> Self {
7395 match side {
7396 SideArgs::Client {
7397 token_store,
7398 server_name,
7399 } => Self::Client {
7400 token: token_store.take(&server_name).unwrap_or_default(),
7401 token_store,
7402 server_name,
7403 },
7404 SideArgs::Server {
7405 server_config,
7406 pref_addr_cid: _,
7407 path_validated: _,
7408 } => Self::Server { server_config },
7409 }
7410 }
7411}
7412
7413pub(crate) enum SideArgs {
7415 Client {
7416 token_store: Arc<dyn TokenStore>,
7417 server_name: String,
7418 },
7419 Server {
7420 server_config: Arc<ServerConfig>,
7421 pref_addr_cid: Option<ConnectionId>,
7422 path_validated: bool,
7423 },
7424}
7425
7426impl SideArgs {
7427 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> {
7428 match *self {
7429 Self::Client { .. } => None,
7430 Self::Server { pref_addr_cid, .. } => pref_addr_cid,
7431 }
7432 }
7433
7434 pub(crate) fn path_validated(&self) -> bool {
7435 match *self {
7436 Self::Client { .. } => true,
7437 Self::Server { path_validated, .. } => path_validated,
7438 }
7439 }
7440
7441 pub(crate) fn side(&self) -> Side {
7442 match *self {
7443 Self::Client { .. } => Side::Client,
7444 Self::Server { .. } => Side::Server,
7445 }
7446 }
7447}
7448
7449#[derive(Debug, Error, Clone, PartialEq, Eq)]
7451pub enum ConnectionError {
7452 #[error("peer doesn't implement any supported version")]
7454 VersionMismatch,
7455 #[error(transparent)]
7457 TransportError(#[from] TransportError),
7458 #[error("aborted by peer: {0}")]
7460 ConnectionClosed(frame::ConnectionClose),
7461 #[error("closed by peer: {0}")]
7463 ApplicationClosed(frame::ApplicationClose),
7464 #[error("reset by peer")]
7466 Reset,
7467 #[error("timed out")]
7473 TimedOut,
7474 #[error("closed")]
7476 LocallyClosed,
7477 #[error("CIDs exhausted")]
7481 CidsExhausted,
7482}
7483
7484impl From<Close> for ConnectionError {
7485 fn from(x: Close) -> Self {
7486 match x {
7487 Close::Connection(reason) => Self::ConnectionClosed(reason),
7488 Close::Application(reason) => Self::ApplicationClosed(reason),
7489 }
7490 }
7491}
7492
7493impl From<ConnectionError> for io::Error {
7495 fn from(x: ConnectionError) -> Self {
7496 use ConnectionError::*;
7497 let kind = match x {
7498 TimedOut => io::ErrorKind::TimedOut,
7499 Reset => io::ErrorKind::ConnectionReset,
7500 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted,
7501 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => {
7502 io::ErrorKind::Other
7503 }
7504 };
7505 Self::new(kind, x)
7506 }
7507}
7508
7509#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
7512pub enum PathError {
7513 #[error("multipath extension not negotiated")]
7515 MultipathNotNegotiated,
7516 #[error("the server side may not open a path")]
7518 ServerSideNotAllowed,
7519 #[error("maximum number of concurrent paths reached")]
7521 MaxPathIdReached,
7522 #[error("remoted CIDs exhausted")]
7524 RemoteCidsExhausted,
7525 #[error("path validation failed")]
7527 ValidationFailed,
7528 #[error("invalid remote address")]
7530 InvalidRemoteAddress(SocketAddr),
7531}
7532
7533#[derive(Debug, Error, Clone, Eq, PartialEq)]
7535pub enum ClosePathError {
7536 #[error("Multipath extension not negotiated")]
7538 MultipathNotNegotiated,
7539 #[error("closed path")]
7541 ClosedPath,
7542 #[error("last open path")]
7546 LastOpenPath,
7547}
7548
7549#[derive(Debug, Error, Clone, Copy)]
7551#[error("Multipath extension not negotiated")]
7552pub struct MultipathNotNegotiated {
7553 _private: (),
7554}
7555
7556#[derive(Debug)]
7558pub enum Event {
7559 HandshakeDataReady,
7561 Connected,
7563 HandshakeConfirmed,
7565 ConnectionLost {
7572 reason: ConnectionError,
7574 },
7575 Stream(StreamEvent),
7577 DatagramReceived,
7579 DatagramsUnblocked,
7581 Path(PathEvent),
7583 NatTraversal(n0_nat_traversal::Event),
7585}
7586
7587impl From<PathEvent> for Event {
7588 fn from(source: PathEvent) -> Self {
7589 Self::Path(source)
7590 }
7591}
7592
7593fn get_max_ack_delay(params: &TransportParameters) -> Duration {
7594 Duration::from_micros(params.max_ack_delay.0 * 1000)
7595}
7596
7597const MAX_BACKOFF_EXPONENT: u32 = 16;
7599
7600const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2);
7604
7605const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25);
7607
7608const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1);
7613
7614const SLOW_RTT_THRESHOLD: Duration =
7619 Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3);
7620
7621const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32;
7629
7630const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize =
7636 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4;
7637
7638#[derive(Default)]
7639struct SentFrames {
7640 retransmits: ThinRetransmits,
7641 path_retransmits: PathRetransmits,
7642 largest_acked: FxHashMap<PathId, u64>,
7644 stream_frames: StreamMetaVec,
7645 non_retransmits: bool,
7647 requires_padding: bool,
7649}
7650
7651impl SentFrames {
7652 fn is_ack_only(&self, streams: &StreamsState) -> bool {
7654 !self.largest_acked.is_empty()
7655 && !self.non_retransmits
7656 && self.stream_frames.is_empty()
7657 && self.retransmits.is_empty(streams)
7658 }
7659
7660 fn retransmits_mut(&mut self) -> &mut Retransmits {
7661 self.retransmits.get_or_create()
7662 }
7663
7664 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) {
7665 use frame::EncodableFrame::*;
7666 match frame {
7667 PathAck(path_ack_encoder) => {
7668 if let Some(max) = path_ack_encoder.ranges.max() {
7669 self.largest_acked.insert(path_ack_encoder.path_id, max);
7670 }
7671 }
7672 Ack(ack_encoder) => {
7673 if let Some(max) = ack_encoder.ranges.max() {
7674 self.largest_acked.insert(PathId::ZERO, max);
7675 }
7676 }
7677 Close(_) => { }
7678 PathResponse(_) => self.non_retransmits = true,
7679 HandshakeDone(_) => self.retransmits_mut().handshake_done = true,
7680 ReachOut(frame) => self.retransmits_mut().reach_out.push(frame),
7681 ObservedAddr(_) => self.path_retransmits.observed_address = true,
7682 Ping(_) => self.non_retransmits = true,
7683 ImmediateAck(_) => self.non_retransmits = true,
7684 AckFrequency(_) => self.retransmits_mut().ack_frequency = true,
7685 PathChallenge(_) => self.non_retransmits = true,
7686 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto),
7687 PathAbandon(path_abandon) => {
7688 self.retransmits_mut()
7689 .path_abandon
7690 .entry(path_abandon.path_id)
7691 .or_insert(path_abandon.error_code);
7692 }
7693 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. })
7694 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => {
7695 self.retransmits_mut().path_status.insert(path_id);
7696 }
7697 MaxPathId(_) => self.retransmits_mut().max_path_id = true,
7698 PathsBlocked(frame::PathsBlocked(path_id)) => {
7699 let paths_blocked = &mut self.retransmits_mut().paths_blocked;
7700 *paths_blocked = cmp::max(*paths_blocked, Some(path_id));
7701 }
7702 PathCidsBlocked(path_cids_blocked) => {
7703 self.retransmits_mut()
7704 .path_cids_blocked
7705 .entry(path_cids_blocked.path_id)
7706 .and_modify(|next_seq| {
7707 *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq);
7708 })
7709 .or_insert(path_cids_blocked.next_seq);
7710 }
7711 ResetStream(reset) => self
7712 .retransmits_mut()
7713 .reset_stream
7714 .push((reset.id, reset.error_code)),
7715 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending),
7716 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()),
7717 RetireConnectionId(retire_cid) => self
7718 .retransmits_mut()
7719 .retire_cids
7720 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)),
7721 Datagram(_) => self.non_retransmits = true,
7722 NewToken(_) => {}
7723 AddAddress(add_address) => {
7724 self.retransmits_mut().add_address.insert(add_address);
7725 }
7726 RemoveAddress(remove_address) => {
7727 self.retransmits_mut().remove_address.insert(remove_address);
7728 }
7729 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta),
7730 MaxData(_) => self.retransmits_mut().max_data = true,
7731 MaxStreamData(max) => {
7732 self.retransmits_mut().max_stream_data.insert(max.id);
7733 }
7734 MaxStreams(max_streams) => {
7735 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true
7736 }
7737 StreamsBlocked(streams_blocked) => {
7738 self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true
7739 }
7740 }
7741 }
7742}
7743
7744fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> {
7756 match (x, y) {
7757 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None,
7758 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)),
7759 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)),
7760 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)),
7761 }
7762}
7763
7764#[cfg(test)]
7765mod tests {
7766 use super::*;
7767
7768 #[test]
7769 fn negotiate_max_idle_timeout_commutative() {
7770 let test_params = [
7771 (None, None, None),
7772 (None, Some(VarInt(0)), None),
7773 (None, Some(VarInt(2)), Some(Duration::from_millis(2))),
7774 (Some(VarInt(0)), Some(VarInt(0)), None),
7775 (
7776 Some(VarInt(2)),
7777 Some(VarInt(0)),
7778 Some(Duration::from_millis(2)),
7779 ),
7780 (
7781 Some(VarInt(1)),
7782 Some(VarInt(4)),
7783 Some(Duration::from_millis(1)),
7784 ),
7785 ];
7786
7787 for (left, right, result) in test_params {
7788 assert_eq!(negotiate_max_idle_timeout(left, right), result);
7789 assert_eq!(negotiate_max_idle_timeout(right, left), result);
7790 }
7791 }
7792
7793 #[test]
7794 fn abandoned_paths() {
7795 let mut t = AbandonedPaths::default();
7796
7797 t.insert(PathId(0));
7798 t.insert(PathId(1));
7799 assert_eq!(t.len(), 2);
7800 assert_eq!(t.0.range_count(), 1); assert!(t.contains(&PathId(0)));
7802 assert!(t.contains(&PathId(1)));
7803 assert!(!t.contains(&PathId(2)));
7804 assert!(!t.contains(&PathId(3)));
7805 assert_eq!(t.max(), Some(PathId(1)));
7806
7807 t.insert(PathId(3));
7808 assert_eq!(t.len(), 3);
7809 assert_eq!(t.0.range_count(), 2); assert!(t.contains(&PathId(0)));
7811 assert!(t.contains(&PathId(1)));
7812 assert!(!t.contains(&PathId(2)));
7813 assert!(t.contains(&PathId(3)));
7814 assert_eq!(t.max(), Some(PathId(3)));
7815
7816 t.insert(PathId(2));
7817 assert_eq!(t.len(), 4);
7818 assert_eq!(t.0.range_count(), 1); assert!(t.contains(&PathId(0)));
7820 assert!(t.contains(&PathId(1)));
7821 assert!(t.contains(&PathId(2)));
7822 assert!(t.contains(&PathId(3)));
7823 assert_eq!(t.max(), Some(PathId(3)));
7824 }
7825}