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::{ClosedPath, PathAbandonReason, PathEvent, PathId, RttEstimator, SetPathStatusError};
78use paths::{PathData, PathState};
79
80pub(crate) mod qlog;
81pub(crate) mod send_buffer;
82
83pub(crate) mod spaces;
84pub use spaces::PathStatus;
85#[cfg(fuzzing)]
86pub use spaces::Retransmits;
87#[cfg(not(fuzzing))]
88use spaces::Retransmits;
89pub(crate) use spaces::SpaceKind;
90use spaces::{OpenStatus, PacketSpace, SendableFrames, SentPacket, ThinRetransmits};
91
92mod stats;
93pub use stats::{ConnectionStats, FrameStats, PathStats, UdpStats};
94
95mod streams;
96#[cfg(fuzzing)]
97pub use streams::StreamsState;
98#[cfg(not(fuzzing))]
99use streams::StreamsState;
100pub use streams::{
101 Chunks, ClosedStream, FinishError, ReadError, ReadableError, RecvStream, SendStream,
102 ShouldTransmit, StreamEvent, Streams, WriteError,
103};
104
105mod timer;
106use timer::{Timer, TimerTable};
107
108mod transmit_buf;
109use transmit_buf::TransmitBuf;
110
111mod state;
112
113#[cfg(not(fuzzing))]
114use state::State;
115#[cfg(fuzzing)]
116pub use state::State;
117use state::StateType;
118
119pub struct Connection {
158 endpoint_config: Arc<EndpointConfig>,
159 config: Arc<TransportConfig>,
160 rng: StdRng,
161 crypto_state: CryptoState,
163 handshake_cid: ConnectionId,
165 remote_handshake_cid: ConnectionId,
167 paths: BTreeMap<PathId, PathState>,
173 path_generation_counter: u64,
184 allow_mtud: bool,
186 state: State,
187 side: ConnectionSide,
188 peer_params: TransportParameters,
190 original_remote_cid: ConnectionId,
192 initial_dst_cid: ConnectionId,
194 retry_src_cid: Option<ConnectionId>,
197 events: VecDeque<Event>,
199 endpoint_events: VecDeque<EndpointEventInner>,
200 spin_enabled: bool,
202 spin: bool,
204 spaces: [PacketSpace; 3],
206 highest_space: SpaceKind,
208 idle_timeout: Option<Duration>,
210 timers: TimerTable,
211 authentication_failures: u64,
213
214 connection_close_pending: bool,
218
219 ack_frequency: AckFrequencyState,
222
223 receiving_ecn: bool,
227 total_authed_packets: u64,
229
230 next_observed_addr_seq_no: VarInt,
234
235 streams: StreamsState,
236 remote_cids: FxHashMap<PathId, CidQueue>,
242 local_cid_state: FxHashMap<PathId, CidState>,
249 datagrams: DatagramState,
251 path_stats: PathStatsMap,
253 partial_stats: ConnectionStats,
259 version: u32,
261
262 max_concurrent_paths: NonZeroU32,
270 local_max_path_id: PathId,
285 remote_max_path_id: PathId,
291 max_path_id_with_cids: PathId,
297 abandoned_paths: AbandonedPaths,
303
304 n0_nat_traversal: n0_nat_traversal::State,
306 qlog: QlogSink,
307}
308
309impl Connection {
310 pub(crate) fn new(
311 endpoint_config: Arc<EndpointConfig>,
312 config: Arc<TransportConfig>,
313 init_cid: ConnectionId,
314 local_cid: ConnectionId,
315 remote_cid: ConnectionId,
316 network_path: FourTuple,
317 crypto: Box<dyn crypto::Session>,
318 cid_gen: &dyn ConnectionIdGenerator,
319 now: Instant,
320 version: u32,
321 allow_mtud: bool,
322 rng_seed: [u8; 32],
323 side_args: SideArgs,
324 qlog: QlogSink,
325 ) -> Self {
326 let pref_addr_cid = side_args.pref_addr_cid();
327 let path_validated = side_args.path_validated();
328 let connection_side = ConnectionSide::from(side_args);
329 let side = connection_side.side();
330 let mut rng = StdRng::from_seed(rng_seed);
331 let mut initial_space = PacketSpace::new(now, SpaceId::Initial, &mut rng);
332 let mut handshake_space = PacketSpace::new(now, SpaceId::Handshake, &mut rng);
333 #[cfg(test)]
334 let mut data_space = match config.deterministic_packet_numbers {
335 true => PacketSpace::new_deterministic(now, SpaceId::Data),
336 false => PacketSpace::new(now, SpaceId::Data, &mut rng),
337 };
338 #[cfg(not(test))]
339 let mut data_space = PacketSpace::new(now, SpaceId::Data, &mut rng);
340
341 initial_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
343 handshake_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
344 data_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
345
346 let state = State::handshake(state::Handshake {
347 remote_cid_set: side.is_server(),
348 expected_token: Bytes::new(),
349 client_hello: None,
350 allow_server_migration: side.is_client() && config.server_handshake_migration,
351 });
352 let local_cid_state = FxHashMap::from_iter([(
353 PathId::ZERO,
354 CidState::new(
355 cid_gen.cid_len(),
356 cid_gen.cid_lifetime(),
357 now,
358 if pref_addr_cid.is_some() { 2 } else { 1 },
359 ),
360 )]);
361
362 let mut this = Self {
363 endpoint_config,
364 crypto_state: CryptoState::new(crypto, init_cid, side, &mut rng),
365 handshake_cid: local_cid,
366 remote_handshake_cid: remote_cid,
367 local_cid_state,
368 paths: BTreeMap::from_iter([(
369 PathId::ZERO,
370 PathState {
371 data: PathData::new(network_path, allow_mtud, None, 0, now, &config),
372 prev: None,
373 },
374 )]),
375 path_generation_counter: 0,
376 allow_mtud,
377 state,
378 side: connection_side,
379 peer_params: TransportParameters::default(),
380 original_remote_cid: remote_cid,
381 initial_dst_cid: init_cid,
382 retry_src_cid: None,
383 events: VecDeque::new(),
384 endpoint_events: VecDeque::new(),
385 spin_enabled: config.allow_spin && rng.random_ratio(7, 8),
386 spin: false,
387 spaces: [initial_space, handshake_space, data_space],
388 highest_space: SpaceKind::Initial,
389 idle_timeout: match config.max_idle_timeout {
390 None | Some(VarInt(0)) => None,
391 Some(dur) => Some(Duration::from_millis(dur.0)),
392 },
393 timers: TimerTable::default(),
394 authentication_failures: 0,
395 connection_close_pending: false,
396
397 ack_frequency: AckFrequencyState::new(get_max_ack_delay(
398 &TransportParameters::default(),
399 )),
400
401 receiving_ecn: false,
402 total_authed_packets: 0,
403
404 next_observed_addr_seq_no: 0u32.into(),
405
406 streams: StreamsState::new(
407 side,
408 config.max_concurrent_uni_streams,
409 config.max_concurrent_bidi_streams,
410 config.send_window,
411 config.receive_window,
412 config.stream_receive_window,
413 ),
414 datagrams: DatagramState::default(),
415 config,
416 remote_cids: FxHashMap::from_iter([(PathId::ZERO, CidQueue::new(remote_cid))]),
417 rng,
418 path_stats: Default::default(),
419 partial_stats: ConnectionStats::default(),
420 version,
421
422 max_concurrent_paths: NonZeroU32::MIN,
424 local_max_path_id: PathId::ZERO,
425 remote_max_path_id: PathId::ZERO,
426 max_path_id_with_cids: PathId::ZERO,
427 abandoned_paths: Default::default(),
428
429 n0_nat_traversal: Default::default(),
430 qlog,
431 };
432 if path_validated {
433 this.on_path_validated(PathId::ZERO);
434 }
435 if side.is_client() {
436 this.write_crypto();
438 this.init_0rtt(now);
439 }
440 this.qlog
441 .emit_tuple_assigned(PathId::ZERO, network_path, now);
442 this
443 }
444
445 #[must_use]
453 pub fn poll_timeout(&self) -> Option<Instant> {
454 self.timers.peek()
455 }
456
457 #[must_use]
463 pub fn poll(&mut self) -> Option<Event> {
464 if let Some(x) = self.events.pop_front() {
465 return Some(x);
466 }
467
468 if let Some(event) = self.streams.poll() {
469 return Some(Event::Stream(event));
470 }
471
472 if let Some(reason) = self.state.take_error() {
473 return Some(Event::ConnectionLost { reason });
474 }
475
476 None
477 }
478
479 #[must_use]
481 pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent> {
482 self.endpoint_events.pop_front().map(EndpointEvent)
483 }
484
485 #[must_use]
487 pub fn streams(&mut self) -> Streams<'_> {
488 Streams {
489 state: &mut self.streams,
490 conn_state: &self.state,
491 }
492 }
493
494 #[must_use]
496 pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_> {
497 assert!(id.dir() == Dir::Bi || id.initiator() != self.side.side());
498 RecvStream {
499 id,
500 state: &mut self.streams,
501 pending: &mut self.spaces[SpaceId::Data].pending,
502 }
503 }
504
505 #[must_use]
507 pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_> {
508 assert!(id.dir() == Dir::Bi || id.initiator() == self.side.side());
509 SendStream {
510 id,
511 state: &mut self.streams,
512 pending: &mut self.spaces[SpaceId::Data].pending,
513 conn_state: &self.state,
514 }
515 }
516
517 pub fn open_path_ensure(
534 &mut self,
535 network_path: FourTuple,
536 initial_status: PathStatus,
537 now: Instant,
538 ) -> Result<(PathId, bool), PathError> {
539 let existing_open_path = self.paths.iter().find(|(id, path)| {
540 network_path.is_probably_same_path(&path.data.network_path)
541 && !self.abandoned_paths.contains(id)
542 });
543 match existing_open_path {
544 Some((path_id, _state)) => Ok((*path_id, true)),
545 None => Ok((self.open_path(network_path, initial_status, now)?, false)),
546 }
547 }
548
549 pub fn open_path(
555 &mut self,
556 network_path: FourTuple,
557 initial_status: PathStatus,
558 now: Instant,
559 ) -> Result<PathId, PathError> {
560 let Some(max_path_id) = self.max_path_id() else {
561 return Err(PathError::MultipathNotNegotiated);
562 };
563 if self.side().is_server() {
564 return Err(PathError::ServerSideNotAllowed);
565 }
566
567 let max_abandoned = self.abandoned_paths.max();
568 let max_used = self.paths.keys().last().copied();
569 let path_id = max_abandoned
570 .max(max_used)
571 .unwrap_or(PathId::ZERO)
572 .saturating_add(1u8);
573
574 if path_id > max_path_id {
575 self.spaces[SpaceId::Data].pending.paths_blocked = Some(self.remote_max_path_id);
576 return Err(PathError::MaxPathIdReached);
577 }
578 if !self.remote_cids.contains_key(&path_id) {
579 self.spaces[SpaceId::Data]
580 .pending
581 .path_cids_blocked
582 .insert(path_id, VarInt(0));
583 return Err(PathError::RemoteCidsExhausted);
584 }
585
586 self.create_network_path(path_id, network_path, now, None);
587 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
588 pns.status.local_update(initial_status);
589
590 Ok(path_id)
591 }
592
593 pub fn close_path(
599 &mut self,
600 now: Instant,
601 path_id: PathId,
602 error_code: VarInt,
603 ) -> Result<(), ClosePathError> {
604 self.close_path_inner(
605 now,
606 path_id,
607 PathAbandonReason::ApplicationClosed { error_code },
608 )
609 }
610
611 pub(crate) fn close_path_inner(
616 &mut self,
617 now: Instant,
618 path_id: PathId,
619 reason: PathAbandonReason,
620 ) -> Result<(), ClosePathError> {
621 if self.state.is_drained() {
622 return Ok(());
623 }
624
625 if !self.is_multipath_negotiated() {
626 return Err(ClosePathError::MultipathNotNegotiated);
627 }
628 if self.abandoned_paths.contains(&path_id)
629 || Some(path_id) > self.max_path_id()
630 || !self.paths.contains_key(&path_id)
631 {
632 return Err(ClosePathError::ClosedPath);
633 }
634
635 let is_last_path = !self
636 .paths
637 .keys()
638 .any(|id| *id != path_id && !self.abandoned_paths.contains(id));
639
640 if is_last_path && !reason.is_remote() {
641 return Err(ClosePathError::LastOpenPath);
642 }
643
644 self.abandon_path(now, path_id, reason);
645
646 if is_last_path {
650 let rtt = RttEstimator::new(self.config.initial_rtt);
654 let pto = rtt.pto_base() + self.ack_frequency.max_ack_delay_for_pto();
655 let grace = pto * 3;
656 self.timers.set(
657 Timer::Conn(ConnTimer::NoAvailablePath),
658 now + grace,
659 self.qlog.with_time(now),
660 );
661 }
662
663 Ok(())
664 }
665
666 fn abandon_path(&mut self, now: Instant, path_id: PathId, reason: PathAbandonReason) {
671 trace!(%path_id, ?reason, "abandoning path");
672
673 let pending_space = &mut self.spaces[SpaceId::Data].pending;
674 pending_space
676 .path_abandon
677 .insert(path_id, reason.error_code());
678
679 pending_space.new_cids.retain(|cid| cid.path_id != path_id);
681 pending_space.path_status.retain(|&id| id != path_id);
682
683 for space in self.spaces[SpaceId::Data].iter_paths_mut() {
686 for sent_packet in space.sent_packets.values_mut() {
687 if let Some(retransmits) = sent_packet.retransmits.get_mut() {
688 retransmits.new_cids.retain(|cid| cid.path_id != path_id);
689 retransmits.path_status.retain(|&id| id != path_id);
690 }
691 }
692 }
693
694 self.spaces[SpaceId::Data].for_path(path_id).loss_probes = 0;
699
700 debug_assert!(!self.state.is_drained()); self.endpoint_events
705 .push_back(EndpointEventInner::RetireResetToken(path_id));
706
707 self.abandoned_paths.insert(path_id);
708
709 for timer in PathTimer::VALUES {
710 let keep_timer = match timer {
712 PathTimer::PathValidationFailed | PathTimer::PathChallengeLost => false,
716 PathTimer::PathKeepAlive | PathTimer::PathIdle => false,
719 PathTimer::MaxAckDelay => false,
722 PathTimer::PathDrained => false,
725 PathTimer::LossDetection => true,
728 PathTimer::Pacing => true,
732 };
733
734 if !keep_timer {
735 let qlog = self.qlog.with_time(now);
736 self.timers.stop(Timer::PerPath(path_id, timer), qlog);
737 }
738 }
739
740 self.set_loss_detection_timer(now, path_id);
745
746 self.events.push_back(Event::Path(PathEvent::Abandoned {
748 id: path_id,
749 reason,
750 }));
751 }
752
753 #[track_caller]
757 fn path_data(&self, path_id: PathId) -> &PathData {
758 if let Some(data) = self.paths.get(&path_id) {
759 &data.data
760 } else {
761 panic!(
762 "unknown path: {path_id}, currently known paths: {:?}",
763 self.paths.keys().collect::<Vec<_>>()
764 );
765 }
766 }
767
768 #[track_caller]
772 fn path_data_mut(&mut self, path_id: PathId) -> &mut PathData {
773 &mut self.paths.get_mut(&path_id).expect("known path").data
774 }
775
776 fn path(&self, path_id: PathId) -> Option<&PathData> {
778 self.paths.get(&path_id).map(|path_state| &path_state.data)
779 }
780
781 fn path_mut(&mut self, path_id: PathId) -> Option<&mut PathData> {
783 self.paths
784 .get_mut(&path_id)
785 .map(|path_state| &mut path_state.data)
786 }
787
788 pub fn paths(&self) -> Vec<PathId> {
792 self.paths.keys().copied().collect()
793 }
794
795 pub fn path_status(&self, path_id: PathId) -> Result<PathStatus, ClosedPath> {
797 self.spaces[SpaceKind::Data]
798 .number_spaces
799 .get(&path_id)
800 .map(|pns| pns.local_status())
801 .ok_or(ClosedPath { _private: () })
802 }
803
804 pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath> {
806 self.path(path_id)
807 .map(|path| path.network_path)
808 .ok_or(ClosedPath { _private: () })
809 }
810
811 pub fn set_path_status(
815 &mut self,
816 path_id: PathId,
817 status: PathStatus,
818 ) -> Result<PathStatus, SetPathStatusError> {
819 if !self.is_multipath_negotiated() {
820 return Err(SetPathStatusError::MultipathNotNegotiated);
821 }
822 let pns = self.spaces[SpaceKind::Data]
823 .number_spaces
824 .get_mut(&path_id)
825 .ok_or(SetPathStatusError::ClosedPath)?;
826 let prev = match pns.status.local_update(status) {
827 Some(prev) => {
828 self.spaces[SpaceKind::Data]
829 .pending
830 .path_status
831 .insert(path_id);
832 prev
833 }
834 None => pns.local_status(),
835 };
836 Ok(prev)
837 }
838
839 pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus> {
844 self.spaces[SpaceKind::Data]
845 .number_spaces
846 .get(&path_id)
847 .and_then(|pns| pns.remote_status())
848 }
849
850 pub fn set_path_max_idle_timeout(
859 &mut self,
860 now: Instant,
861 path_id: PathId,
862 timeout: Option<Duration>,
863 ) -> Result<Option<Duration>, ClosedPath> {
864 let path = self
865 .paths
866 .get_mut(&path_id)
867 .ok_or(ClosedPath { _private: () })?;
868 let prev_timeout = mem::replace(&mut path.data.idle_timeout, timeout);
869
870 self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
878
879 Ok(prev_timeout)
880 }
881
882 fn rearm_path_max_idle_timer(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
890 let timer = Timer::PerPath(path_id, PathTimer::PathIdle);
891
892 if self.state.is_closed() || !self.is_multipath_negotiated() {
893 return self.timers.stop(timer, self.qlog.with_time(now));
894 }
895
896 if let Some(timeout) = self.path_data(path_id).idle_timeout {
897 let dt = cmp::max(timeout, 3 * self.pto(space, path_id));
898 self.timers.set(timer, now + dt, self.qlog.with_time(now));
899 } else {
900 self.timers.stop(timer, self.qlog.with_time(now));
901 }
902 }
903
904 pub fn set_path_keep_alive_interval(
910 &mut self,
911 path_id: PathId,
912 interval: Option<Duration>,
913 ) -> Result<Option<Duration>, ClosedPath> {
914 let path = self
915 .paths
916 .get_mut(&path_id)
917 .ok_or(ClosedPath { _private: () })?;
918 Ok(mem::replace(&mut path.data.keep_alive, interval))
919 }
920
921 fn find_validated_path_on_network_path(
925 &self,
926 network_path: FourTuple,
927 ) -> Option<(&PathId, &PathState)> {
928 self.paths.iter().find(|(path_id, path_state)| {
929 path_state.data.validated
930 && network_path.is_probably_same_path(&path_state.data.network_path)
932 && !self.abandoned_paths.contains(path_id)
933 })
934 }
939
940 fn create_network_path(
944 &mut self,
945 path_id: PathId,
946 network_path: FourTuple,
947 now: Instant,
948 pn: Option<u64>,
949 ) -> &mut PathData {
950 let valid_path = self.find_validated_path_on_network_path(network_path);
951 let validated = valid_path.is_some();
952 let initial_rtt = valid_path.map(|(_, path)| path.data.rtt.conservative());
953 let vacant_entry = match self.paths.entry(path_id) {
954 btree_map::Entry::Vacant(vacant_entry) => vacant_entry,
955 btree_map::Entry::Occupied(occupied_entry) => {
956 return &mut occupied_entry.into_mut().data;
957 }
958 };
959
960 debug!(%validated, %path_id, %network_path, "path added");
961
962 self.timers.stop(
964 Timer::Conn(ConnTimer::NoAvailablePath),
965 self.qlog.with_time(now),
966 );
967 let peer_max_udp_payload_size =
968 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
969 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
970 let mut data = PathData::new(
971 network_path,
972 self.allow_mtud,
973 Some(peer_max_udp_payload_size),
974 self.path_generation_counter,
975 now,
976 &self.config,
977 );
978
979 data.validated = validated;
980 if let Some(initial_rtt) = initial_rtt {
981 data.rtt.reset_initial_rtt(initial_rtt);
982 }
983
984 data.pending_challenge = true;
987 data.pending.observed_address = self
988 .config
989 .address_discovery_role
990 .should_report(&self.peer_params.address_discovery_role);
991
992 let path = vacant_entry.insert(PathState { data, prev: None });
993
994 let mut pn_space = spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng);
995 if let Some(pn) = pn {
996 pn_space.dedup.insert(pn);
997 }
998 self.spaces[SpaceId::Data]
999 .number_spaces
1000 .insert(path_id, pn_space);
1001 self.qlog.emit_tuple_assigned(path_id, network_path, now);
1002
1003 if !self.remote_cids.contains_key(&path_id) {
1007 debug!(%path_id, "Remote opened path without issuing CIDs");
1008 self.spaces[SpaceId::Data]
1009 .pending
1010 .path_cids_blocked
1011 .insert(path_id, VarInt(0));
1012 }
1015
1016 &mut path.data
1017 }
1018
1019 #[must_use]
1029 pub fn poll_transmit(
1030 &mut self,
1031 now: Instant,
1032 max_datagrams: NonZeroUsize,
1033 buf: &mut Vec<u8>,
1034 ) -> Option<Transmit> {
1035 let max_datagrams = match self.config.enable_segmentation_offload {
1036 false => NonZeroUsize::MIN,
1037 true => max_datagrams,
1038 };
1039
1040 let connection_close_pending = match self.state.as_type() {
1046 StateType::Drained => {
1047 for path in self.paths.values_mut() {
1048 path.data.app_limited = true;
1049 }
1050 return None;
1051 }
1052 StateType::Draining | StateType::Closed => {
1053 if !self.connection_close_pending {
1056 for path in self.paths.values_mut() {
1057 path.data.app_limited = true;
1058 }
1059 return None;
1060 }
1061 true
1062 }
1063 _ => false,
1064 };
1065
1066 if let Some(config) = &self.config.ack_frequency_config {
1068 let rtt = self
1069 .paths
1070 .values()
1071 .map(|p| p.data.rtt.get())
1072 .min()
1073 .expect("one path exists");
1074 self.spaces[SpaceId::Data].pending.ack_frequency = self
1075 .ack_frequency
1076 .should_send_ack_frequency(rtt, config, &self.peer_params)
1077 && self.highest_space == SpaceKind::Data
1078 && self.peer_supports_ack_frequency();
1079 }
1080
1081 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1082 while let Some(path_id) = next_path_id {
1083 if !connection_close_pending
1084 && let Some(transmit) = self.poll_transmit_off_path(now, buf, path_id)
1085 {
1086 #[cfg(test)]
1087 {
1088 self.partial_stats.transmits_tx += 1;
1089 }
1090 return Some(transmit);
1091 }
1092
1093 let info = self.scheduling_info(path_id);
1094 if let Some(transmit) = self.poll_transmit_on_path(
1095 now,
1096 buf,
1097 path_id,
1098 max_datagrams,
1099 &info,
1100 connection_close_pending,
1101 ) {
1102 #[cfg(test)]
1103 {
1104 self.partial_stats.transmits_tx += 1;
1105 }
1106 return Some(transmit);
1107 }
1108
1109 debug_assert!(
1112 buf.is_empty(),
1113 "nothing to send on path but buffer not empty"
1114 );
1115
1116 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1117 }
1118
1119 debug_assert!(
1121 buf.is_empty(),
1122 "there was data in the buffer, but it was not sent"
1123 );
1124
1125 if self.state.is_established() {
1126 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1128 while let Some(path_id) = next_path_id {
1129 if let Some(transmit) = self.poll_transmit_mtu_probe(now, buf, path_id) {
1130 #[cfg(test)]
1131 {
1132 self.partial_stats.transmits_tx += 1;
1133 }
1134 return Some(transmit);
1135 }
1136 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1137 }
1138 }
1139
1140 None
1141 }
1142
1143 fn scheduling_info(&self, path_id: PathId) -> PathSchedulingInfo {
1161 let have_validated_status_available_space = self.paths.iter().any(|(path_id, path)| {
1163 let pns = self.spaces[SpaceKind::Data].number_spaces.get(path_id);
1165 self.remote_cids.contains_key(path_id)
1166 && !self.abandoned_paths.contains(path_id)
1167 && path.data.validated
1168 && pns.map(|pns| pns.local_status()).unwrap_or_default() == PathStatus::Available
1169 });
1170
1171 let have_validated_space = self.paths.iter().any(|(path_id, path)| {
1173 self.remote_cids.contains_key(path_id)
1174 && !self.abandoned_paths.contains(path_id)
1175 && path.data.validated
1176 });
1177
1178 let is_handshaking = self.is_handshaking();
1179 let has_cids = self.remote_cids.contains_key(&path_id);
1180 let is_abandoned = self.abandoned_paths.contains(&path_id);
1181 let path_data = self.path_data(path_id);
1182 let validated = path_data.validated;
1183
1184 let pns = self.spaces[SpaceKind::Data].number_spaces.get(&path_id);
1186 let status = pns.map(|pns| pns.local_status()).unwrap_or_default();
1187
1188 let may_send_data = has_cids
1191 && !is_abandoned
1192 && if is_handshaking {
1193 true
1197 } else if !validated {
1198 false
1205 } else {
1206 match status {
1207 PathStatus::Available => {
1208 true
1210 }
1211 PathStatus::Backup => {
1212 !have_validated_status_available_space
1214 }
1215 }
1216 };
1217
1218 let may_send_close = has_cids
1223 && !is_abandoned
1224 && if !validated && have_validated_status_available_space {
1225 false
1227 } else {
1228 true
1230 };
1231
1232 let may_self_abandon = has_cids && validated && !have_validated_space;
1236
1237 PathSchedulingInfo {
1238 is_abandoned,
1239 may_send_data,
1240 may_send_close,
1241 may_self_abandon,
1242 }
1243 }
1244
1245 fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit {
1246 debug_assert!(
1247 !transmit.is_empty(),
1248 "must not be called with an empty transmit buffer"
1249 );
1250
1251 let network_path = self.path_data(path_id).network_path;
1252 trace!(
1253 segment_size = transmit.segment_size(),
1254 last_datagram_len = transmit.len() % transmit.segment_size(),
1255 %network_path,
1256 "sending {} bytes in {} datagrams",
1257 transmit.len(),
1258 transmit.num_datagrams()
1259 );
1260 self.path_data_mut(path_id)
1261 .inc_total_sent(transmit.len() as u64);
1262
1263 self.path_stats
1264 .get_mut(path_id)
1265 .udp_tx
1266 .on_sent(transmit.num_datagrams() as u64, transmit.len());
1267
1268 Transmit {
1269 destination: network_path.remote,
1270 size: transmit.len(),
1271 ecn: if self.path_data(path_id).sending_ecn {
1272 Some(EcnCodepoint::Ect0)
1273 } else {
1274 None
1275 },
1276 segment_size: match transmit.num_datagrams() {
1277 1 => None,
1278 _ => Some(transmit.segment_size()),
1279 },
1280 src_ip: network_path.local_ip,
1281 }
1282 }
1283
1284 fn poll_transmit_off_path(
1286 &mut self,
1287 now: Instant,
1288 buf: &mut Vec<u8>,
1289 path_id: PathId,
1290 ) -> Option<Transmit> {
1291 if let Some(challenge) = self.send_prev_path_challenge(now, buf, path_id) {
1292 return Some(challenge);
1293 }
1294 if let Some(response) = self.send_off_path_path_response(now, buf, path_id) {
1295 return Some(response);
1296 }
1297 if let Some(challenge) = self.send_nat_traversal_path_challenge(now, buf, path_id) {
1298 return Some(challenge);
1299 }
1300 None
1301 }
1302
1303 #[must_use]
1310 fn poll_transmit_on_path(
1311 &mut self,
1312 now: Instant,
1313 buf: &mut Vec<u8>,
1314 path_id: PathId,
1315 max_datagrams: NonZeroUsize,
1316 scheduling_info: &PathSchedulingInfo,
1317 connection_close_pending: bool,
1318 ) -> Option<Transmit> {
1319 let Some(remote_cid) = self.remote_cids.get(&path_id).map(CidQueue::active) else {
1321 if !self.abandoned_paths.contains(&path_id) {
1322 debug!(%path_id, "no remote CIDs for path");
1323 }
1324 return None;
1325 };
1326
1327 let mut pad_datagram = PadDatagram::No;
1333
1334 let mut last_packet_number = None;
1338
1339 let mut send_blocked = false;
1342 let mut cwnd_blocked = false;
1345
1346 let path = self.path_data(path_id);
1347
1348 let controller_metrics = path.congestion.metrics();
1354 let max_datagrams = match controller_metrics.send_quantum {
1355 Some(send_quantum) => {
1356 let datagrams = send_quantum / u64::from(path.current_mtu());
1357 let datagrams = usize::try_from(datagrams).unwrap_or(usize::MAX);
1358 max_datagrams.min(NonZeroUsize::new(datagrams).unwrap_or(NonZeroUsize::MIN))
1359 }
1360 None => max_datagrams,
1361 };
1362
1363 let pmtu = path.current_mtu().into();
1365 let mut transmit = TransmitBuf::new(buf, max_datagrams, pmtu);
1366
1367 for space_id in SpaceId::iter() {
1369 if path_id != PathId::ZERO && space_id != SpaceId::Data {
1371 continue;
1372 }
1373 match self.poll_transmit_path_space(
1374 now,
1375 &mut transmit,
1376 path_id,
1377 space_id,
1378 remote_cid,
1379 scheduling_info,
1380 connection_close_pending,
1381 pad_datagram,
1382 ) {
1383 PollPathSpaceStatus::NothingToSend { path_blocked } => {
1384 match path_blocked {
1387 PathBlocked::No => {}
1388 PathBlocked::AntiAmplification => {
1389 send_blocked = true;
1390 }
1391 PathBlocked::Congestion => {
1392 cwnd_blocked = true;
1393 send_blocked = true;
1394 }
1395 PathBlocked::Pacing => send_blocked = true,
1396 }
1397 }
1398 PollPathSpaceStatus::WrotePacket {
1399 last_packet_number: pn,
1400 pad_datagram: pad,
1401 } => {
1402 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1403 last_packet_number = Some(pn);
1404 pad_datagram = pad;
1405 continue;
1410 }
1411 PollPathSpaceStatus::Send {
1412 last_packet_number: pn,
1413 } => {
1414 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1415 last_packet_number = Some(pn);
1416 break;
1417 }
1418 }
1419 }
1420
1421 if last_packet_number.is_some() || send_blocked {
1422 self.qlog.emit_recovery_metrics(
1423 path_id,
1424 &mut self
1425 .paths
1426 .get_mut(&path_id)
1427 .expect("path_id was iterated from self.paths above")
1428 .data,
1429 now,
1430 );
1431 }
1432
1433 let path = self.path_data_mut(path_id);
1434
1435 path.app_limited = last_packet_number.is_none() && !send_blocked;
1436
1437 if cwnd_blocked {
1438 path.congestion.on_cwnd_limited();
1439 }
1440
1441 match last_packet_number {
1442 Some(last_packet_number) => {
1443 self.path_data_mut(path_id).congestion.on_sent(
1446 now,
1447 transmit.len() as u64,
1448 last_packet_number,
1449 );
1450 Some(self.build_transmit(path_id, transmit))
1451 }
1452 None => None,
1453 }
1454 }
1455
1456 #[must_use]
1458 fn poll_transmit_path_space(
1459 &mut self,
1460 now: Instant,
1461 transmit: &mut TransmitBuf<'_>,
1462 path_id: PathId,
1463 space_id: SpaceId,
1464 remote_cid: ConnectionId,
1465 scheduling_info: &PathSchedulingInfo,
1466 connection_close_pending: bool,
1468 mut pad_datagram: PadDatagram,
1470 ) -> PollPathSpaceStatus {
1471 let mut last_packet_number = None;
1474
1475 loop {
1491 let max_packet_size = if transmit.datagram_remaining_mut() > 0 {
1493 transmit.datagram_remaining_mut()
1495 } else {
1496 transmit.segment_size()
1498 };
1499 let can_send =
1500 self.space_can_send(space_id, path_id, max_packet_size, connection_close_pending);
1501 let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1502 let space_will_send = {
1503 if scheduling_info.is_abandoned {
1504 scheduling_info.may_self_abandon
1509 && self.spaces[space_id]
1510 .pending
1511 .path_abandon
1512 .contains_key(&path_id)
1513 } else if can_send.close && scheduling_info.may_send_close {
1514 true
1516 } else if needs_loss_probe || can_send.space_specific {
1517 true
1520 } else {
1521 !can_send.is_empty() && scheduling_info.may_send_data
1524 }
1525 };
1526
1527 if !space_will_send {
1528 return match last_packet_number {
1531 Some(pn) => PollPathSpaceStatus::WrotePacket {
1532 last_packet_number: pn,
1533 pad_datagram,
1534 },
1535 None => {
1536 if self.crypto_state.has_keys(space_id.encryption_level())
1538 || (space_id == SpaceId::Data
1539 && self.crypto_state.has_keys(EncryptionLevel::ZeroRtt))
1540 {
1541 trace!(?space_id, %path_id, "nothing to send in space");
1542 }
1543 PollPathSpaceStatus::NothingToSend {
1544 path_blocked: PathBlocked::No,
1545 }
1546 }
1547 };
1548 }
1549
1550 if transmit.datagram_remaining_mut() == 0 {
1554 let path_blocked =
1555 self.path_congestion_check(space_id, path_id, transmit, &can_send, now);
1556 if path_blocked != PathBlocked::No {
1557 return match last_packet_number {
1559 Some(pn) => PollPathSpaceStatus::WrotePacket {
1560 last_packet_number: pn,
1561 pad_datagram,
1562 },
1563 None => PollPathSpaceStatus::NothingToSend { path_blocked },
1564 };
1565 }
1566
1567 if transmit.num_datagrams() >= transmit.max_datagrams().get() {
1570 return match last_packet_number {
1573 Some(pn) => PollPathSpaceStatus::WrotePacket {
1574 last_packet_number: pn,
1575 pad_datagram,
1576 },
1577 None => PollPathSpaceStatus::NothingToSend { path_blocked },
1578 };
1579 }
1580
1581 if needs_loss_probe {
1582 let request_immediate_ack =
1584 space_id == SpaceId::Data && self.peer_supports_ack_frequency();
1585 self.spaces[space_id].queue_tail_loss_probe(
1586 path_id,
1587 request_immediate_ack,
1588 &self.streams,
1589 );
1590
1591 self.spaces[space_id].for_path(path_id).loss_probes -= 1; transmit.start_new_datagram_with_size(cmp::min(
1597 usize::from(INITIAL_MTU),
1598 transmit.segment_size(),
1599 ));
1600 } else {
1601 transmit.start_new_datagram();
1602 }
1603 trace!(count = transmit.num_datagrams(), "new datagram started");
1604
1605 pad_datagram = PadDatagram::No;
1607 }
1608
1609 if transmit.datagram_start_offset() < transmit.len() {
1612 debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE);
1613 }
1614
1615 if self.crypto_state.has_keys(EncryptionLevel::Initial)
1620 && space_id == SpaceId::Handshake
1621 && self.side.is_client()
1622 {
1623 self.discard_space(now, SpaceKind::Initial);
1626 }
1627 if let Some(ref mut prev) = self.crypto_state.prev_crypto {
1628 prev.update_unacked = false;
1629 }
1630
1631 let Some(mut builder) =
1632 PacketBuilder::new(now, space_id, path_id, remote_cid, transmit, self)
1633 else {
1634 return PollPathSpaceStatus::NothingToSend {
1641 path_blocked: PathBlocked::No,
1642 };
1643 };
1644 last_packet_number = Some(builder.packet_number);
1645
1646 if space_id == SpaceId::Initial
1647 && (self.side.is_client() || can_send.is_ack_eliciting() || needs_loss_probe)
1648 {
1649 pad_datagram |= PadDatagram::ToMinMtu;
1651 }
1652 if space_id == SpaceId::Data && self.config.pad_to_mtu {
1653 pad_datagram |= PadDatagram::ToSegmentSize;
1654 }
1655
1656 if scheduling_info.may_send_close && can_send.close {
1657 trace!("sending CONNECTION_CLOSE");
1658 let is_multipath_negotiated = self.is_multipath_negotiated();
1663 for path_id in self.spaces[space_id]
1664 .number_spaces
1665 .iter()
1666 .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty())
1667 .map(|(&path_id, _)| path_id)
1668 .collect::<Vec<_>>()
1669 {
1670 Self::populate_acks(
1671 now,
1672 self.receiving_ecn,
1673 path_id,
1674 space_id,
1675 &mut self.spaces[space_id],
1676 is_multipath_negotiated,
1677 &mut builder,
1678 &mut self.path_stats.get_mut(path_id).frame_tx,
1679 self.crypto_state.has_keys(space_id.encryption_level()),
1680 );
1681 }
1682
1683 debug_assert!(
1691 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND,
1692 "ACKs should leave space for ConnectionClose"
1693 );
1694 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
1695 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() {
1696 let max_frame_size = builder.frame_space_remaining();
1697 let close: Close = match self.state.as_type() {
1698 StateType::Closed => {
1699 let reason: Close =
1700 self.state.as_closed().expect("checked").clone().into();
1701 if space_id == SpaceId::Data || reason.is_transport_layer() {
1702 reason
1703 } else {
1704 TransportError::APPLICATION_ERROR("").into()
1705 }
1706 }
1707 StateType::Draining => TransportError::NO_ERROR("").into(),
1708 _ => unreachable!(
1709 "tried to make a close packet when the connection wasn't closed"
1710 ),
1711 };
1712 builder.write_frame(close.encoder(max_frame_size), stats);
1713 }
1714 let last_pn = builder.packet_number;
1715 builder.finish_and_track(now, self, path_id, pad_datagram);
1716 if space_id.kind() == self.highest_space {
1717 self.connection_close_pending = false;
1720 }
1721 return PollPathSpaceStatus::WrotePacket {
1734 last_packet_number: last_pn,
1735 pad_datagram,
1736 };
1737 }
1738
1739 self.populate_packet(now, space_id, path_id, scheduling_info, &mut builder);
1740
1741 debug_assert!(
1748 !(builder.sent_frames().is_ack_only(&self.streams)
1749 && !can_send.acks
1750 && (can_send.other || can_send.space_specific)
1751 && builder.buf.segment_size()
1752 == self.path_data(path_id).current_mtu() as usize
1753 && self.datagrams.outgoing.is_empty()),
1754 "SendableFrames was {can_send:?}, but only ACKs have been written"
1755 );
1756 if builder.sent_frames().requires_padding {
1757 pad_datagram |= PadDatagram::ToMinMtu;
1758 }
1759
1760 for path_id in builder.sent_frames().largest_acked.keys() {
1761 self.spaces[space_id]
1762 .for_path(*path_id)
1763 .pending_acks
1764 .acks_sent();
1765 self.timers.stop(
1766 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
1767 self.qlog.with_time(now),
1768 );
1769 }
1770
1771 let max_packet_size = builder
1777 .buf
1778 .datagram_remaining_mut()
1779 .saturating_sub(builder.predict_packet_end());
1780 if builder.can_coalesce
1783 && path_id == PathId::ZERO
1784 && let Some(next_space_id) = space_id.next()
1785 && max_packet_size > MIN_PACKET_SPACE
1786 && self
1787 .space_can_send(space_id, path_id, max_packet_size, connection_close_pending)
1788 .is_empty()
1789 && self.has_pending_packet(next_space_id, max_packet_size, connection_close_pending)
1790 {
1791 trace!("will coalesce with next packet");
1794 let last_pn = builder.packet_number;
1795 builder.finish_and_track(now, self, path_id, PadDatagram::No);
1796 return PollPathSpaceStatus::WrotePacket {
1799 last_packet_number: last_pn,
1800 pad_datagram,
1801 };
1802 } else {
1803 if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) {
1809 const MAX_PADDING: usize = 32;
1817 if builder.buf.datagram_remaining_mut()
1818 > builder.predict_packet_end() + MAX_PADDING
1819 {
1820 trace!(
1821 "GSO truncated by demand for {} padding bytes",
1822 builder.buf.datagram_remaining_mut() - builder.predict_packet_end()
1823 );
1824 let last_pn = builder.packet_number;
1825 builder.finish_and_track(now, self, path_id, PadDatagram::No);
1826 return PollPathSpaceStatus::Send {
1827 last_packet_number: last_pn,
1828 };
1829 }
1830
1831 builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize);
1834 } else {
1835 builder.finish_and_track(now, self, path_id, pad_datagram);
1836 }
1837
1838 if transmit.num_datagrams() == 1 {
1841 transmit.clip_segment_size();
1842 }
1843 }
1844 }
1845 }
1846
1847 fn poll_transmit_mtu_probe(
1848 &mut self,
1849 now: Instant,
1850 buf: &mut Vec<u8>,
1851 path_id: PathId,
1852 ) -> Option<Transmit> {
1853 let (active_cid, probe_size) = self.get_mtu_probe_data(now, path_id)?;
1854
1855 let mut transmit = TransmitBuf::new(buf, NonZeroUsize::MIN, probe_size as usize);
1857 transmit.start_new_datagram_with_size(probe_size as usize);
1858
1859 let mut builder =
1860 PacketBuilder::new(now, SpaceId::Data, path_id, active_cid, &mut transmit, self)?;
1861
1862 trace!(?probe_size, "writing MTUD probe");
1864 builder.write_frame(frame::Ping, &mut self.path_stats.get_mut(path_id).frame_tx);
1865
1866 if self.peer_supports_ack_frequency() {
1868 builder.write_frame(
1869 frame::ImmediateAck,
1870 &mut self.path_stats.get_mut(path_id).frame_tx,
1871 );
1872 }
1873
1874 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size));
1875
1876 self.path_stats.get_mut(path_id).sent_plpmtud_probes += 1;
1877
1878 Some(self.build_transmit(path_id, transmit))
1879 }
1880
1881 fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> {
1889 let active_cid = self.remote_cids.get(&path_id).map(CidQueue::active)?;
1890 let is_eligible = self.path_data(path_id).validated
1891 && !self.path_data(path_id).is_validating_path()
1892 && !self.abandoned_paths.contains(&path_id);
1893
1894 if !is_eligible {
1895 return None;
1896 }
1897 let next_pn = self.spaces[SpaceId::Data]
1898 .for_path(path_id)
1899 .peek_tx_number();
1900 let probe_size = self
1901 .path_data_mut(path_id)
1902 .mtud
1903 .poll_transmit(now, next_pn)?;
1904
1905 Some((active_cid, probe_size))
1906 }
1907
1908 fn has_pending_packet(
1925 &mut self,
1926 current_space_id: SpaceId,
1927 max_packet_size: usize,
1928 connection_close_pending: bool,
1929 ) -> bool {
1930 let mut space_id = current_space_id;
1931 loop {
1932 let can_send = self.space_can_send(
1933 space_id,
1934 PathId::ZERO,
1935 max_packet_size,
1936 connection_close_pending,
1937 );
1938 if !can_send.is_empty() {
1939 return true;
1940 }
1941 match space_id.next() {
1942 Some(next_space_id) => space_id = next_space_id,
1943 None => break,
1944 }
1945 }
1946 false
1947 }
1948
1949 fn path_congestion_check(
1951 &mut self,
1952 space_id: SpaceId,
1953 path_id: PathId,
1954 transmit: &TransmitBuf<'_>,
1955 can_send: &SendableFrames,
1956 now: Instant,
1957 ) -> PathBlocked {
1958 if self.side().is_server()
1964 && self
1965 .path_data(path_id)
1966 .anti_amplification_blocked(transmit.len() as u64 + 1)
1967 {
1968 trace!(?space_id, %path_id, "blocked by anti-amplification");
1969 return PathBlocked::AntiAmplification;
1970 }
1971
1972 let bytes_to_send = transmit.segment_size() as u64;
1975 let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1976
1977 if can_send.other && !need_loss_probe && !can_send.close {
1978 let path = self.path_data(path_id);
1979 if path.in_flight.bytes + bytes_to_send >= path.congestion.window() {
1980 trace!(
1981 ?space_id,
1982 %path_id,
1983 in_flight=%path.in_flight.bytes,
1984 congestion_window=%path.congestion.window(),
1985 "blocked by congestion control",
1986 );
1987 return PathBlocked::Congestion;
1988 }
1989 }
1990
1991 if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) {
1993 let resume_time = now + delay;
1994 self.timers.set(
1995 Timer::PerPath(path_id, PathTimer::Pacing),
1996 resume_time,
1997 self.qlog.with_time(now),
1998 );
1999 trace!(?space_id, %path_id, ?delay, "blocked by pacing");
2002 return PathBlocked::Pacing;
2003 }
2004
2005 PathBlocked::No
2006 }
2007
2008 fn send_prev_path_challenge(
2013 &mut self,
2014 now: Instant,
2015 buf: &mut Vec<u8>,
2016 path_id: PathId,
2017 ) -> Option<Transmit> {
2018 let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?;
2019 if !prev_path.pending_challenge {
2020 return None;
2021 };
2022 prev_path.pending_challenge = false;
2023 let token = self.rng.random();
2024 let network_path = prev_path.network_path;
2025 prev_path.record_path_challenge_sent(now, token, network_path);
2026
2027 debug_assert_eq!(
2028 self.highest_space,
2029 SpaceKind::Data,
2030 "PATH_CHALLENGE queued without 1-RTT keys"
2031 );
2032 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2033 buf.start_new_datagram();
2034
2035 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, self)?;
2041 let challenge = frame::PathChallenge(token);
2042 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2043 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path"));
2044
2045 builder.pad_to(MIN_INITIAL_SIZE);
2050
2051 builder.finish(self, now);
2052 self.path_stats
2053 .get_mut(path_id)
2054 .udp_tx
2055 .on_sent(1, buf.len());
2056
2057 trace!(
2058 dst = ?network_path.remote,
2059 src = ?network_path.local_ip,
2060 len = buf.len(),
2061 "sending prev_path off-path challenge",
2062 );
2063 Some(Transmit {
2064 destination: network_path.remote,
2065 size: buf.len(),
2066 ecn: None,
2067 segment_size: None,
2068 src_ip: network_path.local_ip,
2069 })
2070 }
2071
2072 fn send_off_path_path_response(
2073 &mut self,
2074 now: Instant,
2075 buf: &mut Vec<u8>,
2076 path_id: PathId,
2077 ) -> Option<Transmit> {
2078 let network_path = self
2079 .paths
2080 .get_mut(&path_id)
2081 .map(|state| state.data.network_path)?;
2082 let cid_queue = self.remote_cids.get_mut(&path_id)?;
2083 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
2084 let (token, network_path) = pns.pending_path_responses.pop_off_path(network_path)?;
2085
2086 let cid = cid_queue.active();
2088
2089 let frame = frame::PathResponse(token);
2091
2092 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2093 buf.start_new_datagram();
2094
2095 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, buf, self)?;
2096 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2097 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)"));
2098
2099 if self
2106 .find_validated_path_on_network_path(network_path)
2107 .is_none()
2108 && self.n0_nat_traversal.client_side().is_ok()
2109 {
2110 let token = self.rng.random();
2111 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2112 builder.write_frame(frame::PathChallenge(token), stats);
2113 let ip_port = (network_path.remote.ip(), network_path.remote.port());
2114 self.n0_nat_traversal.mark_probe_sent(ip_port, token);
2115 }
2116
2117 builder.pad_to(MIN_INITIAL_SIZE);
2120 builder.finish(self, now);
2121
2122 let size = buf.len();
2123 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2124
2125 trace!(
2126 dst = ?network_path.remote,
2127 src = ?network_path.local_ip,
2128 len = buf.len(),
2129 "sending off-path PATH_RESPONSE",
2130 );
2131 Some(Transmit {
2132 destination: network_path.remote,
2133 size,
2134 ecn: None,
2135 segment_size: None,
2136 src_ip: network_path.local_ip,
2137 })
2138 }
2139
2140 fn send_nat_traversal_path_challenge(
2142 &mut self,
2143 now: Instant,
2144 buf: &mut Vec<u8>,
2145 path_id: PathId,
2146 ) -> Option<Transmit> {
2147 let remote = self.n0_nat_traversal.next_probe_addr()?;
2148
2149 if !self.paths.get(&path_id)?.data.validated {
2150 return None;
2152 }
2153
2154 let Some(cid) = self
2159 .remote_cids
2160 .get(&path_id)
2161 .map(|cid_queue| cid_queue.active())
2162 else {
2163 trace!(%path_id, "Not sending NAT traversal probe for path with no CIDs");
2164 return None;
2165 };
2166 let token = self.rng.random();
2167
2168 let frame = frame::PathChallenge(token);
2170
2171 let mut buf = TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2172 buf.start_new_datagram();
2173
2174 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, &mut buf, self)?;
2175 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2176 builder.write_frame_with_log_msg(frame, stats, Some("(nat-traversal)"));
2177 builder.finish(self, now);
2180
2181 self.n0_nat_traversal.mark_probe_sent(remote, token);
2183
2184 let size = buf.len();
2185 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2186
2187 trace!(dst = ?remote, len = buf.len(), "sending off-path NAT probe");
2188 Some(Transmit {
2189 destination: remote.into(),
2190 size,
2191 ecn: None,
2192 segment_size: None,
2193 src_ip: None,
2194 })
2195 }
2196
2197 fn space_can_send(
2205 &mut self,
2206 space_id: SpaceId,
2207 path_id: PathId,
2208 packet_size: usize,
2209 connection_close_pending: bool,
2210 ) -> SendableFrames {
2211 let space = &mut self.spaces[space_id];
2212 let space_has_crypto = self.crypto_state.has_keys(space_id.encryption_level());
2213
2214 if !space_has_crypto
2215 && (space_id != SpaceId::Data
2216 || !self.crypto_state.has_keys(EncryptionLevel::ZeroRtt)
2217 || self.side.is_server())
2218 {
2219 return SendableFrames::empty();
2221 }
2222
2223 let mut can_send = space.can_send(path_id, &self.streams);
2224
2225 if space_id == SpaceId::Data {
2227 let pn = space.for_path(path_id).peek_tx_number();
2228 let frame_space_1rtt =
2234 packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id));
2235 can_send |= self.can_send_1rtt(path_id, frame_space_1rtt);
2236 }
2237
2238 can_send.close = connection_close_pending && space_has_crypto;
2239
2240 can_send
2241 }
2242
2243 pub fn handle_event(&mut self, event: ConnectionEvent) {
2249 use ConnectionEventInner::*;
2250 match event.0 {
2251 Datagram(DatagramConnectionEvent {
2252 now,
2253 network_path,
2254 path_id,
2255 ecn,
2256 first_decode,
2257 remaining,
2258 }) => {
2259 let span = trace_span!("pkt", %path_id);
2260 let _guard = span.enter();
2261
2262 if self.early_discard_packet(network_path, path_id) {
2263 return;
2265 }
2266
2267 let was_anti_amplification_blocked = self
2268 .path(path_id)
2269 .map(|path| path.anti_amplification_blocked(1))
2270 .unwrap_or(false);
2273
2274 let rx = &mut self.path_stats.get_mut(path_id).udp_rx;
2275 rx.datagrams += 1;
2276 rx.bytes += first_decode.len() as u64;
2277 let data_len = first_decode.len();
2278
2279 self.handle_decode(now, network_path, path_id, ecn, first_decode);
2280 if let Some(path) = self.path_mut(path_id) {
2285 path.inc_total_recvd(data_len as u64);
2286 }
2287
2288 if let Some(data) = remaining {
2289 self.path_stats.get_mut(path_id).udp_rx.bytes += data.len() as u64;
2290 self.handle_coalesced(now, network_path, path_id, ecn, data);
2291 }
2292
2293 if let Some(path) = self.paths.get_mut(&path_id) {
2294 self.qlog
2295 .emit_recovery_metrics(path_id, &mut path.data, now);
2296 }
2297
2298 if was_anti_amplification_blocked {
2299 self.set_loss_detection_timer(now, path_id);
2303 }
2304 }
2305 NewIdentifiers(ids, now, cid_len, cid_lifetime) => {
2306 let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default();
2307 debug_assert!(ids.iter().all(|issued| issued.path_id == path_id));
2308
2309 if self.abandoned_paths.contains(&path_id) {
2312 if !self.state.is_drained() {
2313 for issued in &ids {
2314 self.endpoint_events
2315 .push_back(EndpointEventInner::RetireConnectionId(
2316 now,
2317 path_id,
2318 issued.sequence,
2319 false,
2320 ));
2321 }
2322 }
2323 return;
2324 }
2325
2326 let cid_state = self
2327 .local_cid_state
2328 .entry(path_id)
2329 .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0));
2330 cid_state.new_cids(&ids, now);
2331
2332 ids.into_iter().rev().for_each(|frame| {
2333 self.spaces[SpaceId::Data].pending.new_cids.push(frame);
2334 });
2335 self.reset_cid_retirement(now);
2337 }
2338 }
2339 }
2340
2341 fn early_discard_packet(&mut self, network_path: FourTuple, path_id: PathId) -> bool {
2349 if self.is_handshaking() && path_id != PathId::ZERO {
2350 debug!(%network_path, %path_id, "discarding multipath packet during handshake");
2351 return true;
2352 }
2353
2354 if !self.paths.contains_key(&path_id) && self.abandoned_paths.contains(&path_id) {
2355 trace!(%path_id, "discarding packet for discarded path");
2356 return true;
2357 }
2358
2359 let peer_may_probe = self.peer_may_probe();
2360 let local_ip_may_migrate = self.local_ip_may_migrate();
2361
2362 if let Some(known_path) = self.path_mut(path_id) {
2366 if network_path.remote != known_path.network_path.remote && !peer_may_probe {
2367 trace!(
2368 %path_id,
2369 %network_path,
2370 %known_path.network_path,
2371 "discarding packet from unrecognized peer"
2372 );
2373 return true;
2374 }
2375
2376 if known_path.network_path.local_ip.is_some()
2377 && network_path.local_ip.is_some()
2378 && known_path.network_path.local_ip != network_path.local_ip
2379 && !local_ip_may_migrate
2380 {
2381 trace!(
2382 %path_id,
2383 %network_path,
2384 %known_path.network_path,
2385 "discarding packet sent to incorrect interface"
2386 );
2387 return true;
2388 }
2389 }
2390 false
2391 }
2392
2393 fn peer_may_probe(&self) -> bool {
2404 match &self.side {
2405 ConnectionSide::Client { .. } => {
2406 if let Some(hs) = self.state.as_handshake() {
2407 hs.allow_server_migration
2408 } else {
2409 self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed()
2410 }
2411 }
2412 ConnectionSide::Server { server_config } => {
2413 self.is_handshake_confirmed()
2414 && (server_config.migration || self.n0_nat_traversal.is_negotiated())
2415 }
2416 }
2417 }
2418
2419 fn peer_may_migrate(&self) -> bool {
2431 match &self.side {
2432 ConnectionSide::Server { server_config } => {
2433 server_config.migration && self.is_handshake_confirmed()
2434 }
2435 ConnectionSide::Client { .. } => false,
2436 }
2437 }
2438
2439 fn local_ip_may_migrate(&self) -> bool {
2452 (self.side.is_client() || self.n0_nat_traversal.is_negotiated())
2453 && self.is_handshake_confirmed()
2454 }
2455 pub fn handle_timeout(&mut self, now: Instant) {
2465 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) {
2466 let span = match timer {
2467 Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer),
2468 Timer::PerPath(path_id, timer) => {
2469 trace_span!("timer_fired", scope="path", %path_id, ?timer)
2470 }
2471 };
2472 let _guard = span.enter();
2473 trace!("timeout");
2474 match timer {
2475 Timer::Conn(timer) => match timer {
2476 ConnTimer::Close => {
2477 self.state.move_to_drained(None, &mut self.endpoint_events);
2478 }
2479 ConnTimer::Idle => {
2480 self.kill(ConnectionError::TimedOut);
2481 }
2482 ConnTimer::KeepAlive => {
2483 self.ping();
2484 }
2485 ConnTimer::KeyDiscard => {
2486 self.crypto_state.discard_temporary_keys();
2487 }
2488 ConnTimer::PushNewCid => {
2489 while let Some((path_id, when)) = self.next_cid_retirement() {
2490 if when > now {
2491 break;
2492 }
2493 match self.local_cid_state.get_mut(&path_id) {
2494 None => error!(%path_id, "No local CID state for path"),
2495 Some(cid_state) => {
2496 let num_new_cid = cid_state.on_cid_timeout().into();
2498 if !self.state.is_closed() {
2499 trace!(
2500 "push a new CID to peer RETIRE_PRIOR_TO field {}",
2501 cid_state.retire_prior_to()
2502 );
2503 self.endpoint_events.push_back(
2504 EndpointEventInner::NeedIdentifiers(
2505 path_id,
2506 now,
2507 num_new_cid,
2508 ),
2509 );
2510 }
2511 }
2512 }
2513 }
2514 }
2515 ConnTimer::NoAvailablePath => {
2516 if self.state.is_closed() || self.state.is_drained() {
2521 error!("no viable path timer fired, but connection already closing");
2524 } else {
2525 trace!("no viable path grace period expired, closing connection");
2526 let err = TransportError::NO_VIABLE_PATH(
2527 "last path abandoned, no new path opened",
2528 );
2529 self.close_common();
2530 self.set_close_timer(now);
2531 self.connection_close_pending = true;
2532 self.state.move_to_closed(err);
2533 }
2534 }
2535 ConnTimer::NatTraversalProbeRetry => {
2536 self.n0_nat_traversal.queue_retries(self.is_ipv6());
2537 if let Some(delay) =
2538 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
2539 {
2540 self.timers.set(
2541 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
2542 now + delay,
2543 self.qlog.with_time(now),
2544 );
2545 trace!("re-queued NAT probes");
2546 } else {
2547 trace!("no more NAT probes remaining");
2548 }
2549 }
2550 },
2551 Timer::PerPath(path_id, timer) => {
2552 match timer {
2553 PathTimer::PathIdle => {
2554 if let Err(err) =
2555 self.close_path_inner(now, path_id, PathAbandonReason::TimedOut)
2556 {
2557 warn!(?err, "failed closing path");
2558 }
2559 }
2560
2561 PathTimer::PathKeepAlive => {
2562 self.ping_path(path_id).ok();
2563 }
2564 PathTimer::LossDetection => {
2565 self.on_loss_detection_timeout(now, path_id);
2566 if let Some(path) = self.paths.get_mut(&path_id) {
2567 self.qlog
2568 .emit_recovery_metrics(path_id, &mut path.data, now);
2569 } else {
2570 error!("LossDetection fired for unknown path");
2571 }
2572 }
2573 PathTimer::PathValidationFailed => {
2574 let Some(path) = self.paths.get_mut(&path_id) else {
2575 continue;
2576 };
2577 self.timers.stop(
2578 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2579 self.qlog.with_time(now),
2580 );
2581 debug!("path migration validation failed");
2582 path.data.reset_on_path_challenges();
2583 if let Some((_, prev)) = path.prev.take() {
2584 path.data = prev;
2585 self.set_loss_detection_timer(now, path_id);
2586 }
2587 }
2588 PathTimer::PathChallengeLost => {
2589 let Some(path) = self.paths.get_mut(&path_id) else {
2590 continue;
2591 };
2592 trace!(?path.data.lost_challenge_count, "path challenge deemed lost");
2593 path.data.pending_challenge = true;
2594 path.data.lost_challenge_count += 1;
2595 self.timers.set(
2596 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2597 now + path.data.on_path_challenge_pto(),
2598 self.qlog.with_time(now),
2599 );
2600 }
2601 PathTimer::Pacing => {}
2602 PathTimer::MaxAckDelay => {
2603 self.spaces[SpaceId::Data]
2605 .for_path(path_id)
2606 .pending_acks
2607 .on_max_ack_delay_timeout()
2608 }
2609 PathTimer::PathDrained => {
2610 self.timers.stop_per_path(path_id, self.qlog.with_time(now));
2613 if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) {
2614 debug_assert!(!self.state.is_drained()); let (min_seq, max_seq) = local_cid_state.active_seq();
2616 for seq in min_seq..=max_seq {
2617 self.endpoint_events.push_back(
2618 EndpointEventInner::RetireConnectionId(
2619 now, path_id, seq, false,
2620 ),
2621 );
2622 }
2623 }
2624 self.discard_path(path_id, now);
2625 }
2626 }
2627 }
2628 }
2629 }
2630 }
2631
2632 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) {
2644 self.close_inner(
2645 now,
2646 Close::Application(frame::ApplicationClose { error_code, reason }),
2647 )
2648 }
2649
2650 fn close_inner(&mut self, now: Instant, reason: Close) {
2666 let was_closed = self.state.is_closed();
2667 if !was_closed {
2668 self.close_common();
2669 self.set_close_timer(now);
2670 self.connection_close_pending = true;
2671 self.state.move_to_closed_local(reason);
2672 }
2673 }
2674
2675 pub fn datagrams(&mut self) -> Datagrams<'_> {
2677 Datagrams { conn: self }
2678 }
2679
2680 pub fn stats(&mut self) -> ConnectionStats {
2682 let mut stats = self.partial_stats.clone();
2683
2684 for path_stats in self.path_stats.iter_stats() {
2685 stats += *path_stats;
2690 }
2691
2692 stats
2693 }
2694
2695 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> {
2697 let path = self.paths.get(&path_id)?;
2698 let mut stats = self.path_stats.get(path_id).unwrap_or_default();
2699 stats.rtt = path.data.rtt.get();
2700 stats.cwnd = path.data.congestion.window();
2701 stats.current_mtu = path.data.mtud.current_mtu();
2702 Some(stats)
2703 }
2704
2705 pub fn ping(&mut self) {
2709 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() {
2712 path_data.pending_ping = true;
2713 }
2714 }
2715
2716 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> {
2720 let path_data = self.spaces[self.highest_space]
2721 .number_spaces
2722 .get_mut(&path)
2723 .ok_or(ClosedPath { _private: () })?;
2724 path_data.pending_ping = true;
2725 Ok(())
2726 }
2727
2728 pub fn force_key_update(&mut self) {
2732 if !self.state.is_established() {
2733 debug!("ignoring forced key update in illegal state");
2734 return;
2735 }
2736 if self.crypto_state.prev_crypto.is_some() {
2737 debug!("ignoring redundant forced key update");
2740 return;
2741 }
2742 self.crypto_state.update_keys(None, false);
2743 }
2744
2745 pub fn crypto_session(&self) -> &dyn crypto::Session {
2747 self.crypto_state.session.as_ref()
2748 }
2749
2750 pub fn is_handshaking(&self) -> bool {
2760 self.state.is_handshake()
2761 }
2762
2763 pub fn is_closed(&self) -> bool {
2774 self.state.is_closed()
2775 }
2776
2777 pub fn is_drained(&self) -> bool {
2782 self.state.is_drained()
2783 }
2784
2785 pub fn accepted_0rtt(&self) -> bool {
2789 self.crypto_state.accepted_0rtt
2790 }
2791
2792 pub fn has_0rtt(&self) -> bool {
2794 self.crypto_state.zero_rtt_enabled
2795 }
2796
2797 pub fn has_pending_retransmits(&self) -> bool {
2799 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams)
2800 }
2801
2802 pub fn side(&self) -> Side {
2804 self.side.side()
2805 }
2806
2807 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> {
2809 self.path(path_id)
2810 .map(|path_data| {
2811 path_data
2812 .last_observed_addr_report
2813 .as_ref()
2814 .map(|observed| observed.socket_addr())
2815 })
2816 .ok_or(ClosedPath { _private: () })
2817 }
2818
2819 pub fn rtt(&self, path_id: PathId) -> Option<Duration> {
2821 self.path(path_id).map(|d| d.rtt.get())
2822 }
2823
2824 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> {
2826 self.path(path_id).map(|d| d.congestion.as_ref())
2827 }
2828
2829 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) {
2834 self.streams.set_max_concurrent(dir, count);
2835 let pending = &mut self.spaces[SpaceId::Data].pending;
2838 self.streams.queue_max_stream_id(pending);
2839 }
2840
2841 pub fn set_max_concurrent_paths(
2851 &mut self,
2852 now: Instant,
2853 count: NonZeroU32,
2854 ) -> Result<(), MultipathNotNegotiated> {
2855 if !self.is_multipath_negotiated() {
2856 return Err(MultipathNotNegotiated { _private: () });
2857 }
2858 self.max_concurrent_paths = count;
2859
2860 let in_use_count = self
2861 .local_max_path_id
2862 .next()
2863 .saturating_sub(self.abandoned_paths.len())
2864 .as_u32();
2865 let extra_needed = count.get().saturating_sub(in_use_count);
2866 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed);
2867
2868 self.set_max_path_id(now, new_max_path_id);
2869
2870 Ok(())
2871 }
2872
2873 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) {
2875 if max_path_id <= self.local_max_path_id {
2876 return;
2877 }
2878
2879 self.local_max_path_id = max_path_id;
2880 self.spaces[SpaceId::Data].pending.max_path_id = true;
2881
2882 self.issue_first_path_cids(now);
2883 }
2884
2885 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 {
2892 self.streams.max_concurrent(dir)
2893 }
2894
2895 pub fn set_send_window(&mut self, send_window: u64) {
2897 self.streams.set_send_window(send_window);
2898 }
2899
2900 pub fn set_receive_window(&mut self, receive_window: VarInt) {
2902 if self.streams.set_receive_window(receive_window) {
2903 self.spaces[SpaceId::Data].pending.max_data = true;
2904 }
2905 }
2906
2907 pub fn is_multipath_negotiated(&self) -> bool {
2912 !self.is_handshaking()
2913 && self.config.max_concurrent_multipath_paths.is_some()
2914 && self.peer_params.initial_max_path_id.is_some()
2915 }
2916
2917 fn on_ack_received(
2918 &mut self,
2919 now: Instant,
2920 space: SpaceId,
2921 ack: frame::Ack,
2922 ) -> Result<(), TransportError> {
2923 let path = PathId::ZERO;
2925 self.inner_on_ack_received(now, space, path, ack)
2926 }
2927
2928 fn on_path_ack_received(
2929 &mut self,
2930 now: Instant,
2931 space: SpaceId,
2932 path_ack: frame::PathAck,
2933 ) -> Result<(), TransportError> {
2934 let (ack, path) = path_ack.into_ack();
2935 self.inner_on_ack_received(now, space, path, ack)
2936 }
2937
2938 fn inner_on_ack_received(
2940 &mut self,
2941 now: Instant,
2942 space: SpaceId,
2943 path: PathId,
2944 ack: frame::Ack,
2945 ) -> Result<(), TransportError> {
2946 if !self.spaces[space].number_spaces.contains_key(&path) {
2947 if self.abandoned_paths.contains(&path) {
2948 trace!("silently ignoring PATH_ACK on discarded path");
2954 return Ok(());
2955 } else {
2956 return Err(TransportError::PROTOCOL_VIOLATION(
2957 "received PATH_ACK with path ID never used",
2958 ));
2959 }
2960 }
2961 if ack.largest >= self.spaces[space].for_path(path).next_packet_number {
2962 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked"));
2963 }
2964 let new_largest_pn = {
2966 let space = &mut self.spaces[space].for_path(path);
2967 if space
2968 .largest_acked_packet_pn
2969 .is_none_or(|pn| ack.largest > pn)
2970 {
2971 space.largest_acked_packet_pn = Some(ack.largest);
2972 if let Some(info) = space.sent_packets.get(ack.largest) {
2973 space.largest_acked_packet_send_time = info.time_sent;
2977 }
2978 Some(ack.largest)
2979 } else {
2980 None
2981 }
2982 };
2983
2984 if self.detect_spurious_loss(&ack, space, path) {
2985 self.path_stats.get_mut(path).spurious_congestion_events += 1;
2986 self.path_data_mut(path)
2987 .congestion
2988 .on_spurious_congestion_event();
2989 }
2990
2991 let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new();
2993 for range in ack.iter() {
2994 self.spaces[space].for_path(path).check_ack(range.clone())?;
2995 for (pn, _) in self.spaces[space]
2996 .for_path(path)
2997 .sent_packets
2998 .iter_range(range)
2999 {
3000 newly_acked.insert_one(pn);
3001 }
3002 }
3003
3004 if newly_acked.is_empty() {
3005 return Ok(());
3006 }
3007
3008 let mut ack_eliciting_acked = false;
3009 for packet in newly_acked.elts() {
3010 if let Some(info) = self.spaces[space].for_path(path).take(packet) {
3011 for (acked_path_id, acked_pn) in info.largest_acked.iter() {
3012 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) {
3018 pns.pending_acks.subtract_below(*acked_pn);
3019 }
3020 }
3021 ack_eliciting_acked |= info.ack_eliciting;
3022
3023 let path_data = self.path_data_mut(path);
3025 let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size);
3026 if mtu_updated {
3027 path_data
3028 .congestion
3029 .on_mtu_update(path_data.mtud.current_mtu());
3030 }
3031
3032 self.ack_frequency.on_acked(path, packet);
3035
3036 self.on_packet_acked(now, path, packet, info);
3037 }
3038 }
3039
3040 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn;
3041 let path_data = self.path_data_mut(path);
3042 let app_limited = path_data.app_limited;
3043 let in_flight = path_data.in_flight.bytes;
3044
3045 path_data
3046 .congestion
3047 .on_end_acks(now, in_flight, app_limited, largest_ackd);
3048
3049 if new_largest_pn.is_some() && ack_eliciting_acked {
3050 let ack_delay = if space != SpaceId::Data {
3051 Duration::from_micros(0)
3052 } else {
3053 cmp::min(
3054 self.ack_frequency.peer_max_ack_delay,
3055 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0),
3056 )
3057 };
3058 let rtt = now.saturating_duration_since(
3059 self.spaces[space]
3060 .for_path(path)
3061 .largest_acked_packet_send_time,
3062 );
3063
3064 let next_pn = self.spaces[space].for_path(path).next_packet_number;
3065 let path_data = self.path_data_mut(path);
3066 path_data.rtt.update(ack_delay, rtt);
3068 if path_data.first_packet_after_rtt_sample.is_none() {
3069 path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn));
3070 }
3071 }
3072
3073 self.detect_lost_packets(now, space, path, true);
3075
3076 if self.peer_completed_handshake_address_validation() {
3081 self.path_data_mut(path).pto_count = 0;
3082 }
3083
3084 if self.path_data(path).sending_ecn {
3089 if let Some(ecn) = ack.ecn {
3090 if let Some(largest_sent_pn) = new_largest_pn {
3095 let sent = self.spaces[space]
3096 .for_path(path)
3097 .largest_acked_packet_send_time;
3098 self.process_ecn(
3099 now,
3100 space,
3101 path,
3102 newly_acked.range_count() as u64,
3103 ecn,
3104 sent,
3105 largest_sent_pn,
3106 );
3107 }
3108 } else {
3109 debug!("ECN not acknowledged by peer");
3112 self.path_data_mut(path).sending_ecn = false;
3113 }
3114 }
3115
3116 self.set_loss_detection_timer(now, path);
3117 Ok(())
3118 }
3119
3120 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool {
3121 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3122
3123 if lost_packets.is_empty() {
3124 return false;
3125 }
3126
3127 for range in ack.iter() {
3128 let spurious_losses: Vec<u64> = lost_packets
3129 .iter_range(range.clone())
3130 .map(|(pn, _info)| pn)
3131 .collect();
3132
3133 for pn in spurious_losses {
3134 lost_packets.remove(pn);
3135 }
3136 }
3137
3138 lost_packets.is_empty()
3143 }
3144
3145 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) {
3150 let two_pto = 2 * self.path_data(path).rtt.pto_base();
3151
3152 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3153 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto);
3154 }
3155
3156 fn process_ecn(
3158 &mut self,
3159 now: Instant,
3160 space: SpaceId,
3161 path: PathId,
3162 newly_acked_pn: u64,
3163 ecn: frame::EcnCounts,
3164 largest_sent_time: Instant,
3165 largest_sent_pn: u64,
3166 ) {
3167 match self.spaces[space]
3168 .for_path(path)
3169 .detect_ecn(newly_acked_pn, ecn)
3170 {
3171 Err(e) => {
3172 debug!("halting ECN due to verification failure: {}", e);
3173
3174 self.path_data_mut(path).sending_ecn = false;
3175 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO;
3178 }
3179 Ok(false) => {}
3180 Ok(true) => {
3181 self.path_stats.get_mut(path).congestion_events += 1;
3182 self.path_data_mut(path).congestion.on_congestion_event(
3183 now,
3184 largest_sent_time,
3185 false,
3186 true,
3187 0,
3188 largest_sent_pn,
3189 );
3190 }
3191 }
3192 }
3193
3194 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, pn: u64, info: SentPacket) {
3197 let path = self.path_data_mut(path_id);
3198 let app_limited = path.app_limited;
3199 path.remove_in_flight(&info);
3200 if info.ack_eliciting && info.path_generation == path.generation() {
3201 let rtt = path.rtt;
3205 path.congestion
3206 .on_ack(now, info.time_sent, info.size.into(), pn, app_limited, &rtt);
3207 }
3208
3209 if let Some(retransmits) = info.retransmits.get() {
3211 for (id, _) in retransmits.reset_stream.iter() {
3212 self.streams.reset_acked(*id);
3213 }
3214 }
3215
3216 for frame in info.stream_frames {
3217 self.streams.received_ack_of(frame);
3218 }
3219 }
3220
3221 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) {
3222 let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) {
3223 now
3224 } else {
3225 self.crypto_state
3226 .prev_crypto
3227 .as_ref()
3228 .expect("no previous keys")
3229 .end_packet
3230 .as_ref()
3231 .expect("update not acknowledged yet")
3232 .1
3233 };
3234
3235 self.timers.set(
3237 Timer::Conn(ConnTimer::KeyDiscard),
3238 start + self.max_pto_for_space(space) * 3,
3239 self.qlog.with_time(now),
3240 );
3241 }
3242
3243 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) {
3256 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) {
3257 self.detect_lost_packets(now, pn_space, path_id, false);
3259 self.set_loss_detection_timer(now, path_id);
3260 return;
3261 }
3262
3263 let Some((_, space)) = self.pto_time_and_space(now, path_id) else {
3264 debug!(%path_id, "PTO expired while unset");
3265 return;
3266 };
3267 trace!(
3268 in_flight = self.path_data(path_id).in_flight.bytes,
3269 count = self.path_data(path_id).pto_count,
3270 ?space,
3271 %path_id,
3272 "PTO fired"
3273 );
3274
3275 let count = match self.path_data(path_id).in_flight.ack_eliciting {
3276 0 => {
3279 debug_assert!(!self.peer_completed_handshake_address_validation());
3280 1
3281 }
3282 _ => 2,
3284 };
3285 let pns = self.spaces[space].for_path(path_id);
3286 pns.loss_probes = pns.loss_probes.saturating_add(count);
3287 let path_data = self.path_data_mut(path_id);
3288 path_data.pto_count = path_data.pto_count.saturating_add(1);
3289 self.set_loss_detection_timer(now, path_id);
3290 }
3291
3292 fn detect_lost_packets(
3309 &mut self,
3310 now: Instant,
3311 pn_space: SpaceId,
3312 path_id: PathId,
3313 due_to_ack: bool,
3314 ) {
3315 let mut lost_packets = Vec::<u64>::new();
3316 let mut lost_mtu_probe = None;
3317 let mut in_persistent_congestion = false;
3318 let mut size_of_lost_packets = 0u64;
3319 self.spaces[pn_space].for_path(path_id).loss_time = None;
3320
3321 let path = self.path_data(path_id);
3324 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3325 let loss_delay = path
3326 .rtt
3327 .conservative()
3328 .mul_f32(self.config.time_threshold)
3329 .max(TIMER_GRANULARITY);
3330 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample;
3331
3332 let largest_acked_packet_pn = self.spaces[pn_space]
3333 .for_path(path_id)
3334 .largest_acked_packet_pn
3335 .expect("detect_lost_packets only to be called if path received at least one ACK");
3336 let packet_threshold = self.config.packet_threshold as u64;
3337
3338 let congestion_period = self
3342 .pto(SpaceKind::Data, path_id)
3343 .saturating_mul(self.config.persistent_congestion_threshold);
3344 let mut persistent_congestion_start: Option<Instant> = None;
3345 let mut prev_packet = None;
3346 let space = self.spaces[pn_space].for_path(path_id);
3347
3348 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) {
3349 if prev_packet != Some(packet.wrapping_sub(1)) {
3350 persistent_congestion_start = None;
3352 }
3353
3354 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay;
3358 if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold {
3359 if Some(packet) == in_flight_mtu_probe {
3361 lost_mtu_probe = in_flight_mtu_probe;
3364 } else {
3365 lost_packets.push(packet);
3366 size_of_lost_packets += info.size as u64;
3367 if info.ack_eliciting && due_to_ack {
3368 match persistent_congestion_start {
3369 Some(start) if info.time_sent - start > congestion_period => {
3372 in_persistent_congestion = true;
3373 }
3374 None if first_packet_after_rtt_sample
3376 .is_some_and(|x| x < (pn_space.kind(), packet)) =>
3377 {
3378 persistent_congestion_start = Some(info.time_sent);
3379 }
3380 _ => {}
3381 }
3382 }
3383 }
3384 } else {
3385 if space.loss_time.is_none() {
3387 space.loss_time = Some(info.time_sent + loss_delay);
3390 }
3391 persistent_congestion_start = None;
3392 }
3393
3394 prev_packet = Some(packet);
3395 }
3396
3397 self.handle_lost_packets(
3398 pn_space,
3399 path_id,
3400 now,
3401 lost_packets,
3402 lost_mtu_probe,
3403 loss_delay,
3404 in_persistent_congestion,
3405 size_of_lost_packets,
3406 );
3407 }
3408
3409 fn discard_path(&mut self, path_id: PathId, now: Instant) {
3411 trace!(%path_id, "dropping path state");
3412 let path = self.path_data(path_id);
3413 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3414
3415 let mut size_of_lost_packets = 0u64; let lost_pns: Vec<_> = self.spaces[SpaceId::Data]
3417 .for_path(path_id)
3418 .sent_packets
3419 .iter()
3420 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe)
3421 .map(|(pn, info)| {
3422 size_of_lost_packets += info.size as u64;
3423 pn
3424 })
3425 .collect();
3426
3427 if !lost_pns.is_empty() {
3428 trace!(
3429 %path_id,
3430 count = lost_pns.len(),
3431 lost_bytes = size_of_lost_packets,
3432 "packets lost on path abandon"
3433 );
3434 self.handle_lost_packets(
3435 SpaceId::Data,
3436 path_id,
3437 now,
3438 lost_pns,
3439 in_flight_mtu_probe,
3440 Duration::ZERO,
3441 false,
3442 size_of_lost_packets,
3443 );
3444 }
3445 let path_stats = self.path_stats(path_id).unwrap_or_default();
3448 self.path_stats.discard(&path_id);
3449 self.partial_stats += path_stats;
3450 self.paths.remove(&path_id);
3451 self.spaces[SpaceId::Data].number_spaces.remove(&path_id);
3452
3453 self.events.push_back(
3454 PathEvent::Discarded {
3455 id: path_id,
3456 path_stats: Box::new(path_stats),
3457 }
3458 .into(),
3459 );
3460 }
3461
3462 fn handle_lost_packets(
3463 &mut self,
3464 pn_space: SpaceId,
3465 path_id: PathId,
3466 now: Instant,
3467 lost_packets: Vec<u64>,
3468 lost_mtu_probe: Option<u64>,
3469 loss_delay: Duration,
3470 in_persistent_congestion: bool,
3471 size_of_lost_packets: u64,
3472 ) {
3473 debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted");
3474
3475 self.drain_lost_packets(now, pn_space, path_id);
3476
3477 if let Some(largest_lost) = lost_packets.last().cloned() {
3479 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes;
3480 let largest_lost_sent = self.spaces[pn_space]
3481 .for_path(path_id)
3482 .sent_packets
3483 .get(largest_lost)
3484 .unwrap()
3485 .time_sent;
3486 let path_stats = self.path_stats.get_mut(path_id);
3487 path_stats.lost_packets += lost_packets.len() as u64;
3488 path_stats.lost_bytes += size_of_lost_packets;
3489 trace!(
3490 %path_id,
3491 count = lost_packets.len(),
3492 lost_bytes = size_of_lost_packets,
3493 "packets lost",
3494 );
3495
3496 for &packet in &lost_packets {
3497 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else {
3498 continue;
3499 };
3500 self.qlog
3501 .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now);
3502 self.paths
3503 .get_mut(&path_id)
3504 .unwrap()
3505 .remove_in_flight(&info);
3506
3507 for frame in info.stream_frames {
3508 self.streams.retransmit(frame);
3509 }
3510 self.spaces[pn_space].pending |= info.retransmits;
3511 let path = self.path_data_mut(path_id);
3512 path.pending |= info.path_retransmits;
3513 path.mtud.on_non_probe_lost(packet, info.size);
3514 path.congestion.on_packet_lost(info.size, packet, now);
3515
3516 self.spaces[pn_space].for_path(path_id).lost_packets.insert(
3517 packet,
3518 LostPacket {
3519 time_sent: info.time_sent,
3520 },
3521 );
3522 }
3523
3524 let path = self.path_data_mut(path_id);
3525 if path.mtud.black_hole_detected(now) {
3526 path.congestion.on_mtu_update(path.mtud.current_mtu());
3527 if let Some(max_datagram_size) = self.datagrams().max_size()
3528 && self.datagrams.drop_oversized(max_datagram_size)
3529 && self.datagrams.send_blocked
3530 {
3531 self.datagrams.send_blocked = false;
3532 self.events.push_back(Event::DatagramsUnblocked);
3533 }
3534 self.path_stats.get_mut(path_id).black_holes_detected += 1;
3535 }
3536
3537 let lost_ack_eliciting =
3539 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes;
3540
3541 if lost_ack_eliciting {
3542 self.path_stats.get_mut(path_id).congestion_events += 1;
3543 self.path_data_mut(path_id).congestion.on_congestion_event(
3544 now,
3545 largest_lost_sent,
3546 in_persistent_congestion,
3547 false,
3548 size_of_lost_packets,
3549 largest_lost,
3550 );
3551 }
3552 }
3553
3554 if let Some(packet) = lost_mtu_probe {
3556 let info = self.spaces[SpaceId::Data]
3557 .for_path(path_id)
3558 .take(packet)
3559 .unwrap(); self.paths
3562 .get_mut(&path_id)
3563 .unwrap()
3564 .remove_in_flight(&info);
3565 self.path_data_mut(path_id).mtud.on_probe_lost();
3566 self.path_stats.get_mut(path_id).lost_plpmtud_probes += 1;
3567 }
3568 }
3569
3570 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> {
3576 SpaceId::iter()
3577 .filter_map(|id| {
3578 self.spaces[id]
3579 .number_spaces
3580 .get(&path_id)
3581 .and_then(|pns| pns.loss_time)
3582 .map(|time| (time, id))
3583 })
3584 .min_by_key(|&(time, _)| time)
3585 }
3586
3587 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> {
3595 let path = self.path(path_id)?;
3596 let pto_count = path.pto_count;
3597
3598 let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD {
3600 (path.rtt.get() * 3) / 2
3602 } else if let Some(idle) = path.idle_timeout.or(self.idle_timeout)
3603 && idle <= MIN_IDLE_FOR_FAST_PTO
3604 {
3605 MAX_PTO_FAST_INTERVAL
3608 } else {
3609 MAX_PTO_INTERVAL
3611 };
3612
3613 if path_id == PathId::ZERO
3614 && path.in_flight.ack_eliciting == 0
3615 && !self.peer_completed_handshake_address_validation()
3616 {
3617 let space = match self.highest_space {
3623 SpaceKind::Handshake => SpaceId::Handshake,
3624 _ => SpaceId::Initial,
3625 };
3626
3627 let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT));
3628 let duration = path.rtt.pto_base() * backoff;
3629 let duration = duration.min(max_interval);
3630 return Some((now + duration, space));
3631 }
3632
3633 let mut result = None;
3634 for space in SpaceId::iter() {
3635 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else {
3636 continue;
3637 };
3638
3639 if space == SpaceId::Data && !self.is_handshake_confirmed() {
3640 continue;
3644 }
3645
3646 if !pns.has_in_flight() {
3647 continue;
3648 }
3649
3650 let duration = {
3655 let max_ack_delay = if space == SpaceId::Data {
3656 self.ack_frequency.max_ack_delay_for_pto()
3657 } else {
3658 Duration::ZERO
3659 };
3660 let pto_base = path.rtt.pto_base() + max_ack_delay;
3661 let mut duration = pto_base;
3662 for i in 1..=pto_count {
3663 let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT));
3664 let max_duration = duration + max_interval;
3665 duration = exponential_duration.min(max_duration);
3666 }
3667 duration
3668 };
3669
3670 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else {
3671 continue;
3672 };
3673 let pto = last_ack_eliciting + duration;
3676 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) {
3677 if path.anti_amplification_blocked(1) {
3678 continue;
3680 }
3681 if path.in_flight.ack_eliciting == 0 {
3682 continue;
3684 }
3685 result = Some((pto, space));
3686 }
3687 }
3688 result
3689 }
3690
3691 fn peer_completed_handshake_address_validation(&self) -> bool {
3693 if self.side.is_server() || self.state.is_closed() {
3694 return true;
3695 }
3696 self.spaces[SpaceId::Handshake]
3700 .path_space(PathId::ZERO)
3701 .and_then(|pns| pns.largest_acked_packet_pn)
3702 .is_some()
3703 || self.spaces[SpaceId::Data]
3704 .path_space(PathId::ZERO)
3705 .and_then(|pns| pns.largest_acked_packet_pn)
3706 .is_some()
3707 || (self.crypto_state.has_keys(EncryptionLevel::OneRtt)
3708 && !self.crypto_state.has_keys(EncryptionLevel::Handshake))
3709 }
3710
3711 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) {
3719 if self.state.is_closed() {
3720 return;
3724 }
3725
3726 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) {
3727 self.timers.set(
3729 Timer::PerPath(path_id, PathTimer::LossDetection),
3730 loss_time,
3731 self.qlog.with_time(now),
3732 );
3733 return;
3734 }
3735
3736 if !self.abandoned_paths.contains(&path_id)
3739 && let Some((timeout, _)) = self.pto_time_and_space(now, path_id)
3740 {
3741 self.timers.set(
3742 Timer::PerPath(path_id, PathTimer::LossDetection),
3743 timeout,
3744 self.qlog.with_time(now),
3745 );
3746 } else {
3747 self.timers.stop(
3748 Timer::PerPath(path_id, PathTimer::LossDetection),
3749 self.qlog.with_time(now),
3750 );
3751 }
3752 }
3753
3754 fn max_pto_for_space(&self, space: SpaceKind) -> Duration {
3758 self.paths
3759 .keys()
3760 .map(|path_id| self.pto(space, *path_id))
3761 .max()
3762 .unwrap_or_else(|| {
3763 let rtt = self.config.initial_rtt;
3767 let max_ack_delay = match space {
3768 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3769 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3770 };
3771 rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay
3772 })
3773 }
3774
3775 fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration {
3780 let max_ack_delay = match space {
3781 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3782 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3783 };
3784 self.path_data(path_id).rtt.pto_base() + max_ack_delay
3785 }
3786
3787 fn on_packet_authenticated(
3788 &mut self,
3789 now: Instant,
3790 space_id: SpaceKind,
3791 path_id: PathId,
3792 ecn: Option<EcnCodepoint>,
3793 packet_number: Option<u64>,
3794 spin: bool,
3795 is_1rtt: bool,
3796 remote: &FourTuple,
3797 ) {
3798 let is_on_path = self
3805 .path_data(path_id)
3806 .network_path
3807 .is_probably_same_path(remote);
3808
3809 self.total_authed_packets += 1;
3810 self.reset_keep_alive(path_id, now);
3811 self.reset_idle_timeout(now, space_id, path_id);
3812 self.path_data_mut(path_id).permit_idle_reset = true;
3813
3814 if is_on_path {
3817 self.receiving_ecn |= ecn.is_some();
3818 if let Some(x) = ecn {
3819 let space = &mut self.spaces[space_id];
3820 space.for_path(path_id).ecn_counters += x;
3821
3822 if x.is_ce() {
3823 space
3824 .for_path(path_id)
3825 .pending_acks
3826 .set_immediate_ack_required();
3827 }
3828 }
3829 }
3830
3831 let Some(packet_number) = packet_number else {
3832 return;
3833 };
3834 match &self.side {
3835 ConnectionSide::Client { .. } => {
3836 if space_id == SpaceKind::Handshake
3840 && let Some(hs) = self.state.as_handshake_mut()
3841 {
3842 hs.allow_server_migration = false;
3843 }
3844 }
3845 ConnectionSide::Server { .. } => {
3846 if self.crypto_state.has_keys(EncryptionLevel::Initial)
3847 && space_id == SpaceKind::Handshake
3848 {
3849 self.discard_space(now, SpaceKind::Initial);
3852 }
3853 if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt {
3854 self.set_key_discard_timer(now, space_id)
3856 }
3857 }
3858 }
3859 let space = self.spaces[space_id].for_path(path_id);
3860
3861 space.pending_acks.insert_one(packet_number, now);
3862 if packet_number >= space.largest_received_packet_number.unwrap_or_default() {
3863 space.largest_received_packet_number = Some(packet_number);
3864
3865 if is_on_path {
3867 self.spin = self.side.is_client() ^ spin;
3868 }
3869 }
3870 }
3871
3872 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
3877 if let Some(timeout) = self.idle_timeout {
3879 if self.state.is_closed() {
3880 self.timers
3881 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now));
3882 } else {
3883 let dt = cmp::max(timeout, 3 * self.max_pto_for_space(space));
3884 self.timers.set(
3885 Timer::Conn(ConnTimer::Idle),
3886 now + dt,
3887 self.qlog.with_time(now),
3888 );
3889 }
3890 }
3891
3892 self.rearm_path_max_idle_timer(now, space, path_id);
3894 }
3895
3896 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) {
3898 if !self.state.is_established() {
3899 return;
3900 }
3901
3902 if let Some(interval) = self.config.keep_alive_interval {
3903 self.timers.set(
3904 Timer::Conn(ConnTimer::KeepAlive),
3905 now + interval,
3906 self.qlog.with_time(now),
3907 );
3908 }
3909
3910 if let Some(interval) = self.path_data(path_id).keep_alive {
3911 self.timers.set(
3912 Timer::PerPath(path_id, PathTimer::PathKeepAlive),
3913 now + interval,
3914 self.qlog.with_time(now),
3915 );
3916 }
3917 }
3918
3919 fn reset_cid_retirement(&mut self, now: Instant) {
3921 if let Some((_path, t)) = self.next_cid_retirement() {
3922 self.timers.set(
3923 Timer::Conn(ConnTimer::PushNewCid),
3924 t,
3925 self.qlog.with_time(now),
3926 );
3927 }
3928 }
3929
3930 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> {
3932 self.local_cid_state
3933 .iter()
3934 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t)))
3935 .min_by_key(|(_path_id, timeout)| *timeout)
3936 }
3937
3938 pub(crate) fn handle_first_packet(
3943 &mut self,
3944 now: Instant,
3945 network_path: FourTuple,
3946 ecn: Option<EcnCodepoint>,
3947 packet_number: u64,
3948 packet: InitialPacket,
3949 remaining: Option<BytesMut>,
3950 ) -> Result<(), ConnectionError> {
3951 let span = trace_span!("first recv");
3952 let _guard = span.enter();
3953 debug_assert!(self.side.is_server());
3954 let len = packet.header_data.len() + packet.payload.len();
3955 let path_id = PathId::ZERO;
3956 self.path_data_mut(path_id).total_recvd = len as u64;
3957
3958 if let Some(hs) = self.state.as_handshake_mut() {
3959 hs.expected_token = packet.header.token.clone();
3960 } else {
3961 unreachable!("first packet must be delivered in Handshake state");
3962 }
3963
3964 self.on_packet_authenticated(
3966 now,
3967 SpaceKind::Initial,
3968 path_id,
3969 ecn,
3970 Some(packet_number),
3971 false,
3972 false,
3973 &network_path,
3974 );
3975
3976 let packet: Packet = packet.into();
3977
3978 let mut qlog = QlogRecvPacket::new(len);
3979 qlog.header(&packet.header, Some(packet_number), path_id);
3980
3981 self.process_decrypted_packet(
3982 now,
3983 network_path,
3984 path_id,
3985 Some(packet_number),
3986 packet,
3987 &mut qlog,
3988 )?;
3989 self.qlog.emit_packet_received(qlog, now);
3990 if let Some(data) = remaining {
3991 self.handle_coalesced(now, network_path, path_id, ecn, data);
3992 }
3993
3994 self.qlog.emit_recovery_metrics(
3995 path_id,
3996 &mut self
3997 .paths
3998 .get_mut(&path_id)
3999 .expect("path_id was supplied by the caller for an active path")
4000 .data,
4001 now,
4002 );
4003
4004 Ok(())
4005 }
4006
4007 fn init_0rtt(&mut self, now: Instant) {
4008 let Some((header, packet)) = self.crypto_state.session.early_crypto() else {
4009 return;
4010 };
4011 if self.side.is_client() {
4012 match self.crypto_state.session.transport_parameters() {
4013 Ok(params) => {
4014 let params = params
4015 .expect("crypto layer didn't supply transport parameters with ticket");
4016 let params = TransportParameters {
4018 initial_src_cid: None,
4019 original_dst_cid: None,
4020 preferred_address: None,
4021 retry_src_cid: None,
4022 stateless_reset_token: None,
4023 min_ack_delay: None,
4024 ack_delay_exponent: TransportParameters::default().ack_delay_exponent,
4025 max_ack_delay: TransportParameters::default().max_ack_delay,
4026 initial_max_path_id: None,
4027 ..params
4028 };
4029 self.set_peer_params(params);
4030 self.qlog.emit_peer_transport_params_restored(self, now);
4031 }
4032 Err(e) => {
4033 error!("session ticket has malformed transport parameters: {}", e);
4034 return;
4035 }
4036 }
4037 }
4038 trace!("0-RTT enabled");
4039 self.crypto_state.enable_zero_rtt(header, packet);
4040 }
4041
4042 fn read_crypto(
4043 &mut self,
4044 space: SpaceId,
4045 crypto: &frame::Crypto,
4046 payload_len: usize,
4047 ) -> Result<(), TransportError> {
4048 let expected = if !self.state.is_handshake() {
4049 SpaceId::Data
4050 } else if self.highest_space == SpaceKind::Initial {
4051 SpaceId::Initial
4052 } else {
4053 SpaceId::Handshake
4056 };
4057 debug_assert!(space <= expected, "received out-of-order CRYPTO data");
4061
4062 let end = crypto.offset + crypto.data.len() as u64;
4063 if space < expected
4064 && end
4065 > self.crypto_state.spaces[space.kind()]
4066 .crypto_stream
4067 .bytes_read()
4068 {
4069 warn!(
4070 "received new {:?} CRYPTO data when expecting {:?}",
4071 space, expected
4072 );
4073 return Err(TransportError::PROTOCOL_VIOLATION(
4074 "new data at unexpected encryption level",
4075 ));
4076 }
4077
4078 let crypto_space = &mut self.crypto_state.spaces[space.kind()];
4079 let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read());
4080 if max > self.config.crypto_buffer_size as u64 {
4081 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED(""));
4082 }
4083
4084 crypto_space
4085 .crypto_stream
4086 .insert(crypto.offset, crypto.data.clone(), payload_len);
4087 while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) {
4088 trace!("consumed {} CRYPTO bytes", chunk.bytes.len());
4089 if self.crypto_state.session.read_handshake(&chunk.bytes)? {
4090 self.events.push_back(Event::HandshakeDataReady);
4091 }
4092 }
4093
4094 Ok(())
4095 }
4096
4097 fn write_crypto(&mut self) {
4098 loop {
4099 let space = self.highest_space;
4100 let mut outgoing = Vec::new();
4101 if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) {
4102 match space {
4103 SpaceKind::Initial => {
4104 self.upgrade_crypto(SpaceKind::Handshake, crypto);
4105 }
4106 SpaceKind::Handshake => {
4107 self.upgrade_crypto(SpaceKind::Data, crypto);
4108 }
4109 SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"),
4110 }
4111 }
4112 if outgoing.is_empty() {
4113 if space == self.highest_space {
4114 break;
4115 } else {
4116 continue;
4118 }
4119 }
4120 let offset = self.crypto_state.spaces[space].crypto_offset;
4121 let outgoing = Bytes::from(outgoing);
4122 if let Some(hs) = self.state.as_handshake_mut()
4123 && space == SpaceKind::Initial
4124 && offset == 0
4125 && self.side.is_client()
4126 {
4127 hs.client_hello = Some(outgoing.clone());
4128 }
4129 self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64;
4130 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space);
4131 self.spaces[space].pending.crypto.push_back(frame::Crypto {
4132 offset,
4133 data: outgoing,
4134 });
4135 }
4136 }
4137
4138 fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) {
4140 debug_assert!(
4141 !self.crypto_state.has_keys(space.encryption_level()),
4142 "already reached packet space {space:?}"
4143 );
4144 trace!("{:?} keys ready", space);
4145 if space == SpaceKind::Data {
4146 self.crypto_state.next_crypto = Some(
4148 self.crypto_state
4149 .session
4150 .next_1rtt_keys()
4151 .expect("handshake should be complete"),
4152 );
4153 }
4154
4155 self.crypto_state.spaces[space].keys = Some(crypto);
4156 debug_assert!(space > self.highest_space);
4157 self.highest_space = space;
4158 if space == SpaceKind::Data && self.side.is_client() {
4159 self.crypto_state.discard_zero_rtt();
4161 }
4162 }
4163
4164 fn discard_space(&mut self, now: Instant, space: SpaceKind) {
4165 debug_assert!(space != SpaceKind::Data);
4166 trace!("discarding {:?} keys", space);
4167 if space == SpaceKind::Initial {
4168 if let ConnectionSide::Client { token, .. } = &mut self.side {
4170 *token = Bytes::new();
4171 }
4172 }
4173 self.crypto_state.spaces[space].keys = None;
4174 let space = &mut self.spaces[space];
4175 let pns = space.for_path(PathId::ZERO);
4176 pns.time_of_last_ack_eliciting_packet = None;
4177 pns.loss_time = None;
4178 pns.loss_probes = 0;
4179 let sent_packets = mem::take(&mut pns.sent_packets);
4180 let path = self
4181 .paths
4182 .get_mut(&PathId::ZERO)
4183 .expect("PathId::ZERO is alive while Initial/Handshake spaces exist");
4184 for (_, packet) in sent_packets.into_iter() {
4185 path.data.remove_in_flight(&packet);
4186 }
4187
4188 self.set_loss_detection_timer(now, PathId::ZERO)
4189 }
4190
4191 fn handle_coalesced(
4192 &mut self,
4193 now: Instant,
4194 network_path: FourTuple,
4195 path_id: PathId,
4196 ecn: Option<EcnCodepoint>,
4197 data: BytesMut,
4198 ) {
4199 let Some(path) = self.paths.get_mut(&path_id) else {
4200 trace!(%path_id, "discarding coalesced datagram tail for unknown path");
4201 return;
4202 };
4203 path.data.inc_total_recvd(data.len() as u64);
4204 let mut remaining = Some(data);
4205 let cid_len = self
4206 .local_cid_state
4207 .values()
4208 .map(|cid_state| cid_state.cid_len())
4209 .next()
4210 .expect("one cid_state must exist");
4211 while let Some(data) = remaining {
4212 match PartialDecode::new(
4213 data,
4214 &FixedLengthConnectionIdParser::new(cid_len),
4215 &[self.version],
4216 self.endpoint_config.grease_quic_bit,
4217 ) {
4218 Ok((partial_decode, rest)) => {
4219 remaining = rest;
4220 self.handle_decode(now, network_path, path_id, ecn, partial_decode);
4221 }
4222 Err(e) => {
4223 trace!("malformed header: {}", e);
4224 return;
4225 }
4226 }
4227 }
4228 }
4229
4230 fn handle_decode(
4236 &mut self,
4237 now: Instant,
4238 network_path: FourTuple,
4239 path_id: PathId,
4240 ecn: Option<EcnCodepoint>,
4241 partial_decode: PartialDecode,
4242 ) {
4243 let qlog = QlogRecvPacket::new(partial_decode.len());
4244 if let Some(decoded) = self
4245 .crypto_state
4246 .unprotect_header(partial_decode, self.peer_params.stateless_reset_token)
4247 {
4248 self.handle_packet(
4249 now,
4250 network_path,
4251 path_id,
4252 ecn,
4253 decoded.packet,
4254 decoded.stateless_reset,
4255 qlog,
4256 );
4257 }
4258 }
4259
4260 fn handle_packet(
4267 &mut self,
4268 now: Instant,
4269 network_path: FourTuple,
4270 path_id: PathId,
4271 ecn: Option<EcnCodepoint>,
4272 packet: Option<Packet>,
4273 stateless_reset: bool,
4274 mut qlog: QlogRecvPacket,
4275 ) {
4276 if let Some(ref packet) = packet {
4277 trace!(
4278 "got {:?} packet ({} bytes) from {} using id {}",
4279 packet.header.space(),
4280 packet.payload.len() + packet.header_data.len(),
4281 network_path,
4282 packet.header.dst_cid(),
4283 );
4284 }
4285
4286 let was_closed = self.state.is_closed();
4287 let was_drained = self.state.is_drained();
4288
4289 let decrypted = match packet {
4291 None => Err(None),
4292 Some(mut packet) => self
4293 .decrypt_packet(now, path_id, &mut packet)
4294 .map(move |number| (packet, number)),
4295 };
4296 let result = match decrypted {
4297 _ if stateless_reset => {
4298 debug!("got stateless reset");
4299 Err(ConnectionError::Reset)
4300 }
4301 Err(Some(e)) => {
4302 warn!("illegal packet: {}", e);
4303 Err(e.into())
4304 }
4305 Err(None) => {
4306 debug!("failed to authenticate packet");
4307 self.authentication_failures += 1;
4308 let integrity_limit = self
4309 .crypto_state
4310 .integrity_limit(self.highest_space)
4311 .unwrap();
4312 if self.authentication_failures > integrity_limit {
4313 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into())
4314 } else {
4315 return;
4316 }
4317 }
4318 Ok((packet, pn)) => {
4319 qlog.header(&packet.header, pn, path_id);
4321 let span = match pn {
4322 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn),
4323 None => trace_span!("recv", space = ?packet.header.space()),
4324 };
4325 let _guard = span.enter();
4326
4327 if self.is_handshaking()
4335 && self
4336 .path(path_id)
4337 .map(|path_data| {
4338 !path_data.network_path.is_probably_same_path(&network_path)
4339 })
4340 .unwrap_or(false)
4341 {
4342 if let Some(hs) = self.state.as_handshake()
4343 && hs.allow_server_migration
4344 {
4345 trace!(
4346 %network_path,
4347 prev = %self.path_data(path_id).network_path,
4348 "server migrated to new remote",
4349 );
4350 self.path_data_mut(path_id).network_path = network_path;
4351 self.qlog.emit_tuple_assigned(path_id, network_path, now);
4352 } else {
4353 debug!(
4354 recv_path = %network_path,
4355 expected_path = %self.path_data_mut(path_id).network_path,
4356 "discarding packet with unexpected remote during handshake",
4357 );
4358 return;
4359 }
4360 }
4361
4362 let dedup = self.spaces[packet.header.space()]
4363 .path_space_mut(path_id)
4364 .map(|pns| &mut pns.dedup);
4365 if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) {
4366 debug!("discarding possible duplicate packet");
4367 self.qlog.emit_packet_received(qlog, now);
4368 return;
4369 } else if self.state.is_handshake() && packet.header.is_short() {
4370 trace!("dropping short packet during handshake");
4372 self.qlog.emit_packet_received(qlog, now);
4373 return;
4374 } else {
4375 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header
4376 && let Some(hs) = self.state.as_handshake()
4377 && self.side.is_server()
4378 && token != &hs.expected_token
4379 {
4380 warn!("discarding Initial with invalid retry token");
4384 self.qlog.emit_packet_received(qlog, now);
4385 return;
4386 }
4387
4388 if !self.state.is_closed() {
4389 let spin = match packet.header {
4390 Header::Short { spin, .. } => spin,
4391 _ => false,
4392 };
4393
4394 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) {
4395 self.create_network_path(path_id, network_path, now, pn);
4397 }
4398 if self.paths.contains_key(&path_id) {
4399 self.on_packet_authenticated(
4400 now,
4401 packet.header.space(),
4402 path_id,
4403 ecn,
4404 pn,
4405 spin,
4406 packet.header.is_1rtt(),
4407 &network_path,
4408 );
4409 }
4410 }
4411
4412 let res = self.process_decrypted_packet(
4413 now,
4414 network_path,
4415 path_id,
4416 pn,
4417 packet,
4418 &mut qlog,
4419 );
4420
4421 self.qlog.emit_packet_received(qlog, now);
4422 res
4423 }
4424 }
4425 };
4426
4427 if let Err(conn_err) = result {
4429 match conn_err {
4430 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason),
4431 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason),
4432 ConnectionError::Reset
4433 | ConnectionError::TransportError(TransportError {
4434 code: TransportErrorCode::AEAD_LIMIT_REACHED,
4435 ..
4436 }) => {
4437 if !self.state.is_drained() {
4438 self.state
4439 .move_to_drained(Some(conn_err), &mut self.endpoint_events);
4440 }
4441 }
4442 ConnectionError::TimedOut => {
4443 unreachable!("timeouts aren't generated by packet processing");
4444 }
4445 ConnectionError::TransportError(err) => {
4446 debug!("closing connection due to transport error: {}", err);
4447 self.state.move_to_closed(err);
4448 }
4449 ConnectionError::VersionMismatch => {
4450 self.state
4451 .move_to_draining(Some(conn_err), &mut self.endpoint_events);
4452 }
4453 ConnectionError::LocallyClosed => {
4454 unreachable!("LocallyClosed isn't generated by packet processing");
4455 }
4456 ConnectionError::CidsExhausted => {
4457 unreachable!("CidsExhausted isn't generated by packet processing");
4458 }
4459 };
4460 }
4461
4462 if !was_closed && self.state.is_closed() {
4463 self.close_common();
4464 if !self.state.is_drained() {
4465 self.set_close_timer(now);
4466 }
4467 }
4468 if !was_drained && self.state.is_drained() {
4469 self.timers
4472 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now));
4473 }
4474
4475 if matches!(self.state.as_type(), StateType::Closed) {
4482 if self
4500 .paths
4501 .get(&path_id)
4502 .map(|p| p.data.validated && p.data.network_path == network_path)
4503 .unwrap_or(false)
4504 {
4505 self.connection_close_pending = true;
4506 }
4507 }
4508 }
4509
4510 fn process_decrypted_packet(
4511 &mut self,
4512 now: Instant,
4513 network_path: FourTuple,
4514 path_id: PathId,
4515 number: Option<u64>,
4516 packet: Packet,
4517 qlog: &mut QlogRecvPacket,
4518 ) -> Result<(), ConnectionError> {
4519 if !self.paths.contains_key(&path_id) {
4520 trace!(%path_id, ?number, "discarding packet for unknown path");
4524 return Ok(());
4525 }
4526 let state = match self.state.as_type() {
4527 StateType::Established => {
4528 match packet.header.space() {
4529 SpaceKind::Data => self.process_payload(
4530 now,
4531 network_path,
4532 path_id,
4533 number.unwrap(),
4534 packet,
4535 qlog,
4536 )?,
4537 _ if packet.header.has_frames() => {
4538 self.process_early_payload(now, path_id, packet, qlog)?
4539 }
4540 _ => {
4541 trace!("discarding unexpected pre-handshake packet");
4542 }
4543 }
4544 return Ok(());
4545 }
4546 StateType::Closed => {
4547 for result in frame::Iter::new(packet.payload.freeze())? {
4548 let frame = match result {
4549 Ok(frame) => frame,
4550 Err(err) => {
4551 debug!("frame decoding error: {err:?}");
4552 continue;
4553 }
4554 };
4555 qlog.frame(&frame);
4556
4557 if let Frame::Padding = frame {
4558 continue;
4559 };
4560
4561 trace!(?frame, "processing frame in closed state");
4562
4563 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4564
4565 if let Frame::Close(_error) = frame {
4566 self.state.move_to_draining(None, &mut self.endpoint_events);
4567 break;
4568 }
4569 }
4570 return Ok(());
4571 }
4572 StateType::Draining | StateType::Drained => return Ok(()),
4573 StateType::Handshake => self.state.as_handshake_mut().expect("checked"),
4574 };
4575
4576 match packet.header {
4577 Header::Retry {
4578 src_cid: remote_cid,
4579 ..
4580 } => {
4581 debug_assert_eq!(path_id, PathId::ZERO);
4582 if self.side.is_server() {
4583 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into());
4584 }
4585
4586 let is_valid_retry = self
4587 .remote_cids
4588 .get(&path_id)
4589 .map(|cids| cids.active())
4590 .map(|orig_dst_cid| {
4591 self.crypto_state.session.is_valid_retry(
4592 orig_dst_cid,
4593 &packet.header_data,
4594 &packet.payload,
4595 )
4596 })
4597 .unwrap_or_default();
4598 if self.total_authed_packets > 1
4599 || packet.payload.len() <= 16 || !is_valid_retry
4601 {
4602 trace!("discarding invalid Retry");
4603 return Ok(());
4609 }
4610
4611 trace!("retrying with CID {}", remote_cid);
4612 let client_hello = state.client_hello.take().unwrap();
4613 self.retry_src_cid = Some(remote_cid);
4614 self.remote_cids
4615 .get_mut(&path_id)
4616 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false")
4617 .update_initial_cid(remote_cid);
4618 self.remote_handshake_cid = remote_cid;
4619
4620 let space = &mut self.spaces[SpaceId::Initial];
4621 if let Some(info) = space.for_path(PathId::ZERO).take(0) {
4622 self.on_packet_acked(now, PathId::ZERO, 0, info);
4623 };
4624
4625 self.discard_space(now, SpaceKind::Initial); let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial];
4628 crypto_space.keys = Some(
4629 self.crypto_state
4630 .session
4631 .initial_keys(remote_cid, self.side.side()),
4632 );
4633 crypto_space.crypto_offset = client_hello.len() as u64;
4634
4635 let next_pn = self.spaces[SpaceId::Initial]
4636 .for_path(path_id)
4637 .next_packet_number;
4638 self.spaces[SpaceId::Initial] = {
4639 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng);
4640 space.for_path(path_id).next_packet_number = next_pn;
4641 space.pending.crypto.push_back(frame::Crypto {
4642 offset: 0,
4643 data: client_hello,
4644 });
4645 space
4646 };
4647
4648 let zero_rtt = mem::take(
4650 &mut self.spaces[SpaceId::Data]
4651 .for_path(PathId::ZERO)
4652 .sent_packets,
4653 );
4654 for (_, info) in zero_rtt.into_iter() {
4655 self.paths
4656 .get_mut(&PathId::ZERO)
4657 .unwrap()
4658 .remove_in_flight(&info);
4659 self.spaces[SpaceId::Data].pending |= info.retransmits;
4660 }
4661 self.streams.retransmit_all_for_0rtt();
4662
4663 let token_len = packet.payload.len() - 16;
4664 let ConnectionSide::Client { ref mut token, .. } = self.side else {
4665 unreachable!("we already short-circuited if we're server");
4666 };
4667 *token = packet.payload.freeze().split_to(token_len);
4668
4669 self.state = State::handshake(state::Handshake {
4670 expected_token: Bytes::new(),
4671 remote_cid_set: false,
4672 client_hello: None,
4673 allow_server_migration: self.config.server_handshake_migration,
4674 });
4675 Ok(())
4676 }
4677 Header::Long {
4678 ty: LongType::Handshake,
4679 src_cid: remote_cid,
4680 dst_cid: local_cid,
4681 ..
4682 } => {
4683 debug_assert_eq!(path_id, PathId::ZERO);
4684 if remote_cid != self.remote_handshake_cid {
4685 debug!(
4686 "discarding packet with mismatched remote CID: {} != {}",
4687 self.remote_handshake_cid, remote_cid
4688 );
4689 return Ok(());
4690 }
4691 self.on_path_validated(path_id);
4692
4693 self.process_early_payload(now, path_id, packet, qlog)?;
4694 if self.state.is_closed() {
4695 return Ok(());
4696 }
4697
4698 if self.crypto_state.session.is_handshaking() {
4699 trace!("handshake ongoing");
4700 return Ok(());
4701 }
4702
4703 if self.side.is_client() {
4704 let params = self
4706 .crypto_state
4707 .session
4708 .transport_parameters()?
4709 .ok_or_else(|| {
4710 TransportError::new(
4711 TransportErrorCode::crypto(0x6d),
4712 "transport parameters missing".to_owned(),
4713 )
4714 })?;
4715
4716 if self.has_0rtt() {
4717 if !self.crypto_state.session.early_data_accepted().unwrap() {
4718 debug_assert!(self.side.is_client());
4719 debug!("0-RTT rejected");
4720 self.crypto_state.accepted_0rtt = false;
4721 self.streams.zero_rtt_rejected();
4722
4723 self.spaces[SpaceId::Data].pending = Retransmits::default();
4725
4726 let sent_packets = mem::take(
4728 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets,
4729 );
4730 for (_, packet) in sent_packets.into_iter() {
4731 self.paths
4732 .get_mut(&path_id)
4733 .unwrap()
4734 .remove_in_flight(&packet);
4735 }
4736 } else {
4737 self.crypto_state.accepted_0rtt = true;
4738 params.validate_resumption_from(&self.peer_params)?;
4739 }
4740 }
4741 if let Some(token) = params.stateless_reset_token {
4742 let remote = self.path_data(path_id).network_path.remote;
4743 debug_assert!(!self.state.is_drained()); self.endpoint_events
4745 .push_back(EndpointEventInner::ResetToken(path_id, remote, token));
4746 }
4747 self.handle_peer_params(params, local_cid, remote_cid, now)?;
4748 self.issue_first_cids(now);
4749 } else {
4750 self.spaces[SpaceId::Data].pending.handshake_done = true;
4752 self.discard_space(now, SpaceKind::Handshake);
4753 self.events.push_back(Event::HandshakeConfirmed);
4754 trace!("handshake confirmed");
4755 }
4756
4757 self.events.push_back(Event::Connected);
4758 self.state.move_to_established();
4759 trace!("established");
4760
4761 self.issue_first_path_cids(now);
4764 self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
4765 Ok(())
4766 }
4767 Header::Initial(InitialHeader {
4768 src_cid: remote_cid,
4769 dst_cid: local_cid,
4770 ..
4771 }) => {
4772 debug_assert_eq!(path_id, PathId::ZERO);
4773 if !state.remote_cid_set {
4774 trace!("switching remote CID to {}", remote_cid);
4775 let mut state = state.clone();
4776 self.remote_cids
4777 .get_mut(&path_id)
4778 .expect("PathId::ZERO not yet abandoned")
4779 .update_initial_cid(remote_cid);
4780 self.remote_handshake_cid = remote_cid;
4781 self.original_remote_cid = remote_cid;
4782 state.remote_cid_set = true;
4783 self.state.move_to_handshake(state);
4784 } else if remote_cid != self.remote_handshake_cid {
4785 debug!(
4786 "discarding packet with mismatched remote CID: {} != {}",
4787 self.remote_handshake_cid, remote_cid
4788 );
4789 return Ok(());
4790 }
4791
4792 let starting_space = self.highest_space;
4793 self.process_early_payload(now, path_id, packet, qlog)?;
4794
4795 if self.side.is_server()
4796 && starting_space == SpaceKind::Initial
4797 && self.highest_space != SpaceKind::Initial
4798 {
4799 let params = self
4800 .crypto_state
4801 .session
4802 .transport_parameters()?
4803 .ok_or_else(|| {
4804 TransportError::new(
4805 TransportErrorCode::crypto(0x6d),
4806 "transport parameters missing".to_owned(),
4807 )
4808 })?;
4809 self.handle_peer_params(params, local_cid, remote_cid, now)?;
4810 self.issue_first_cids(now);
4811 self.init_0rtt(now);
4812 }
4813 Ok(())
4814 }
4815 Header::Long {
4816 ty: LongType::ZeroRtt,
4817 ..
4818 } => {
4819 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?;
4820 Ok(())
4821 }
4822 Header::VersionNegotiate { .. } => {
4823 if self.total_authed_packets > 1 {
4824 return Ok(());
4825 }
4826 let supported = packet
4827 .payload
4828 .chunks(4)
4829 .any(|x| match <[u8; 4]>::try_from(x) {
4830 Ok(version) => self.version == u32::from_be_bytes(version),
4831 Err(_) => false,
4832 });
4833 if supported {
4834 return Ok(());
4835 }
4836 debug!("remote doesn't support our version");
4837 Err(ConnectionError::VersionMismatch)
4838 }
4839 Header::Short { .. } => unreachable!(
4840 "short packets received during handshake are discarded in handle_packet"
4841 ),
4842 }
4843 }
4844
4845 fn process_early_payload(
4847 &mut self,
4848 now: Instant,
4849 path_id: PathId,
4850 packet: Packet,
4851 #[allow(unused)] qlog: &mut QlogRecvPacket,
4852 ) -> Result<(), TransportError> {
4853 debug_assert_ne!(packet.header.space(), SpaceKind::Data);
4854 debug_assert_eq!(path_id, PathId::ZERO);
4855 let payload_len = packet.payload.len();
4856 let mut ack_eliciting = false;
4857 for result in frame::Iter::new(packet.payload.freeze())? {
4858 let frame = result?;
4859 qlog.frame(&frame);
4860 let span = match frame {
4861 Frame::Padding => continue,
4862 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)),
4863 };
4864
4865 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4866
4867 let _guard = span.as_ref().map(|x| x.enter());
4868 ack_eliciting |= frame.is_ack_eliciting();
4869
4870 if frame.is_1rtt() && packet.header.space() != SpaceKind::Data {
4872 return Err(TransportError::PROTOCOL_VIOLATION(
4873 "illegal frame type in handshake",
4874 ));
4875 }
4876
4877 match frame {
4878 Frame::Padding | Frame::Ping => {}
4879 Frame::Crypto(frame) => {
4880 self.read_crypto(packet.header.space().into(), &frame, payload_len)?;
4881 }
4882 Frame::Ack(ack) => {
4883 self.on_ack_received(now, packet.header.space().into(), ack)?;
4884 }
4885 Frame::PathAck(ack) => {
4886 span.as_ref()
4887 .map(|span| span.record("path", tracing::field::display(&ack.path_id)));
4888 self.on_path_ack_received(now, packet.header.space().into(), ack)?;
4889 }
4890 Frame::Close(reason) => {
4891 self.state
4892 .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
4893 return Ok(());
4894 }
4895 _ => {
4896 let mut err =
4897 TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake");
4898 err.frame = frame::MaybeFrame::Known(frame.ty());
4899 return Err(err);
4900 }
4901 }
4902 }
4903
4904 if ack_eliciting {
4905 self.spaces[packet.header.space()]
4907 .for_path(path_id)
4908 .pending_acks
4909 .set_immediate_ack_required();
4910 }
4911
4912 self.write_crypto();
4913 Ok(())
4914 }
4915
4916 fn process_payload(
4918 &mut self,
4919 now: Instant,
4920 network_path: FourTuple,
4921 path_id: PathId,
4922 number: u64,
4923 packet: Packet,
4924 #[allow(unused)] qlog: &mut QlogRecvPacket,
4925 ) -> Result<(), TransportError> {
4926 let payload = packet.payload.freeze();
4927 let mut is_probing_packet = true;
4928 let mut close = None;
4929 let payload_len = payload.len();
4930 let mut ack_eliciting = false;
4931 let mut migration_observed_addr = None;
4934 for result in frame::Iter::new(payload)? {
4935 let frame = result?;
4936 qlog.frame(&frame);
4937 let span = match frame {
4938 Frame::Padding => continue,
4939 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty),
4940 };
4941
4942 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4943 match &frame {
4946 Frame::Crypto(f) => {
4947 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO");
4948 }
4949 Frame::Stream(f) => {
4950 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM");
4951 }
4952 Frame::Datagram(f) => {
4953 trace!(len = f.data.len(), "got frame DATAGRAM");
4954 }
4955 f => {
4956 trace!("got frame {f}");
4957 }
4958 }
4959
4960 let _guard = span.enter();
4961 if packet.header.is_0rtt() {
4962 match frame {
4963 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => {
4964 return Err(TransportError::PROTOCOL_VIOLATION(
4965 "illegal frame type in 0-RTT",
4966 ));
4967 }
4968 _ => {
4969 if frame.is_1rtt() {
4970 return Err(TransportError::PROTOCOL_VIOLATION(
4971 "illegal frame type in 0-RTT",
4972 ));
4973 }
4974 }
4975 }
4976 }
4977 ack_eliciting |= frame.is_ack_eliciting();
4978
4979 match frame {
4981 Frame::Padding
4982 | Frame::PathChallenge(_)
4983 | Frame::PathResponse(_)
4984 | Frame::NewConnectionId(_)
4985 | Frame::ObservedAddr(_) => {}
4986 _ => {
4987 is_probing_packet = false;
4988 }
4989 }
4990
4991 match frame {
4992 Frame::Crypto(frame) => {
4993 self.read_crypto(SpaceId::Data, &frame, payload_len)?;
4994 }
4995 Frame::Stream(frame) => {
4996 if self.streams.received(frame, payload_len)?.should_transmit() {
4997 self.spaces[SpaceId::Data].pending.max_data = true;
4998 }
4999 }
5000 Frame::Ack(ack) => {
5001 self.on_ack_received(now, SpaceId::Data, ack)?;
5002 }
5003 Frame::PathAck(ack) => {
5004 if !self.is_multipath_negotiated() {
5005 return Err(TransportError::PROTOCOL_VIOLATION(
5006 "received PATH_ACK frame when multipath was not negotiated",
5007 ));
5008 }
5009 span.record("path", tracing::field::display(&ack.path_id));
5010 self.on_path_ack_received(now, SpaceId::Data, ack)?;
5011 }
5012 Frame::Padding | Frame::Ping => {}
5013 Frame::Close(reason) => {
5014 close = Some(reason);
5015 }
5016 Frame::PathChallenge(challenge) => {
5017 self.spaces[SpaceKind::Data]
5018 .for_path(path_id)
5019 .pending_path_responses
5020 .push(number, challenge.0, network_path);
5021 let path = &mut self
5025 .path_mut(path_id)
5026 .expect("payload is processed only after the path becomes known");
5027 if network_path.remote == path.network_path.remote {
5028 match self.peer_supports_ack_frequency() {
5036 true => self.immediate_ack(path_id),
5037 false => {
5038 self.ping_path(path_id).ok();
5039 }
5040 }
5041 }
5042 }
5043 Frame::PathResponse(response) => {
5044 if self
5046 .n0_nat_traversal
5047 .handle_path_response(network_path, response.0)
5048 {
5049 self.open_nat_traversed_paths(now);
5050 } else {
5051 self.handle_path_response_on_path(now, response, path_id);
5053 }
5054 }
5055 Frame::MaxData(frame::MaxData(bytes)) => {
5056 self.streams.received_max_data(bytes);
5057 }
5058 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => {
5059 self.streams.received_max_stream_data(id, offset)?;
5060 }
5061 Frame::MaxStreams(frame::MaxStreams { dir, count }) => {
5062 self.streams.received_max_streams(dir, count)?;
5063 }
5064 Frame::ResetStream(frame) => {
5065 if self.streams.received_reset(frame)?.should_transmit() {
5066 self.spaces[SpaceId::Data].pending.max_data = true;
5067 }
5068 }
5069 Frame::DataBlocked(DataBlocked(offset)) => {
5070 debug!(offset, "peer claims to be blocked at connection level");
5071 }
5072 Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => {
5073 if id.initiator() == self.side.side() && id.dir() == Dir::Uni {
5074 debug!("got STREAM_DATA_BLOCKED on send-only {}", id);
5075 return Err(TransportError::STREAM_STATE_ERROR(
5076 "STREAM_DATA_BLOCKED on send-only stream",
5077 ));
5078 }
5079 debug!(
5080 stream = %id,
5081 offset, "peer claims to be blocked at stream level"
5082 );
5083 }
5084 Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => {
5085 if limit > MAX_STREAM_COUNT {
5086 return Err(TransportError::FRAME_ENCODING_ERROR(
5087 "unrepresentable stream limit",
5088 ));
5089 }
5090 debug!(
5091 "peer claims to be blocked opening more than {} {} streams",
5092 limit, dir
5093 );
5094 }
5095 Frame::StopSending(frame::StopSending { id, error_code }) => {
5096 if id.initiator() != self.side.side() {
5097 if id.dir() == Dir::Uni {
5098 debug!("got STOP_SENDING on recv-only {}", id);
5099 return Err(TransportError::STREAM_STATE_ERROR(
5100 "STOP_SENDING on recv-only stream",
5101 ));
5102 }
5103 } else if self.streams.is_local_unopened(id) {
5104 return Err(TransportError::STREAM_STATE_ERROR(
5105 "STOP_SENDING on unopened stream",
5106 ));
5107 }
5108 self.streams.received_stop_sending(id, error_code);
5109 }
5110 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => {
5111 if let Some(ref path_id) = path_id {
5112 span.record("path", tracing::field::display(&path_id));
5113 }
5114 let path_id = path_id.unwrap_or_default();
5115 match self.local_cid_state.get_mut(&path_id) {
5116 None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"),
5117 Some(cid_state) => {
5118 let allow_more_cids = cid_state
5119 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?;
5120
5121 let has_path = !self.abandoned_paths.contains(&path_id);
5125 let allow_more_cids = allow_more_cids && has_path;
5126
5127 debug_assert!(!self.state.is_drained()); self.endpoint_events
5129 .push_back(EndpointEventInner::RetireConnectionId(
5130 now,
5131 path_id,
5132 sequence,
5133 allow_more_cids,
5134 ));
5135 }
5136 }
5137 }
5138 Frame::NewConnectionId(frame) => {
5139 let path_id = if let Some(path_id) = frame.path_id {
5140 if !self.is_multipath_negotiated() {
5141 return Err(TransportError::PROTOCOL_VIOLATION(
5142 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated",
5143 ));
5144 }
5145 if path_id > self.local_max_path_id {
5146 return Err(TransportError::PROTOCOL_VIOLATION(
5147 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max",
5148 ));
5149 }
5150 path_id
5151 } else {
5152 PathId::ZERO
5153 };
5154
5155 if let Some(ref path_id) = frame.path_id {
5156 span.record("path", tracing::field::display(&path_id));
5157 }
5158
5159 if self.abandoned_paths.contains(&path_id) {
5160 trace!("ignoring issued CID for abandoned path");
5161 continue;
5162 }
5163 let remote_cids = self
5164 .remote_cids
5165 .entry(path_id)
5166 .or_insert_with(|| CidQueue::new(frame.id));
5167 if remote_cids.active().is_empty() {
5168 return Err(TransportError::PROTOCOL_VIOLATION(
5169 "NEW_CONNECTION_ID when CIDs aren't in use",
5170 ));
5171 }
5172 if frame.retire_prior_to > frame.sequence {
5173 return Err(TransportError::PROTOCOL_VIOLATION(
5174 "NEW_CONNECTION_ID retiring unissued CIDs",
5175 ));
5176 }
5177
5178 use crate::cid_queue::InsertError;
5179 match remote_cids.insert(frame) {
5180 Ok(None) => {
5181 self.open_nat_traversed_paths(now);
5182 }
5183 Ok(Some((retired, reset_token))) => {
5184 let pending_retired =
5185 &mut self.spaces[SpaceId::Data].pending.retire_cids;
5186 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10;
5189 if (pending_retired.len() as u64)
5192 .saturating_add(retired.end.saturating_sub(retired.start))
5193 > MAX_PENDING_RETIRED_CIDS
5194 {
5195 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(
5196 "queued too many retired CIDs",
5197 ));
5198 }
5199 pending_retired.extend(retired.map(|seq| (path_id, seq)));
5200 self.set_reset_token(path_id, network_path.remote, reset_token);
5201 self.open_nat_traversed_paths(now);
5202 }
5203 Err(InsertError::ExceedsLimit) => {
5204 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(""));
5205 }
5206 Err(InsertError::Retired) => {
5207 trace!("discarding already-retired");
5208 self.spaces[SpaceId::Data]
5212 .pending
5213 .retire_cids
5214 .push((path_id, frame.sequence));
5215 continue;
5216 }
5217 };
5218
5219 if self.side.is_server()
5220 && path_id == PathId::ZERO
5221 && self
5222 .remote_cids
5223 .get(&PathId::ZERO)
5224 .map(|cids| cids.active_seq() == 0)
5225 .unwrap_or_default()
5226 {
5227 self.update_remote_cid(PathId::ZERO);
5230 }
5231 }
5232 Frame::NewToken(NewToken { token }) => {
5233 let ConnectionSide::Client {
5234 token_store,
5235 server_name,
5236 ..
5237 } = &self.side
5238 else {
5239 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN"));
5240 };
5241 if token.is_empty() {
5242 return Err(TransportError::FRAME_ENCODING_ERROR("empty token"));
5243 }
5244 trace!("got new token");
5245 token_store.insert(server_name, token);
5246 }
5247 Frame::Datagram(datagram) => {
5248 if self
5249 .datagrams
5250 .received(datagram, &self.config.datagram_receive_buffer_size)?
5251 {
5252 self.events.push_back(Event::DatagramReceived);
5253 }
5254 }
5255 Frame::AckFrequency(ack_frequency) => {
5256 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? {
5259 continue;
5262 }
5263
5264 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() {
5266 space.pending_acks.set_ack_frequency_params(&ack_frequency);
5267
5268 if !self.abandoned_paths.contains(path_id)
5272 && let Some(timeout) = space
5273 .pending_acks
5274 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay)
5275 {
5276 self.timers.set(
5277 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
5278 timeout,
5279 self.qlog.with_time(now),
5280 );
5281 }
5282 }
5283 }
5284 Frame::ImmediateAck => {
5285 for pns in self.spaces[SpaceId::Data].iter_paths_mut() {
5287 pns.pending_acks.set_immediate_ack_required();
5288 }
5289 }
5290 Frame::HandshakeDone => {
5291 if self.side.is_server() {
5292 return Err(TransportError::PROTOCOL_VIOLATION(
5293 "client sent HANDSHAKE_DONE",
5294 ));
5295 }
5296 if self.crypto_state.has_keys(EncryptionLevel::Handshake) {
5297 self.discard_space(now, SpaceKind::Handshake);
5298 self.events.push_back(Event::HandshakeConfirmed);
5299 trace!("handshake confirmed");
5300 }
5301 }
5302 Frame::ObservedAddr(observed) => {
5303 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port);
5305 if !self
5306 .peer_params
5307 .address_discovery_role
5308 .should_report(&self.config.address_discovery_role)
5309 {
5310 return Err(TransportError::PROTOCOL_VIOLATION(
5311 "received OBSERVED_ADDRESS frame when not negotiated",
5312 ));
5313 }
5314 if packet.header.space() != SpaceKind::Data {
5316 return Err(TransportError::PROTOCOL_VIOLATION(
5317 "OBSERVED_ADDRESS frame outside data space",
5318 ));
5319 }
5320
5321 let space_open_status =
5322 self.spaces[SpaceKind::Data].for_path(path_id).open_status;
5323 let path = self.path_data_mut(path_id);
5324 if path.network_path.remote == network_path.remote {
5325 if let Some(updated) = path.update_observed_addr_report(observed)
5326 && space_open_status == OpenStatus::Informed
5327 {
5328 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5329 id: path_id,
5330 addr: updated,
5331 }));
5332 }
5334 } else {
5335 migration_observed_addr = Some(observed)
5337 }
5338 }
5339 Frame::PathAbandon(frame::PathAbandon {
5340 path_id,
5341 error_code,
5342 }) => {
5343 span.record("path", tracing::field::display(&path_id));
5344 match self.close_path_inner(
5345 now,
5346 path_id,
5347 PathAbandonReason::RemoteAbandoned {
5348 error_code: error_code.into(),
5349 },
5350 ) {
5351 Ok(()) => {
5352 trace!("peer abandoned path");
5353 }
5354 Err(ClosePathError::ClosedPath) => {
5355 trace!("peer abandoned already closed path");
5356 }
5357 Err(ClosePathError::MultipathNotNegotiated) => {
5358 return Err(TransportError::PROTOCOL_VIOLATION(
5359 "received PATH_ABANDON frame when multipath was not negotiated",
5360 ));
5361 }
5362 Err(ClosePathError::LastOpenPath) => {
5363 error!(
5366 "peer abandoned last path but close_path_inner returned LastOpenPath"
5367 );
5368 }
5369 };
5370
5371 if let Some(path) = self.paths.get_mut(&path_id)
5373 && !mem::replace(&mut path.data.draining, true)
5374 {
5375 let ack_delay = self.ack_frequency.max_ack_delay_for_pto();
5376 let pto = path.data.rtt.pto_base() + ack_delay;
5377 self.timers.set(
5378 Timer::PerPath(path_id, PathTimer::PathDrained),
5379 now + 3 * pto,
5380 self.qlog.with_time(now),
5381 );
5382
5383 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8));
5384 }
5385 }
5386 Frame::PathStatusAvailable(info) => {
5387 span.record("path", tracing::field::display(&info.path_id));
5388 if self.is_multipath_negotiated() {
5389 self.on_path_status(
5390 info.path_id,
5391 PathStatus::Available,
5392 info.status_seq_no,
5393 );
5394 } else {
5395 return Err(TransportError::PROTOCOL_VIOLATION(
5396 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated",
5397 ));
5398 }
5399 }
5400 Frame::PathStatusBackup(info) => {
5401 span.record("path", tracing::field::display(&info.path_id));
5402 if self.is_multipath_negotiated() {
5403 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no);
5404 } else {
5405 return Err(TransportError::PROTOCOL_VIOLATION(
5406 "received PATH_STATUS_BACKUP frame when multipath was not negotiated",
5407 ));
5408 }
5409 }
5410 Frame::MaxPathId(frame::MaxPathId(path_id)) => {
5411 span.record("path", tracing::field::display(&path_id));
5412 if !self.is_multipath_negotiated() {
5413 return Err(TransportError::PROTOCOL_VIOLATION(
5414 "received MAX_PATH_ID frame when multipath was not negotiated",
5415 ));
5416 }
5417 if path_id > self.remote_max_path_id {
5419 self.remote_max_path_id = path_id;
5420 self.issue_first_path_cids(now);
5421 self.open_nat_traversed_paths(now);
5422 }
5423 }
5424 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => {
5425 if self.is_multipath_negotiated() {
5430 if max_path_id > self.local_max_path_id {
5431 return Err(TransportError::PROTOCOL_VIOLATION(
5432 "PATHS_BLOCKED maximum path identifier was larger than local maximum",
5433 ));
5434 }
5435 } else {
5436 return Err(TransportError::PROTOCOL_VIOLATION(
5437 "received PATHS_BLOCKED frame when not multipath was not negotiated",
5438 ));
5439 }
5440 }
5441 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => {
5442 if self.is_multipath_negotiated() {
5451 if path_id > self.local_max_path_id {
5452 return Err(TransportError::PROTOCOL_VIOLATION(
5453 "PATH_CIDS_BLOCKED path identifier was larger than local maximum",
5454 ));
5455 }
5456 if self
5457 .local_cid_state
5458 .get(&path_id)
5459 .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1)
5463 {
5464 return Err(TransportError::PROTOCOL_VIOLATION(
5465 "PATH_CIDS_BLOCKED next sequence number larger than in local state",
5466 ));
5467 }
5468 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED");
5469 } else {
5470 return Err(TransportError::PROTOCOL_VIOLATION(
5471 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated",
5472 ));
5473 }
5474 }
5475 Frame::AddAddress(addr) => {
5476 let client_state = match self.n0_nat_traversal.client_side_mut() {
5477 Ok(state) => state,
5478 Err(err) => {
5479 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5480 "Nat traversal(ADD_ADDRESS): {err}"
5481 )));
5482 }
5483 };
5484
5485 if !client_state.check_remote_address(&addr) {
5486 warn!(?addr, "server sent illegal ADD_ADDRESS frame");
5488 }
5489
5490 match client_state.add_remote_address(addr) {
5491 Ok(maybe_added) => {
5492 if let Some(added) = maybe_added {
5493 self.events.push_back(Event::NatTraversal(
5494 n0_nat_traversal::Event::AddressAdded(added),
5495 ));
5496 }
5497 }
5498 Err(e) => {
5499 warn!(%e, "failed to add remote address")
5500 }
5501 }
5502 }
5503 Frame::RemoveAddress(addr) => {
5504 let client_state = match self.n0_nat_traversal.client_side_mut() {
5505 Ok(state) => state,
5506 Err(err) => {
5507 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5508 "Nat traversal(REMOVE_ADDRESS): {err}"
5509 )));
5510 }
5511 };
5512 if let Some(removed_addr) = client_state.remove_remote_address(addr) {
5513 self.events.push_back(Event::NatTraversal(
5514 n0_nat_traversal::Event::AddressRemoved(removed_addr),
5515 ));
5516 }
5517 }
5518 Frame::ReachOut(reach_out) => {
5519 let ipv6 = self.is_ipv6();
5520 let server_state = match self.n0_nat_traversal.server_side_mut() {
5521 Ok(state) => state,
5522 Err(err) => {
5523 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5524 "Nat traversal(REACH_OUT): {err}"
5525 )));
5526 }
5527 };
5528
5529 let round_before = server_state.current_round();
5530
5531 if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) {
5532 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5533 "Nat traversal(REACH_OUT): {err}"
5534 )));
5535 }
5536
5537 if server_state.current_round() > round_before {
5538 if let Some(delay) =
5540 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
5541 {
5542 self.timers.set(
5543 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
5544 now + delay,
5545 self.qlog.with_time(now),
5546 );
5547 }
5548 }
5549 }
5550 }
5551 }
5552
5553 let space = self.spaces[SpaceId::Data].for_path(path_id);
5554 if space
5555 .pending_acks
5556 .packet_received(now, number, ack_eliciting, &space.dedup)
5557 {
5558 if self.abandoned_paths.contains(&path_id) {
5559 space.pending_acks.set_immediate_ack_required();
5562 } else {
5563 self.timers.set(
5564 Timer::PerPath(path_id, PathTimer::MaxAckDelay),
5565 now + self.ack_frequency.max_ack_delay,
5566 self.qlog.with_time(now),
5567 );
5568 }
5569 }
5570
5571 let pending = &mut self.spaces[SpaceId::Data].pending;
5576 self.streams.queue_max_stream_id(pending);
5577
5578 if let Some(reason) = close {
5579 self.state
5580 .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
5581 self.connection_close_pending = true;
5582 }
5583
5584 let migrate_on_any_packet =
5587 self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated();
5588
5589 let is_largest_received_pn = Some(number)
5591 == self.spaces[SpaceId::Data]
5592 .for_path(path_id)
5593 .largest_received_packet_number;
5594
5595 if (migrate_on_any_packet || !is_probing_packet)
5600 && is_largest_received_pn
5601 && self.local_ip_may_migrate()
5602 && let Some(new_local_ip) = network_path.local_ip
5603 {
5604 let path_data = self.path_data_mut(path_id);
5605 if path_data
5606 .network_path
5607 .local_ip
5608 .is_some_and(|ip| ip != new_local_ip)
5609 {
5610 debug!(
5611 %path_id,
5612 new_4tuple = %network_path,
5613 prev_4tuple = %path_data.network_path,
5614 "local address passive migration"
5615 );
5616 }
5617 path_data.network_path.local_ip = Some(new_local_ip)
5618 }
5619
5620 if self.peer_may_migrate()
5622 && (migrate_on_any_packet || !is_probing_packet)
5623 && is_largest_received_pn
5624 && network_path.remote != self.path_data(path_id).network_path.remote
5625 {
5626 self.migrate(path_id, now, network_path, migration_observed_addr);
5627 self.update_remote_cid(path_id);
5629 self.spin = false;
5630 }
5631
5632 Ok(())
5633 }
5634
5635 fn handle_path_response_on_path(
5639 &mut self,
5640 now: Instant,
5641 response: frame::PathResponse,
5642 path_id: PathId,
5643 ) {
5644 let is_multipath_negotiated = self.is_multipath_negotiated();
5645 let path = self
5646 .paths
5647 .get_mut(&path_id)
5648 .expect("payload is processed only after the path becomes known");
5649 match path.data.on_path_response_received(now, response.0) {
5650 paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => {
5651 let qlog = self.qlog.with_time(now);
5652 self.timers.stop(
5653 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5654 qlog.clone(),
5655 );
5656 let next_challenge = path
5657 .data
5658 .earliest_on_path_expiring_challenge()
5659 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto());
5660 self.timers.set_or_stop(
5661 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
5662 next_challenge,
5663 qlog,
5664 );
5665 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
5666 if !matches!(pns.open_status, OpenStatus::Informed) {
5667 if is_multipath_negotiated {
5668 self.events
5669 .push_back(Event::Path(PathEvent::Established { id: path_id }));
5670 }
5671 pns.open_status = OpenStatus::Informed;
5672 if let Some(observed) = path.data.last_observed_addr_report.as_ref() {
5673 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5674 id: path_id,
5675 addr: observed.socket_addr(),
5676 }));
5677 }
5678 }
5679 if let Some((_, ref mut prev)) = path.prev {
5680 prev.reset_on_path_challenges();
5685 }
5686 }
5687 paths::OnPathResponseReceived::OnPath => {
5688 trace!(
5689 %response,
5690 "ignoring PATH_RESPONSE received after path is abandoned"
5691 );
5692 }
5693 paths::OnPathResponseReceived::Unknown => {
5694 debug!(%response, "ignoring invalid PATH_RESPONSE");
5695 }
5696 paths::OnPathResponseReceived::Ignored {
5697 sent_on,
5698 current_path,
5699 } => {
5700 debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE");
5701 }
5702 }
5703 }
5704
5705 fn open_nat_traversed_paths(&mut self, now: Instant) {
5707 while let Some(network_path) = self
5708 .n0_nat_traversal
5709 .client_side_mut()
5710 .ok()
5711 .and_then(|s| s.pop_pending_path_open())
5712 {
5713 match self.open_path_ensure(network_path, PathStatus::Backup, now) {
5714 Ok((path_id, already_existed)) => {
5715 debug!(
5716 %path_id,
5717 ?network_path,
5718 new_path = !already_existed,
5719 "Opened NAT traversal path",
5720 );
5721 }
5722 Err(err) => match err {
5723 PathError::MultipathNotNegotiated
5724 | PathError::ServerSideNotAllowed
5725 | PathError::ValidationFailed
5726 | PathError::InvalidRemoteAddress(_) => {
5727 error!(
5728 ?err,
5729 ?network_path,
5730 "Failed to open path for successful NAT traversal"
5731 );
5732 }
5733 PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => {
5734 self.n0_nat_traversal
5736 .client_side_mut()
5737 .map(|s| s.push_pending_path_open(network_path))
5738 .ok();
5739 debug!(
5740 ?err,
5741 ?network_path,
5742 "Blocked opening NAT traversal path, enqueued"
5743 );
5744 return;
5745 }
5746 },
5747 }
5748 }
5749 }
5750
5751 fn migrate(
5756 &mut self,
5757 path_id: PathId,
5758 now: Instant,
5759 network_path: FourTuple,
5760 observed_addr: Option<ObservedAddr>,
5761 ) {
5762 trace!(
5763 new_4tuple = %network_path,
5764 prev_4tuple = %self.path_data(path_id).network_path,
5765 %path_id,
5766 "migration initiated",
5767 );
5768 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
5769 let prev_pto = self.pto(SpaceKind::Data, path_id);
5776 let path = self.paths.get_mut(&path_id).expect("known path");
5777 let mut new_path_data = if network_path.remote.is_ipv4()
5778 && network_path.remote.ip() == path.data.network_path.remote.ip()
5779 {
5780 PathData::from_previous(network_path, &path.data, self.path_generation_counter, now)
5781 } else {
5782 let peer_max_udp_payload_size =
5783 u16::try_from(self.peer_params.max_udp_payload_size.into_inner())
5784 .unwrap_or(u16::MAX);
5785 PathData::new(
5786 network_path,
5787 self.allow_mtud,
5788 Some(peer_max_udp_payload_size),
5789 self.path_generation_counter,
5790 now,
5791 &self.config,
5792 )
5793 };
5794 new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone();
5795 if let Some(report) = observed_addr
5796 && let Some(updated) = new_path_data.update_observed_addr_report(report)
5797 {
5798 tracing::info!("adding observed addr event from migration");
5799 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5800 id: path_id,
5801 addr: updated,
5802 }));
5803 }
5804 new_path_data.pending_challenge = true;
5805 new_path_data.pending.observed_address = self
5806 .config
5807 .address_discovery_role
5808 .should_report(&self.peer_params.address_discovery_role);
5809
5810 let mut prev_path_data = mem::replace(&mut path.data, new_path_data);
5811
5812 if !prev_path_data.validated
5821 && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active)
5822 {
5823 prev_path_data.pending_challenge = true;
5824 path.prev = Some((cid, prev_path_data));
5827 }
5828
5829 self.qlog.emit_tuple_assigned(path_id, network_path, now);
5831
5832 self.timers.set(
5833 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5834 now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto),
5835 self.qlog.with_time(now),
5836 );
5837 }
5838
5839 pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) {
5856 debug!("network changed");
5857 if self.state.is_drained() {
5858 return;
5859 }
5860 if self.highest_space < SpaceKind::Data {
5861 for path in self.paths.values_mut() {
5862 path.data.network_path.local_ip = None;
5864 }
5865
5866 self.update_remote_cid(PathId::ZERO);
5867 self.ping();
5868
5869 return;
5870 }
5871
5872 let mut non_recoverable_paths = Vec::default();
5875 let mut recoverable_paths = Vec::default();
5876 let mut open_paths = 0;
5877
5878 let is_multipath_negotiated = self.is_multipath_negotiated();
5879 let is_client = self.side().is_client();
5880 let immediate_ack_allowed = self.peer_supports_ack_frequency();
5881
5882 for path_id in self.spaces[SpaceKind::Data].number_spaces.keys() {
5883 if self.abandoned_paths.contains(path_id) {
5884 continue;
5885 }
5886 open_paths += 1;
5887
5888 let path = self.paths.get_mut(path_id).expect("PathData missing");
5889
5890 let network_path = path.data.network_path;
5893
5894 path.data.network_path.local_ip = None;
5897 let remote = network_path.remote;
5898
5899 let attempt_to_recover = if is_multipath_negotiated {
5903 hint.map(|h| h.is_path_recoverable(*path_id, network_path))
5907 .unwrap_or(!is_client)
5908 } else {
5909 true
5911 };
5912
5913 if attempt_to_recover {
5914 recoverable_paths.push((*path_id, remote));
5915 } else {
5916 non_recoverable_paths.push((*path_id, remote));
5917 }
5918 }
5919
5920 let open_first = open_paths == non_recoverable_paths.len();
5929
5930 for (path_id, remote) in non_recoverable_paths.into_iter() {
5931 let network_path = FourTuple {
5932 remote,
5933 local_ip: None, };
5935 let status = self.spaces[SpaceKind::Data]
5936 .number_spaces
5937 .get(&path_id)
5938 .map(|pns| pns.local_status())
5939 .expect("spaces iterated above");
5940 if open_first && let Err(e) = self.open_path(network_path, status, now) {
5941 if self.side().is_client() {
5942 debug!(%e, "Failed to open new path for network change");
5943 }
5944 recoverable_paths.push((path_id, remote));
5946 continue;
5947 }
5948
5949 if let Err(e) =
5950 self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange)
5951 {
5952 debug!(%e,"Failed to close unrecoverable path after network change");
5953 recoverable_paths.push((path_id, remote));
5954 continue;
5955 }
5956
5957 if !open_first && let Err(e) = self.open_path(network_path, status, now) {
5958 debug!(%e,"Failed to open new path for network change");
5962 }
5963 }
5964
5965 for (path_id, remote) in recoverable_paths.into_iter() {
5968 if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) {
5970 path_space.pending_ping = true;
5971
5972 if immediate_ack_allowed {
5973 path_space.pending_immediate_ack = true;
5974 }
5975 }
5976
5977 if let Some(path) = self.paths.get_mut(&path_id) {
5982 path.data.pto_count = 0;
5983 }
5984 self.set_loss_detection_timer(now, path_id);
5985
5986 let Some((reset_token, retired)) =
5987 self.remote_cids.get_mut(&path_id).and_then(CidQueue::next)
5988 else {
5989 continue;
5990 };
5991
5992 self.spaces[SpaceId::Data]
5994 .pending
5995 .retire_cids
5996 .extend(retired.map(|seq| (path_id, seq)));
5997
5998 debug_assert!(!self.state.is_drained()); self.endpoint_events
6000 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
6001 }
6002 }
6003
6004 fn update_remote_cid(&mut self, path_id: PathId) {
6006 let Some((reset_token, retired)) = self
6007 .remote_cids
6008 .get_mut(&path_id)
6009 .and_then(|cids| cids.next())
6010 else {
6011 return;
6012 };
6013
6014 self.spaces[SpaceId::Data]
6016 .pending
6017 .retire_cids
6018 .extend(retired.map(|seq| (path_id, seq)));
6019 let remote = self.path_data(path_id).network_path.remote;
6020 self.set_reset_token(path_id, remote, reset_token);
6021 }
6022
6023 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) {
6032 debug_assert!(!self.state.is_drained()); self.endpoint_events
6034 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
6035
6036 if path_id == PathId::ZERO {
6042 self.peer_params.stateless_reset_token = Some(reset_token);
6043 }
6044 }
6045
6046 fn issue_first_cids(&mut self, now: Instant) {
6048 if self
6049 .local_cid_state
6050 .get(&PathId::ZERO)
6051 .expect("PathId::ZERO exists when the connection is created")
6052 .cid_len()
6053 == 0
6054 {
6055 return;
6056 }
6057
6058 let mut n = self.peer_params.issue_cids_limit() - 1;
6060 if let ConnectionSide::Server { server_config } = &self.side
6061 && server_config.has_preferred_address()
6062 {
6063 n -= 1;
6065 }
6066 debug_assert!(!self.state.is_drained()); self.endpoint_events
6068 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6069 }
6070
6071 fn issue_first_path_cids(&mut self, now: Instant) {
6075 if let Some(max_path_id) = self.max_path_id() {
6076 let mut path_id = self.max_path_id_with_cids.next();
6077 while path_id <= max_path_id {
6078 self.endpoint_events
6079 .push_back(EndpointEventInner::NeedIdentifiers(
6080 path_id,
6081 now,
6082 self.peer_params.issue_cids_limit(),
6083 ));
6084 path_id = path_id.next();
6085 }
6086 self.max_path_id_with_cids = max_path_id;
6087 }
6088 }
6089
6090 fn populate_packet<'a, 'b>(
6098 &mut self,
6099 now: Instant,
6100 space_id: SpaceId,
6101 path_id: PathId,
6102 scheduling_info: &PathSchedulingInfo,
6103 builder: &mut PacketBuilder<'a, 'b>,
6104 ) {
6105 let is_multipath_negotiated = self.is_multipath_negotiated();
6106 let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level());
6107 let is_0rtt = space_id == SpaceId::Data && !space_has_keys;
6108 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
6109 let space = &mut self.spaces[space_id];
6110 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6111 space
6112 .for_path(path_id)
6113 .pending_acks
6114 .maybe_ack_non_eliciting();
6115
6116 if !is_0rtt
6118 && !scheduling_info.is_abandoned
6119 && scheduling_info.may_send_data
6120 && mem::replace(&mut space.pending.handshake_done, false)
6121 {
6122 builder.write_frame(frame::HandshakeDone, stats);
6123 }
6124
6125 if !scheduling_info.is_abandoned
6127 && mem::replace(&mut space.for_path(path_id).pending_ping, false)
6128 {
6129 builder.write_frame(frame::Ping, stats);
6130 }
6131
6132 if !scheduling_info.is_abandoned
6134 && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false)
6135 {
6136 debug_assert_eq!(
6137 space_id,
6138 SpaceId::Data,
6139 "immediate acks must be sent in the data space"
6140 );
6141 builder.write_frame(frame::ImmediateAck, stats);
6142 }
6143
6144 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6146 for path_id in space
6147 .number_spaces
6148 .iter_mut()
6149 .filter(|(_, pns)| pns.pending_acks.can_send())
6150 .map(|(&path_id, _)| path_id)
6151 .collect::<Vec<_>>()
6152 {
6153 Self::populate_acks(
6154 now,
6155 self.receiving_ecn,
6156 path_id,
6157 space_id,
6158 space,
6159 is_multipath_negotiated,
6160 builder,
6161 stats,
6162 space_has_keys,
6163 );
6164 }
6165 }
6166
6167 if !scheduling_info.is_abandoned
6169 && scheduling_info.may_send_data
6170 && mem::replace(&mut space.pending.ack_frequency, false)
6171 {
6172 let sequence_number = self.ack_frequency.next_sequence_number();
6173
6174 let config = self.config.ack_frequency_config.as_ref().unwrap();
6176
6177 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay(
6179 path.rtt.get(),
6180 config,
6181 &self.peer_params,
6182 );
6183
6184 let frame = frame::AckFrequency {
6185 sequence: sequence_number,
6186 ack_eliciting_threshold: config.ack_eliciting_threshold,
6187 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX),
6188 reordering_threshold: config.reordering_threshold,
6189 };
6190 builder.write_frame(frame, stats);
6191
6192 self.ack_frequency
6193 .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay);
6194 path.congestion.on_ack_frequency_update(
6195 config.ack_eliciting_threshold.into_inner(),
6196 max_ack_delay,
6197 );
6198 }
6199
6200 if !scheduling_info.is_abandoned
6202 && space_id == SpaceId::Data
6203 && path.pending_challenge
6204 && !self.state.is_closed()
6206 && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND
6207 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6210 {
6211 path.pending_challenge = false;
6212
6213 let token = self.rng.random();
6214 path.record_path_challenge_sent(now, token, path.network_path);
6215 let challenge = frame::PathChallenge(token);
6217 builder.write_frame(challenge, stats);
6218 builder.require_padding();
6219
6220 self.timers.set(
6225 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
6226 now + path.on_path_challenge_pto(),
6227 self.qlog.with_time(now),
6228 );
6229
6230 if is_multipath_negotiated && !path.validated && path.pending_challenge {
6231 space.pending.path_status.insert(path_id);
6233 }
6234
6235 path.pending.observed_address = self
6238 .config
6239 .address_discovery_role
6240 .should_report(&self.peer_params.address_discovery_role);
6241 }
6242
6243 if !scheduling_info.is_abandoned
6245 && space_id == SpaceId::Data
6246 && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND
6247 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6250 && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path)
6251 {
6252 let response = frame::PathResponse(token);
6253 builder.write_frame(response, stats);
6254 builder.require_padding();
6255
6256 path.pending.observed_address = self
6260 .config
6261 .address_discovery_role
6262 .should_report(&self.peer_params.address_discovery_role);
6263 }
6264
6265 while space_id == SpaceId::Data
6267 && !scheduling_info.is_abandoned
6268 && scheduling_info.may_send_data
6269 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining()
6270 {
6271 if let Some(added_address) = space.pending.add_address.pop_last() {
6272 builder.write_frame(added_address, stats);
6273 } else {
6274 break;
6275 }
6276 }
6277
6278 while space_id == SpaceId::Data
6280 && !scheduling_info.is_abandoned
6281 && scheduling_info.may_send_data
6282 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining()
6283 {
6284 if let Some(removed_address) = space.pending.remove_address.pop_last() {
6285 builder.write_frame(removed_address, stats);
6286 } else {
6287 break;
6288 }
6289 }
6290
6291 while !scheduling_info.is_abandoned
6293 && scheduling_info.may_send_data
6294 && let Some(reach_out) = space
6295 .pending
6296 .reach_out
6297 .pop_if(|frame| builder.frame_space_remaining() >= frame.size())
6298 {
6299 builder.write_frame(reach_out, stats);
6300 }
6301
6302 if space_id == SpaceId::Data
6304 && scheduling_info.is_abandoned
6305 && scheduling_info.may_self_abandon
6306 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6307 && let Some(error_code) = space.pending.path_abandon.remove(&path_id)
6308 {
6309 let frame = frame::PathAbandon {
6310 path_id,
6311 error_code,
6312 };
6313 builder.write_frame(frame, stats);
6314
6315 self.remote_cids.remove(&path_id);
6318 }
6319 while space_id == SpaceId::Data
6320 && scheduling_info.may_send_data
6321 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6322 && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first()
6323 {
6324 let frame = frame::PathAbandon {
6325 path_id: abandoned_path_id,
6326 error_code,
6327 };
6328 builder.write_frame(frame, stats);
6329
6330 self.remote_cids.remove(&abandoned_path_id);
6333 }
6334
6335 if !scheduling_info.is_abandoned
6337 && space_id == SpaceId::Data
6338 && path.pending.observed_address
6339 {
6340 let frame = ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no);
6341 if builder.frame_space_remaining() > frame.size() {
6342 builder.write_frame(frame, stats);
6343
6344 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8);
6345 path.pending.observed_address = false;
6346 }
6347 }
6348
6349 while !is_0rtt
6351 && !scheduling_info.is_abandoned
6352 && scheduling_info.may_send_data
6353 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND
6354 {
6355 let Some(mut frame) = space.pending.crypto.pop_front() else {
6356 break;
6357 };
6358
6359 let max_crypto_data_size = builder.frame_space_remaining()
6364 - 1 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) })
6366 - 2; let len = frame
6369 .data
6370 .len()
6371 .min(2usize.pow(14) - 1)
6372 .min(max_crypto_data_size);
6373
6374 let data = frame.data.split_to(len);
6375 let offset = frame.offset;
6376 let truncated = frame::Crypto { offset, data };
6377 builder.write_frame(truncated, stats);
6378
6379 if !frame.data.is_empty() {
6380 frame.offset += len as u64;
6381 space.pending.crypto.push_front(frame);
6382 }
6383 }
6384
6385 while space_id == SpaceId::Data
6387 && !scheduling_info.is_abandoned
6388 && scheduling_info.may_send_data
6389 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining()
6390 {
6391 let Some(path_id) = space.pending.path_status.pop_first() else {
6392 break;
6393 };
6394 let Some(pns) = space.number_spaces.get(&path_id) else {
6395 trace!(%path_id, "discarding queued path status for unknown path");
6396 continue;
6397 };
6398
6399 let seq = pns.status.seq();
6400 match pns.local_status() {
6401 PathStatus::Available => {
6402 let frame = frame::PathStatusAvailable {
6403 path_id,
6404 status_seq_no: seq,
6405 };
6406 builder.write_frame(frame, stats);
6407 }
6408 PathStatus::Backup => {
6409 let frame = frame::PathStatusBackup {
6410 path_id,
6411 status_seq_no: seq,
6412 };
6413 builder.write_frame(frame, stats);
6414 }
6415 }
6416 }
6417
6418 if space_id == SpaceId::Data
6420 && !scheduling_info.is_abandoned
6421 && scheduling_info.may_send_data
6422 && space.pending.max_path_id
6423 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining()
6424 {
6425 let frame = frame::MaxPathId(self.local_max_path_id);
6426 builder.write_frame(frame, stats);
6427 space.pending.max_path_id = false;
6428 }
6429
6430 if space_id == SpaceId::Data
6432 && !scheduling_info.is_abandoned
6433 && scheduling_info.may_send_data
6434 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6435 && let Some(remote_max_path_id) = space.pending.paths_blocked.take()
6436 {
6437 let frame = frame::PathsBlocked(remote_max_path_id);
6438 builder.write_frame(frame, stats);
6439 }
6440
6441 while space_id == SpaceId::Data
6443 && !scheduling_info.is_abandoned
6444 && scheduling_info.may_send_data
6445 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6446 {
6447 let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else {
6448 break;
6449 };
6450 let frame = frame::PathCidsBlocked { path_id, next_seq };
6451 builder.write_frame(frame, stats);
6452 }
6453
6454 if space_id == SpaceId::Data
6456 && !scheduling_info.is_abandoned
6457 && scheduling_info.may_send_data
6458 {
6459 self.streams
6460 .write_control_frames(builder, &mut space.pending, stats);
6461 }
6462
6463 let cid_len = self
6465 .local_cid_state
6466 .values()
6467 .map(|cid_state| cid_state.cid_len())
6468 .max()
6469 .expect("some local CID state must exist");
6470 let new_cid_size_bound =
6471 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len);
6472 while !scheduling_info.is_abandoned
6473 && scheduling_info.may_send_data
6474 && builder.frame_space_remaining() > new_cid_size_bound
6475 {
6476 let Some(issued) = space.pending.new_cids.pop() else {
6477 break;
6478 };
6479 let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else {
6481 debug!(
6482 path = %issued.path_id, seq = issued.sequence,
6483 "dropping queued NEW_CONNECTION_ID for discarded path",
6484 );
6485 continue;
6486 };
6487 let retire_prior_to = cid_state.retire_prior_to();
6488
6489 let cid_path_id = match is_multipath_negotiated {
6490 true => Some(issued.path_id),
6491 false => {
6492 debug_assert_eq!(issued.path_id, PathId::ZERO);
6493 None
6494 }
6495 };
6496 let frame = frame::NewConnectionId {
6497 path_id: cid_path_id,
6498 sequence: issued.sequence,
6499 retire_prior_to,
6500 id: issued.id,
6501 reset_token: issued.reset_token,
6502 };
6503 builder.write_frame(frame, stats);
6504 }
6505
6506 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated);
6508 while !scheduling_info.is_abandoned
6509 && scheduling_info.may_send_data
6510 && builder.frame_space_remaining() > retire_cid_bound
6511 {
6512 let (path_id, sequence) = match space.pending.retire_cids.pop() {
6513 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq),
6514 Some((path_id, seq)) => (Some(path_id), seq),
6515 None => break,
6516 };
6517 let frame = frame::RetireConnectionId { path_id, sequence };
6518 builder.write_frame(frame, stats);
6519 }
6520
6521 let mut sent_datagrams = false;
6523 while !scheduling_info.is_abandoned
6524 && scheduling_info.may_send_data
6525 && builder.frame_space_remaining() > Datagram::SIZE_BOUND
6526 && space_id == SpaceId::Data
6527 {
6528 match self.datagrams.write(builder, stats) {
6529 true => {
6530 sent_datagrams = true;
6531 }
6532 false => break,
6533 }
6534 }
6535 if self.datagrams.send_blocked && sent_datagrams {
6536 self.events.push_back(Event::DatagramsUnblocked);
6537 self.datagrams.send_blocked = false;
6538 }
6539
6540 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6541
6542 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6544 while let Some(network_path) = space.pending.new_tokens.pop() {
6545 debug_assert_eq!(space_id, SpaceId::Data);
6546 let ConnectionSide::Server { server_config } = &self.side else {
6547 panic!("NEW_TOKEN frames should not be enqueued by clients");
6548 };
6549
6550 if !network_path.is_probably_same_path(&path.network_path) {
6551 continue;
6556 }
6557
6558 let token = Token::new(
6559 TokenPayload::Validation {
6560 ip: network_path.remote.ip(),
6561 issued: server_config.time_source.now(),
6562 },
6563 &mut self.rng,
6564 );
6565 let new_token = NewToken {
6566 token: token.encode(&*server_config.token_key).into(),
6567 };
6568
6569 if builder.frame_space_remaining() < new_token.size() {
6570 space.pending.new_tokens.push(network_path);
6571 break;
6572 }
6573
6574 builder.write_frame(new_token, stats);
6575 builder.retransmits_mut().new_tokens.push(network_path);
6576 }
6577 }
6578
6579 if !scheduling_info.is_abandoned
6581 && scheduling_info.may_send_data
6582 && space_id == SpaceId::Data
6583 {
6584 self.streams
6585 .write_stream_frames(builder, self.config.send_fairness, stats);
6586 }
6587 }
6588
6589 fn populate_acks<'a, 'b>(
6591 now: Instant,
6592 receiving_ecn: bool,
6593 path_id: PathId,
6594 space_id: SpaceId,
6595 space: &mut PacketSpace,
6596 is_multipath_negotiated: bool,
6597 builder: &mut PacketBuilder<'a, 'b>,
6598 stats: &mut FrameStats,
6599 space_has_keys: bool,
6600 ) {
6601 debug_assert!(space_has_keys, "tried to send ACK in 0-RTT");
6603
6604 debug_assert!(
6605 is_multipath_negotiated || path_id == PathId::ZERO,
6606 "Only PathId::ZERO allowed without multipath (have {path_id:?})"
6607 );
6608 if is_multipath_negotiated {
6609 debug_assert!(
6610 space_id == SpaceId::Data || path_id == PathId::ZERO,
6611 "path acks must be sent in 1RTT space (have {space_id:?})"
6612 );
6613 }
6614
6615 let pns = space.for_path(path_id);
6616 let ranges = pns.pending_acks.ranges();
6617 debug_assert!(!ranges.is_empty(), "can not send empty ACK range");
6618 let ecn = if receiving_ecn {
6619 Some(&pns.ecn_counters)
6620 } else {
6621 None
6622 };
6623
6624 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64;
6625 let ack_delay_exp = TransportParameters::default().ack_delay_exponent;
6627 let delay = delay_micros >> ack_delay_exp.into_inner();
6628
6629 if is_multipath_negotiated && space_id == SpaceId::Data {
6630 if !ranges.is_empty() {
6631 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn);
6632 builder.write_frame(frame, stats);
6633 }
6634 } else {
6635 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats);
6636 }
6637 }
6638
6639 fn close_common(&mut self) {
6640 trace!("connection closed");
6641 self.timers.reset();
6642 }
6643
6644 fn set_close_timer(&mut self, now: Instant) {
6645 let pto_max = self.max_pto_for_space(self.highest_space);
6648 self.timers.set(
6649 Timer::Conn(ConnTimer::Close),
6650 now + 3 * pto_max,
6651 self.qlog.with_time(now),
6652 );
6653 }
6654
6655 fn handle_peer_params(
6660 &mut self,
6661 params: TransportParameters,
6662 local_cid: ConnectionId,
6663 remote_cid: ConnectionId,
6664 now: Instant,
6665 ) -> Result<(), TransportError> {
6666 if Some(self.original_remote_cid) != params.initial_src_cid
6667 || (self.side.is_client()
6668 && (Some(self.initial_dst_cid) != params.original_dst_cid
6669 || self.retry_src_cid != params.retry_src_cid))
6670 {
6671 return Err(TransportError::TRANSPORT_PARAMETER_ERROR(
6672 "CID authentication failure",
6673 ));
6674 }
6675 if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) {
6676 return Err(TransportError::PROTOCOL_VIOLATION(
6677 "multipath must not use zero-length CIDs",
6678 ));
6679 }
6680
6681 self.set_peer_params(params);
6682 self.qlog.emit_peer_transport_params_received(self, now);
6683
6684 Ok(())
6685 }
6686
6687 fn set_peer_params(&mut self, params: TransportParameters) {
6688 self.streams.set_params(¶ms);
6689 self.idle_timeout =
6690 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout));
6691 trace!("negotiated max idle timeout {:?}", self.idle_timeout);
6692
6693 if let Some(ref info) = params.preferred_address {
6694 self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId {
6696 path_id: None,
6697 sequence: 1,
6698 id: info.connection_id,
6699 reset_token: info.stateless_reset_token,
6700 retire_prior_to: 0,
6701 })
6702 .expect(
6703 "preferred address CID is the first received, and hence is guaranteed to be legal",
6704 );
6705 let remote = self.path_data(PathId::ZERO).network_path.remote;
6706 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token);
6707 }
6708 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(¶ms);
6709
6710 let mut multipath_enabled = false;
6711 if let (Some(local_max_path_id), Some(remote_max_path_id)) = (
6712 self.config.get_initial_max_path_id(),
6713 params.initial_max_path_id,
6714 ) {
6715 self.local_max_path_id = local_max_path_id;
6717 self.remote_max_path_id = remote_max_path_id;
6718 let initial_max_path_id = local_max_path_id.min(remote_max_path_id);
6719 debug!(%initial_max_path_id, "multipath negotiated");
6720 multipath_enabled = true;
6721 }
6722
6723 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) =
6724 self.config
6725 .max_remote_nat_traversal_addresses
6726 .zip(params.max_remote_nat_traversal_addresses)
6727 {
6728 if multipath_enabled {
6729 let max_local_addresses = max_remotely_allowed_remote_addresses.get();
6730 let max_remote_addresses = max_locally_allowed_remote_addresses.get();
6731 self.n0_nat_traversal = n0_nat_traversal::State::new(
6732 max_remote_addresses,
6733 max_local_addresses,
6734 self.side(),
6735 );
6736 debug!(
6737 %max_remote_addresses, %max_local_addresses,
6738 "n0's nat traversal negotiated"
6739 );
6740 } else {
6741 debug!("n0 nat traversal enabled for both endpoints, but multipath is missing")
6742 }
6743 }
6744
6745 self.peer_params = params;
6746 let peer_max_udp_payload_size =
6747 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
6748 let address_discovery_negotiated = self
6749 .config
6750 .address_discovery_role
6751 .should_report(&self.peer_params.address_discovery_role);
6752
6753 let path = self.path_data_mut(PathId::ZERO);
6754 path.pending.observed_address = address_discovery_negotiated;
6755 path.mtud
6756 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size);
6757 }
6758
6759 fn decrypt_packet(
6761 &mut self,
6762 now: Instant,
6763 path_id: PathId,
6764 packet: &mut Packet,
6765 ) -> Result<Option<u64>, Option<TransportError>> {
6766 let result = self
6767 .crypto_state
6768 .decrypt_packet_body(packet, path_id, &self.spaces)?;
6769
6770 let Some(result) = result else {
6771 return Ok(None);
6772 };
6773
6774 if result.outgoing_key_update_acked
6775 && let Some(prev) = self.crypto_state.prev_crypto.as_mut()
6776 {
6777 prev.end_packet = Some((result.packet_number, now));
6778 self.set_key_discard_timer(now, packet.header.space());
6779 }
6780
6781 if result.incoming_key_update {
6782 trace!("key update authenticated");
6783 self.crypto_state
6784 .update_keys(Some((result.packet_number, now)), true);
6785 self.set_key_discard_timer(now, packet.header.space());
6786 }
6787
6788 Ok(Some(result.packet_number))
6789 }
6790
6791 fn peer_supports_ack_frequency(&self) -> bool {
6792 self.peer_params.min_ack_delay.is_some()
6793 }
6794
6795 pub(crate) fn immediate_ack(&mut self, path_id: PathId) {
6800 debug_assert_eq!(
6801 self.highest_space,
6802 SpaceKind::Data,
6803 "immediate ack must be written in the data space"
6804 );
6805 self.spaces[SpaceId::Data]
6806 .for_path(path_id)
6807 .pending_immediate_ack = true;
6808 }
6809
6810 #[cfg(test)]
6812 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> {
6813 let ConnectionEventInner::Datagram(DatagramConnectionEvent {
6814 path_id,
6815 first_decode,
6816 remaining,
6817 ..
6818 }) = &event.0
6819 else {
6820 return None;
6821 };
6822
6823 if remaining.is_some() {
6824 panic!("Packets should never be coalesced in tests");
6825 }
6826
6827 let decrypted_header = self
6828 .crypto_state
6829 .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?;
6830
6831 let mut packet = decrypted_header.packet?;
6832 self.crypto_state
6833 .decrypt_packet_body(&mut packet, *path_id, &self.spaces)
6834 .ok()?;
6835
6836 Some(packet.payload.to_vec())
6837 }
6838
6839 #[cfg(test)]
6842 pub(crate) fn bytes_in_flight(&self) -> u64 {
6843 self.path_data(PathId::ZERO).in_flight.bytes
6845 }
6846
6847 #[cfg(test)]
6849 pub(crate) fn congestion_window(&self) -> u64 {
6850 let path = self.path_data(PathId::ZERO);
6851 path.congestion
6852 .window()
6853 .saturating_sub(path.in_flight.bytes)
6854 }
6855
6856 #[cfg(test)]
6858 pub(crate) fn is_idle(&self) -> bool {
6859 let current_timers = self.timers.values();
6860 current_timers
6861 .into_iter()
6862 .filter(|(timer, _)| {
6863 !matches!(
6864 timer,
6865 Timer::Conn(ConnTimer::KeepAlive)
6866 | Timer::PerPath(_, PathTimer::PathKeepAlive)
6867 | Timer::Conn(ConnTimer::PushNewCid)
6868 | Timer::Conn(ConnTimer::KeyDiscard)
6869 )
6870 })
6871 .min_by_key(|(_, time)| *time)
6872 .is_none_or(|(timer, _)| {
6873 matches!(
6874 timer,
6875 Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle)
6876 )
6877 })
6878 }
6879
6880 #[cfg(test)]
6882 pub(crate) fn using_ecn(&self) -> bool {
6883 self.path_data(PathId::ZERO).sending_ecn
6884 }
6885
6886 #[cfg(test)]
6888 pub(crate) fn total_recvd(&self) -> u64 {
6889 self.path_data(PathId::ZERO).total_recvd
6890 }
6891
6892 #[cfg(test)]
6893 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) {
6894 self.local_cid_state
6895 .get(&PathId::ZERO)
6896 .unwrap()
6897 .active_seq()
6898 }
6899
6900 #[cfg(test)]
6901 #[track_caller]
6902 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) {
6903 self.local_cid_state
6904 .get(&PathId(path_id))
6905 .unwrap()
6906 .active_seq()
6907 }
6908
6909 #[cfg(test)]
6912 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) {
6913 let n = self
6914 .local_cid_state
6915 .get_mut(&PathId::ZERO)
6916 .unwrap()
6917 .assign_retire_seq(v);
6918 debug_assert!(!self.state.is_drained()); self.endpoint_events
6920 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6921 }
6922
6923 #[cfg(test)]
6925 pub(crate) fn active_remote_cid_seq(&self) -> u64 {
6926 self.remote_cids.get(&PathId::ZERO).unwrap().active_seq()
6927 }
6928
6929 #[cfg(test)]
6931 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 {
6932 self.path_data(path_id).current_mtu()
6933 }
6934
6935 #[cfg(test)]
6937 pub(crate) fn trigger_path_validation(&mut self) {
6938 for path in self.paths.values_mut() {
6939 path.data.pending_challenge = true;
6940 }
6941 }
6942
6943 #[cfg(test)]
6945 pub fn simulate_protocol_violation(&mut self, now: Instant) {
6946 if !self.state.is_closed() {
6947 self.state
6948 .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation"));
6949 self.close_common();
6950 if !self.state.is_drained() {
6951 self.set_close_timer(now);
6952 }
6953 self.connection_close_pending = true;
6954 }
6955 }
6956
6957 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames {
6968 let network_path = self.path_data(path_id).network_path;
6969 let space_specific = self
6970 .paths
6971 .get(&path_id)
6972 .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty())
6973 || self.spaces[SpaceKind::Data]
6974 .number_spaces
6975 .get(&path_id)
6976 .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path));
6977
6978 let other = self.streams.can_send_stream_data()
6980 || self
6981 .datagrams
6982 .outgoing
6983 .front()
6984 .is_some_and(|x| x.size(true) <= max_size);
6985
6986 SendableFrames {
6988 acks: false,
6989 close: false,
6990 space_specific,
6991 other,
6992 }
6993 }
6994
6995 fn kill(&mut self, reason: ConnectionError) {
6997 self.close_common();
6998 self.state
6999 .move_to_drained(Some(reason), &mut self.endpoint_events);
7000 }
7001
7002 pub fn current_mtu(&self) -> u16 {
7009 self.paths
7010 .iter()
7011 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id))
7012 .map(|(_path_id, path_state)| path_state.data.current_mtu())
7013 .min()
7014 .unwrap_or(INITIAL_MTU)
7015 }
7016
7017 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize {
7024 let pn_len = PacketNumber::new(
7025 pn,
7026 self.spaces[SpaceId::Data]
7027 .for_path(path)
7028 .largest_acked_packet_pn
7029 .unwrap_or(0),
7030 )
7031 .len();
7032
7033 1 + self
7035 .remote_cids
7036 .get(&path)
7037 .map(|cids| cids.active().len())
7038 .unwrap_or(20) + pn_len
7040 + self.tag_len_1rtt()
7041 }
7042
7043 fn predict_1rtt_overhead_no_pn(&self) -> usize {
7044 let pn_len = 4;
7045
7046 let cid_len = self
7047 .remote_cids
7048 .values()
7049 .map(|cids| cids.active().len())
7050 .max()
7051 .unwrap_or(20); 1 + cid_len + pn_len + self.tag_len_1rtt()
7055 }
7056
7057 fn tag_len_1rtt(&self) -> usize {
7058 let packet_crypto = self
7060 .crypto_state
7061 .encryption_keys(SpaceKind::Data, self.side.side())
7062 .map(|(_header, packet, _level)| packet);
7063 packet_crypto.map_or(16, |x| x.tag_len())
7067 }
7068
7069 fn on_path_validated(&mut self, path_id: PathId) {
7071 self.path_data_mut(path_id).validated = true;
7072 let ConnectionSide::Server { server_config } = &self.side else {
7073 return;
7074 };
7075 let network_path = self.path_data(path_id).network_path;
7076 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens;
7077 new_tokens.clear();
7078 for _ in 0..server_config.validation_token.sent {
7079 new_tokens.push(network_path);
7080 }
7081 }
7082
7083 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) {
7085 if let Some(pns) = self.spaces[SpaceKind::Data].number_spaces.get_mut(&path_id) {
7086 pns.status.remote_update(status, status_seq_no);
7087 self.events.push_back(
7088 PathEvent::RemoteStatus {
7089 id: path_id,
7090 status,
7091 }
7092 .into(),
7093 );
7094 } else {
7095 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id);
7096 }
7097 }
7098
7099 fn max_path_id(&self) -> Option<PathId> {
7108 if self.is_multipath_negotiated() {
7109 Some(self.remote_max_path_id.min(self.local_max_path_id))
7110 } else {
7111 None
7112 }
7113 }
7114
7115 pub(crate) fn is_ipv6(&self) -> bool {
7120 self.paths
7121 .values()
7122 .any(|p| p.data.network_path.remote.is_ipv6())
7123 }
7124
7125 pub fn add_nat_traversal_address(
7127 &mut self,
7128 address: SocketAddr,
7129 ) -> Result<(), n0_nat_traversal::Error> {
7130 if let Some(added) = self.n0_nat_traversal.add_local_address(address)? {
7131 self.spaces[SpaceId::Data].pending.add_address.insert(added);
7132 };
7133 Ok(())
7134 }
7135
7136 pub fn remove_nat_traversal_address(
7140 &mut self,
7141 address: SocketAddr,
7142 ) -> Result<(), n0_nat_traversal::Error> {
7143 if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? {
7144 self.spaces[SpaceId::Data]
7145 .pending
7146 .remove_address
7147 .insert(removed);
7148 }
7149 Ok(())
7150 }
7151
7152 pub fn get_local_nat_traversal_addresses(
7154 &self,
7155 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7156 self.n0_nat_traversal.get_local_nat_traversal_addresses()
7157 }
7158
7159 pub fn get_remote_nat_traversal_addresses(
7161 &self,
7162 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7163 Ok(self
7164 .n0_nat_traversal
7165 .client_side()?
7166 .get_remote_nat_traversal_addresses())
7167 }
7168
7169 pub fn initiate_nat_traversal_round(
7181 &mut self,
7182 now: Instant,
7183 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7184 if self.state.is_closed() {
7185 return Err(n0_nat_traversal::Error::Closed);
7186 }
7187
7188 let ipv6 = self.is_ipv6();
7189 let client_state = self.n0_nat_traversal.client_side_mut()?;
7190 let (mut reach_out_frames, probed_addrs) =
7191 client_state.initiate_nat_traversal_round(ipv6)?;
7192 if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) {
7193 self.timers.set(
7194 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
7195 now + delay,
7196 self.qlog.with_time(now),
7197 );
7198 }
7199
7200 self.spaces[SpaceId::Data]
7201 .pending
7202 .reach_out
7203 .append(&mut reach_out_frames);
7204
7205 Ok(probed_addrs)
7206 }
7207
7208 fn is_handshake_confirmed(&self) -> bool {
7217 !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake)
7218 }
7219}
7220
7221impl fmt::Debug for Connection {
7222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7223 f.debug_struct("Connection")
7224 .field("handshake_cid", &self.handshake_cid)
7225 .finish()
7226 }
7227}
7228
7229#[derive(Debug, Default)]
7235struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>);
7236
7237const ABANDONED_PATH_INLINE_RANGES: usize = 16;
7242
7243impl AbandonedPaths {
7244 fn len(&self) -> u32 {
7246 self.0.elts_count()
7247 }
7248
7249 fn max(&self) -> Option<PathId> {
7251 self.0.max().map(PathId::from)
7252 }
7253
7254 fn contains(&self, val: &PathId) -> bool {
7256 self.0.contains(val.as_u32())
7257 }
7258
7259 fn insert(&mut self, val: PathId) {
7261 self.0.insert_one(val.as_u32());
7262 }
7263}
7264
7265pub trait NetworkChangeHint: fmt::Debug + 'static {
7267 fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool;
7276}
7277
7278#[derive(Debug)]
7280enum PollPathSpaceStatus {
7281 NothingToSend {
7283 path_blocked: PathBlocked,
7286 },
7287 WrotePacket {
7289 last_packet_number: u64,
7291 pad_datagram: PadDatagram,
7305 },
7306 Send {
7313 last_packet_number: u64,
7315 },
7316}
7317
7318#[derive(Debug, Copy, Clone)]
7324struct PathSchedulingInfo {
7325 is_abandoned: bool,
7331 may_send_data: bool,
7349 may_send_close: bool,
7355 may_self_abandon: bool,
7356}
7357
7358#[derive(Debug, Copy, Clone, PartialEq, Eq)]
7359enum PathBlocked {
7360 No,
7361 AntiAmplification,
7362 Congestion,
7363 Pacing,
7364}
7365
7366enum ConnectionSide {
7368 Client {
7369 token: Bytes,
7371 token_store: Arc<dyn TokenStore>,
7372 server_name: String,
7373 },
7374 Server {
7375 server_config: Arc<ServerConfig>,
7376 },
7377}
7378
7379impl ConnectionSide {
7380 fn is_client(&self) -> bool {
7381 self.side().is_client()
7382 }
7383
7384 fn is_server(&self) -> bool {
7385 self.side().is_server()
7386 }
7387
7388 fn side(&self) -> Side {
7389 match *self {
7390 Self::Client { .. } => Side::Client,
7391 Self::Server { .. } => Side::Server,
7392 }
7393 }
7394}
7395
7396impl From<SideArgs> for ConnectionSide {
7397 fn from(side: SideArgs) -> Self {
7398 match side {
7399 SideArgs::Client {
7400 token_store,
7401 server_name,
7402 } => Self::Client {
7403 token: token_store.take(&server_name).unwrap_or_default(),
7404 token_store,
7405 server_name,
7406 },
7407 SideArgs::Server {
7408 server_config,
7409 pref_addr_cid: _,
7410 path_validated: _,
7411 } => Self::Server { server_config },
7412 }
7413 }
7414}
7415
7416pub(crate) enum SideArgs {
7418 Client {
7419 token_store: Arc<dyn TokenStore>,
7420 server_name: String,
7421 },
7422 Server {
7423 server_config: Arc<ServerConfig>,
7424 pref_addr_cid: Option<ConnectionId>,
7425 path_validated: bool,
7426 },
7427}
7428
7429impl SideArgs {
7430 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> {
7431 match *self {
7432 Self::Client { .. } => None,
7433 Self::Server { pref_addr_cid, .. } => pref_addr_cid,
7434 }
7435 }
7436
7437 pub(crate) fn path_validated(&self) -> bool {
7438 match *self {
7439 Self::Client { .. } => true,
7440 Self::Server { path_validated, .. } => path_validated,
7441 }
7442 }
7443
7444 pub(crate) fn side(&self) -> Side {
7445 match *self {
7446 Self::Client { .. } => Side::Client,
7447 Self::Server { .. } => Side::Server,
7448 }
7449 }
7450}
7451
7452#[derive(Debug, Error, Clone, PartialEq, Eq)]
7454pub enum ConnectionError {
7455 #[error("peer doesn't implement any supported version")]
7457 VersionMismatch,
7458 #[error(transparent)]
7460 TransportError(#[from] TransportError),
7461 #[error("aborted by peer: {0}")]
7463 ConnectionClosed(frame::ConnectionClose),
7464 #[error("closed by peer: {0}")]
7466 ApplicationClosed(frame::ApplicationClose),
7467 #[error("reset by peer")]
7469 Reset,
7470 #[error("timed out")]
7476 TimedOut,
7477 #[error("closed")]
7479 LocallyClosed,
7480 #[error("CIDs exhausted")]
7484 CidsExhausted,
7485}
7486
7487impl From<Close> for ConnectionError {
7488 fn from(x: Close) -> Self {
7489 match x {
7490 Close::Connection(reason) => Self::ConnectionClosed(reason),
7491 Close::Application(reason) => Self::ApplicationClosed(reason),
7492 }
7493 }
7494}
7495
7496impl From<ConnectionError> for io::Error {
7498 fn from(x: ConnectionError) -> Self {
7499 use ConnectionError::*;
7500 let kind = match x {
7501 TimedOut => io::ErrorKind::TimedOut,
7502 Reset => io::ErrorKind::ConnectionReset,
7503 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted,
7504 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => {
7505 io::ErrorKind::Other
7506 }
7507 };
7508 Self::new(kind, x)
7509 }
7510}
7511
7512#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
7515pub enum PathError {
7516 #[error("multipath extension not negotiated")]
7518 MultipathNotNegotiated,
7519 #[error("the server side may not open a path")]
7521 ServerSideNotAllowed,
7522 #[error("maximum number of concurrent paths reached")]
7524 MaxPathIdReached,
7525 #[error("remoted CIDs exhausted")]
7527 RemoteCidsExhausted,
7528 #[error("path validation failed")]
7530 ValidationFailed,
7531 #[error("invalid remote address")]
7533 InvalidRemoteAddress(SocketAddr),
7534}
7535
7536#[derive(Debug, Error, Clone, Eq, PartialEq)]
7538pub enum ClosePathError {
7539 #[error("Multipath extension not negotiated")]
7541 MultipathNotNegotiated,
7542 #[error("closed path")]
7544 ClosedPath,
7545 #[error("last open path")]
7549 LastOpenPath,
7550}
7551
7552#[derive(Debug, Error, Clone, Copy)]
7554#[error("Multipath extension not negotiated")]
7555pub struct MultipathNotNegotiated {
7556 _private: (),
7557}
7558
7559#[derive(Debug)]
7561pub enum Event {
7562 HandshakeDataReady,
7564 Connected,
7566 HandshakeConfirmed,
7568 ConnectionLost {
7575 reason: ConnectionError,
7577 },
7578 Stream(StreamEvent),
7580 DatagramReceived,
7582 DatagramsUnblocked,
7584 Path(PathEvent),
7586 NatTraversal(n0_nat_traversal::Event),
7588}
7589
7590impl From<PathEvent> for Event {
7591 fn from(source: PathEvent) -> Self {
7592 Self::Path(source)
7593 }
7594}
7595
7596fn get_max_ack_delay(params: &TransportParameters) -> Duration {
7597 Duration::from_micros(params.max_ack_delay.0 * 1000)
7598}
7599
7600const MAX_BACKOFF_EXPONENT: u32 = 16;
7602
7603const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2);
7607
7608const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25);
7610
7611const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1);
7616
7617const SLOW_RTT_THRESHOLD: Duration =
7622 Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3);
7623
7624const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32;
7632
7633const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize =
7639 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4;
7640
7641#[derive(Default)]
7642struct SentFrames {
7643 retransmits: ThinRetransmits,
7644 path_retransmits: PathRetransmits,
7645 largest_acked: FxHashMap<PathId, u64>,
7647 stream_frames: StreamMetaVec,
7648 non_retransmits: bool,
7650 requires_padding: bool,
7652}
7653
7654impl SentFrames {
7655 fn is_ack_only(&self, streams: &StreamsState) -> bool {
7657 !self.largest_acked.is_empty()
7658 && !self.non_retransmits
7659 && self.stream_frames.is_empty()
7660 && self.retransmits.is_empty(streams)
7661 }
7662
7663 fn retransmits_mut(&mut self) -> &mut Retransmits {
7664 self.retransmits.get_or_create()
7665 }
7666
7667 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) {
7668 use frame::EncodableFrame::*;
7669 match frame {
7670 PathAck(path_ack_encoder) => {
7671 if let Some(max) = path_ack_encoder.ranges.max() {
7672 self.largest_acked.insert(path_ack_encoder.path_id, max);
7673 }
7674 }
7675 Ack(ack_encoder) => {
7676 if let Some(max) = ack_encoder.ranges.max() {
7677 self.largest_acked.insert(PathId::ZERO, max);
7678 }
7679 }
7680 Close(_) => { }
7681 PathResponse(_) => self.non_retransmits = true,
7682 HandshakeDone(_) => self.retransmits_mut().handshake_done = true,
7683 ReachOut(frame) => self.retransmits_mut().reach_out.push(frame),
7684 ObservedAddr(_) => self.path_retransmits.observed_address = true,
7685 Ping(_) => self.non_retransmits = true,
7686 ImmediateAck(_) => self.non_retransmits = true,
7687 AckFrequency(_) => self.retransmits_mut().ack_frequency = true,
7688 PathChallenge(_) => self.non_retransmits = true,
7689 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto),
7690 PathAbandon(path_abandon) => {
7691 self.retransmits_mut()
7692 .path_abandon
7693 .entry(path_abandon.path_id)
7694 .or_insert(path_abandon.error_code);
7695 }
7696 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. })
7697 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => {
7698 self.retransmits_mut().path_status.insert(path_id);
7699 }
7700 MaxPathId(_) => self.retransmits_mut().max_path_id = true,
7701 PathsBlocked(frame::PathsBlocked(path_id)) => {
7702 let paths_blocked = &mut self.retransmits_mut().paths_blocked;
7703 *paths_blocked = cmp::max(*paths_blocked, Some(path_id));
7704 }
7705 PathCidsBlocked(path_cids_blocked) => {
7706 self.retransmits_mut()
7707 .path_cids_blocked
7708 .entry(path_cids_blocked.path_id)
7709 .and_modify(|next_seq| {
7710 *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq);
7711 })
7712 .or_insert(path_cids_blocked.next_seq);
7713 }
7714 ResetStream(reset) => self
7715 .retransmits_mut()
7716 .reset_stream
7717 .push((reset.id, reset.error_code)),
7718 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending),
7719 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()),
7720 RetireConnectionId(retire_cid) => self
7721 .retransmits_mut()
7722 .retire_cids
7723 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)),
7724 Datagram(_) => self.non_retransmits = true,
7725 NewToken(_) => {}
7726 AddAddress(add_address) => {
7727 self.retransmits_mut().add_address.insert(add_address);
7728 }
7729 RemoveAddress(remove_address) => {
7730 self.retransmits_mut().remove_address.insert(remove_address);
7731 }
7732 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta),
7733 MaxData(_) => self.retransmits_mut().max_data = true,
7734 MaxStreamData(max) => {
7735 self.retransmits_mut().max_stream_data.insert(max.id);
7736 }
7737 MaxStreams(max_streams) => {
7738 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true
7739 }
7740 StreamsBlocked(streams_blocked) => {
7741 self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true
7742 }
7743 }
7744 }
7745}
7746
7747fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> {
7759 match (x, y) {
7760 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None,
7761 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)),
7762 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)),
7763 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)),
7764 }
7765}
7766
7767#[cfg(test)]
7768mod tests {
7769 use super::*;
7770
7771 #[test]
7772 fn negotiate_max_idle_timeout_commutative() {
7773 let test_params = [
7774 (None, None, None),
7775 (None, Some(VarInt(0)), None),
7776 (None, Some(VarInt(2)), Some(Duration::from_millis(2))),
7777 (Some(VarInt(0)), Some(VarInt(0)), None),
7778 (
7779 Some(VarInt(2)),
7780 Some(VarInt(0)),
7781 Some(Duration::from_millis(2)),
7782 ),
7783 (
7784 Some(VarInt(1)),
7785 Some(VarInt(4)),
7786 Some(Duration::from_millis(1)),
7787 ),
7788 ];
7789
7790 for (left, right, result) in test_params {
7791 assert_eq!(negotiate_max_idle_timeout(left, right), result);
7792 assert_eq!(negotiate_max_idle_timeout(right, left), result);
7793 }
7794 }
7795
7796 #[test]
7797 fn abandoned_paths() {
7798 let mut t = AbandonedPaths::default();
7799
7800 t.insert(PathId(0));
7801 t.insert(PathId(1));
7802 assert_eq!(t.len(), 2);
7803 assert_eq!(t.0.range_count(), 1); assert!(t.contains(&PathId(0)));
7805 assert!(t.contains(&PathId(1)));
7806 assert!(!t.contains(&PathId(2)));
7807 assert!(!t.contains(&PathId(3)));
7808 assert_eq!(t.max(), Some(PathId(1)));
7809
7810 t.insert(PathId(3));
7811 assert_eq!(t.len(), 3);
7812 assert_eq!(t.0.range_count(), 2); assert!(t.contains(&PathId(0)));
7814 assert!(t.contains(&PathId(1)));
7815 assert!(!t.contains(&PathId(2)));
7816 assert!(t.contains(&PathId(3)));
7817 assert_eq!(t.max(), Some(PathId(3)));
7818
7819 t.insert(PathId(2));
7820 assert_eq!(t.len(), 4);
7821 assert_eq!(t.0.range_count(), 1); assert!(t.contains(&PathId(0)));
7823 assert!(t.contains(&PathId(1)));
7824 assert!(t.contains(&PathId(2)));
7825 assert!(t.contains(&PathId(3)));
7826 assert_eq!(t.max(), Some(PathId(3)));
7827 }
7828}