1use std::{
2 cmp,
3 collections::{BTreeMap, VecDeque, btree_map},
4 convert::TryFrom,
5 fmt, io, mem,
6 net::SocketAddr,
7 num::{NonZeroU32, NonZeroUsize},
8 sync::Arc,
9};
10
11use bytes::{Bytes, BytesMut};
12use frame::StreamMetaVec;
13
14use rand::{RngExt, SeedableRng, rngs::StdRng};
15use rustc_hash::FxHashMap;
16use thiserror::Error;
17use tracing::{debug, error, trace, trace_span, warn};
18
19use crate::{
20 Dir, Duration, EndpointConfig, FourTuple, Frame, INITIAL_MTU, Instant, MAX_CID_SIZE,
21 MAX_STREAM_COUNT, MIN_INITIAL_SIZE, Side, StreamId, TIMER_GRANULARITY, TokenStore, Transmit,
22 TransportError, TransportErrorCode, VarInt,
23 cid_generator::ConnectionIdGenerator,
24 cid_queue::CidQueue,
25 config::{ServerConfig, TransportConfig},
26 congestion::Controller,
27 connection::{
28 paths::PathRetransmits,
29 qlog::{QlogRecvPacket, QlogSink},
30 spaces::LostPacket,
31 stats::PathStatsMap,
32 timer::{ConnTimer, PathTimer},
33 },
34 crypto::{self, Keys},
35 frame::{
36 self, Close, DataBlocked, Datagram, FrameStruct, NewToken, ObservedAddr, StreamDataBlocked,
37 StreamsBlocked,
38 },
39 n0_nat_traversal,
40 packet::{
41 FixedLengthConnectionIdParser, Header, InitialHeader, InitialPacket, LongType, Packet,
42 PacketNumber, PartialDecode, SpaceId,
43 },
44 range_set::ArrayRangeSet,
45 shared::{
46 ConnectionEvent, ConnectionEventInner, ConnectionId, DatagramConnectionEvent, EcnCodepoint,
47 EndpointEvent, EndpointEventInner,
48 },
49 token::{ResetToken, Token, TokenPayload},
50 transport_parameters::TransportParameters,
51};
52
53mod ack_frequency;
54use ack_frequency::AckFrequencyState;
55
56mod assembler;
57pub use assembler::Chunk;
58
59mod cid_state;
60use cid_state::CidState;
61
62mod datagrams;
63use datagrams::DatagramState;
64pub use datagrams::{Datagrams, SendDatagramError};
65
66mod mtud;
67mod pacing;
68
69mod packet_builder;
70use packet_builder::{PacketBuilder, PadDatagram};
71
72mod packet_crypto;
73use packet_crypto::CryptoState;
74pub(crate) use packet_crypto::EncryptionLevel;
75
76mod paths;
77pub use paths::{
78 ClosedPath, PathAbandonReason, PathEvent, PathId, PathStatus, RttEstimator, SetPathStatusError,
79};
80use paths::{PathData, PathState};
81
82pub(crate) mod qlog;
83pub(crate) mod send_buffer;
84
85pub(crate) mod spaces;
86#[cfg(fuzzing)]
87pub use spaces::Retransmits;
88#[cfg(not(fuzzing))]
89use spaces::Retransmits;
90pub(crate) use spaces::SpaceKind;
91use spaces::{OpenStatus, PacketSpace, SendableFrames, SentPacket, ThinRetransmits};
92
93mod stats;
94pub use stats::{ConnectionStats, FrameStats, PathStats, UdpStats};
95
96mod streams;
97#[cfg(fuzzing)]
98pub use streams::StreamsState;
99#[cfg(not(fuzzing))]
100use streams::StreamsState;
101pub use streams::{
102 Chunks, ClosedStream, FinishError, ReadError, ReadableError, RecvStream, SendStream,
103 ShouldTransmit, StreamEvent, Streams, WriteError,
104};
105
106mod timer;
107use timer::{Timer, TimerTable};
108
109mod transmit_buf;
110use transmit_buf::TransmitBuf;
111
112mod state;
113
114#[cfg(not(fuzzing))]
115use state::State;
116#[cfg(fuzzing)]
117pub use state::State;
118use state::StateType;
119
120pub struct Connection {
159 endpoint_config: Arc<EndpointConfig>,
160 config: Arc<TransportConfig>,
161 rng: StdRng,
162 crypto_state: CryptoState,
164 handshake_cid: ConnectionId,
166 remote_handshake_cid: ConnectionId,
168 paths: BTreeMap<PathId, PathState>,
174 path_generation_counter: u64,
185 allow_mtud: bool,
187 state: State,
188 side: ConnectionSide,
189 peer_params: TransportParameters,
191 original_remote_cid: ConnectionId,
193 initial_dst_cid: ConnectionId,
195 retry_src_cid: Option<ConnectionId>,
198 events: VecDeque<Event>,
200 endpoint_events: VecDeque<EndpointEventInner>,
201 spin_enabled: bool,
203 spin: bool,
205 spaces: [PacketSpace; 3],
207 highest_space: SpaceKind,
209 idle_timeout: Option<Duration>,
211 timers: TimerTable,
212 authentication_failures: u64,
214
215 connection_close_pending: bool,
219
220 ack_frequency: AckFrequencyState,
223
224 receiving_ecn: bool,
228 total_authed_packets: u64,
230
231 next_observed_addr_seq_no: VarInt,
235
236 streams: StreamsState,
237 remote_cids: FxHashMap<PathId, CidQueue>,
243 local_cid_state: FxHashMap<PathId, CidState>,
250 datagrams: DatagramState,
252 path_stats: PathStatsMap,
254 partial_stats: ConnectionStats,
260 version: u32,
262
263 max_concurrent_paths: NonZeroU32,
271 local_max_path_id: PathId,
286 remote_max_path_id: PathId,
292 max_path_id_with_cids: PathId,
298 abandoned_paths: AbandonedPaths,
304
305 n0_nat_traversal: n0_nat_traversal::State,
307 qlog: QlogSink,
308}
309
310impl Connection {
311 pub(crate) fn new(
312 endpoint_config: Arc<EndpointConfig>,
313 config: Arc<TransportConfig>,
314 init_cid: ConnectionId,
315 local_cid: ConnectionId,
316 remote_cid: ConnectionId,
317 network_path: FourTuple,
318 crypto: Box<dyn crypto::Session>,
319 cid_gen: &dyn ConnectionIdGenerator,
320 now: Instant,
321 version: u32,
322 allow_mtud: bool,
323 rng_seed: [u8; 32],
324 side_args: SideArgs,
325 qlog: QlogSink,
326 ) -> Self {
327 let pref_addr_cid = side_args.pref_addr_cid();
328 let path_validated = side_args.path_validated();
329 let connection_side = ConnectionSide::from(side_args);
330 let side = connection_side.side();
331 let mut rng = StdRng::from_seed(rng_seed);
332 let mut initial_space = PacketSpace::new(now, SpaceId::Initial, &mut rng);
333 let mut handshake_space = PacketSpace::new(now, SpaceId::Handshake, &mut rng);
334 #[cfg(test)]
335 let mut data_space = match config.deterministic_packet_numbers {
336 true => PacketSpace::new_deterministic(now, SpaceId::Data),
337 false => PacketSpace::new(now, SpaceId::Data, &mut rng),
338 };
339 #[cfg(not(test))]
340 let mut data_space = PacketSpace::new(now, SpaceId::Data, &mut rng);
341
342 initial_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
344 handshake_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
345 data_space.for_path(PathId::ZERO).open_status = OpenStatus::Informed;
346
347 let state = State::handshake(state::Handshake {
348 remote_cid_set: side.is_server(),
349 expected_token: Bytes::new(),
350 client_hello: None,
351 allow_server_migration: side.is_client() && config.server_handshake_migration,
352 });
353 let local_cid_state = FxHashMap::from_iter([(
354 PathId::ZERO,
355 CidState::new(
356 cid_gen.cid_len(),
357 cid_gen.cid_lifetime(),
358 now,
359 if pref_addr_cid.is_some() { 2 } else { 1 },
360 ),
361 )]);
362
363 let mut this = Self {
364 endpoint_config,
365 crypto_state: CryptoState::new(crypto, init_cid, side, &mut rng),
366 handshake_cid: local_cid,
367 remote_handshake_cid: remote_cid,
368 local_cid_state,
369 paths: BTreeMap::from_iter([(
370 PathId::ZERO,
371 PathState {
372 data: PathData::new(network_path, allow_mtud, None, 0, now, &config),
373 prev: None,
374 },
375 )]),
376 path_generation_counter: 0,
377 allow_mtud,
378 state,
379 side: connection_side,
380 peer_params: TransportParameters::default(),
381 original_remote_cid: remote_cid,
382 initial_dst_cid: init_cid,
383 retry_src_cid: None,
384 events: VecDeque::new(),
385 endpoint_events: VecDeque::new(),
386 spin_enabled: config.allow_spin && rng.random_ratio(7, 8),
387 spin: false,
388 spaces: [initial_space, handshake_space, data_space],
389 highest_space: SpaceKind::Initial,
390 idle_timeout: match config.max_idle_timeout {
391 None | Some(VarInt(0)) => None,
392 Some(dur) => Some(Duration::from_millis(dur.0)),
393 },
394 timers: TimerTable::default(),
395 authentication_failures: 0,
396 connection_close_pending: false,
397
398 ack_frequency: AckFrequencyState::new(get_max_ack_delay(
399 &TransportParameters::default(),
400 )),
401
402 receiving_ecn: false,
403 total_authed_packets: 0,
404
405 next_observed_addr_seq_no: 0u32.into(),
406
407 streams: StreamsState::new(
408 side,
409 config.max_concurrent_uni_streams,
410 config.max_concurrent_bidi_streams,
411 config.send_window,
412 config.receive_window,
413 config.stream_receive_window,
414 ),
415 datagrams: DatagramState::default(),
416 config,
417 remote_cids: FxHashMap::from_iter([(PathId::ZERO, CidQueue::new(remote_cid))]),
418 rng,
419 path_stats: Default::default(),
420 partial_stats: ConnectionStats::default(),
421 version,
422
423 max_concurrent_paths: NonZeroU32::MIN,
425 local_max_path_id: PathId::ZERO,
426 remote_max_path_id: PathId::ZERO,
427 max_path_id_with_cids: PathId::ZERO,
428 abandoned_paths: Default::default(),
429
430 n0_nat_traversal: Default::default(),
431 qlog,
432 };
433 if path_validated {
434 this.on_path_validated(PathId::ZERO);
435 }
436 if side.is_client() {
437 this.write_crypto();
439 this.init_0rtt(now);
440 }
441 this.qlog
442 .emit_tuple_assigned(PathId::ZERO, network_path, now);
443 this
444 }
445
446 #[must_use]
454 pub fn poll_timeout(&self) -> Option<Instant> {
455 self.timers.peek()
456 }
457
458 #[must_use]
464 pub fn poll(&mut self) -> Option<Event> {
465 if let Some(x) = self.events.pop_front() {
466 return Some(x);
467 }
468
469 if let Some(event) = self.streams.poll() {
470 return Some(Event::Stream(event));
471 }
472
473 if let Some(reason) = self.state.take_error() {
474 return Some(Event::ConnectionLost { reason });
475 }
476
477 None
478 }
479
480 #[must_use]
482 pub fn poll_endpoint_events(&mut self) -> Option<EndpointEvent> {
483 self.endpoint_events.pop_front().map(EndpointEvent)
484 }
485
486 #[must_use]
488 pub fn streams(&mut self) -> Streams<'_> {
489 Streams {
490 state: &mut self.streams,
491 conn_state: &self.state,
492 }
493 }
494
495 #[must_use]
497 pub fn recv_stream(&mut self, id: StreamId) -> RecvStream<'_> {
498 assert!(id.dir() == Dir::Bi || id.initiator() != self.side.side());
499 RecvStream {
500 id,
501 state: &mut self.streams,
502 pending: &mut self.spaces[SpaceId::Data].pending,
503 }
504 }
505
506 #[must_use]
508 pub fn send_stream(&mut self, id: StreamId) -> SendStream<'_> {
509 assert!(id.dir() == Dir::Bi || id.initiator() == self.side.side());
510 SendStream {
511 id,
512 state: &mut self.streams,
513 pending: &mut self.spaces[SpaceId::Data].pending,
514 conn_state: &self.state,
515 }
516 }
517
518 pub fn open_path_ensure(
535 &mut self,
536 network_path: FourTuple,
537 initial_status: PathStatus,
538 now: Instant,
539 ) -> Result<(PathId, bool), PathError> {
540 let existing_open_path = self.paths.iter().find(|(id, path)| {
541 network_path.is_probably_same_path(&path.data.network_path)
542 && !self.abandoned_paths.contains(id)
543 });
544 match existing_open_path {
545 Some((path_id, _state)) => Ok((*path_id, true)),
546 None => Ok((self.open_path(network_path, initial_status, now)?, false)),
547 }
548 }
549
550 pub fn open_path(
556 &mut self,
557 network_path: FourTuple,
558 initial_status: PathStatus,
559 now: Instant,
560 ) -> Result<PathId, PathError> {
561 let Some(max_path_id) = self.max_path_id() else {
562 return Err(PathError::MultipathNotNegotiated);
563 };
564 if self.side().is_server() {
565 return Err(PathError::ServerSideNotAllowed);
566 }
567
568 let max_abandoned = self.abandoned_paths.max();
569 let max_used = self.paths.keys().last().copied();
570 let path_id = max_abandoned
571 .max(max_used)
572 .unwrap_or(PathId::ZERO)
573 .saturating_add(1u8);
574
575 if path_id > max_path_id {
576 self.spaces[SpaceId::Data].pending.paths_blocked = Some(self.remote_max_path_id);
577 return Err(PathError::MaxPathIdReached);
578 }
579 if !self.remote_cids.contains_key(&path_id) {
580 self.spaces[SpaceId::Data]
581 .pending
582 .path_cids_blocked
583 .insert(path_id, VarInt(0));
584 return Err(PathError::RemoteCidsExhausted);
585 }
586
587 let path = self.create_path(path_id, network_path, now, None);
588 path.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.path(path_id)
798 .map(PathData::local_status)
799 .ok_or(ClosedPath { _private: () })
800 }
801
802 pub fn network_path(&self, path_id: PathId) -> Result<FourTuple, ClosedPath> {
804 self.path(path_id)
805 .map(|path| path.network_path)
806 .ok_or(ClosedPath { _private: () })
807 }
808
809 pub fn set_path_status(
813 &mut self,
814 path_id: PathId,
815 status: PathStatus,
816 ) -> Result<PathStatus, SetPathStatusError> {
817 if !self.is_multipath_negotiated() {
818 return Err(SetPathStatusError::MultipathNotNegotiated);
819 }
820 let path = self
821 .path_mut(path_id)
822 .ok_or(SetPathStatusError::ClosedPath)?;
823 let prev = match path.status.local_update(status) {
824 Some(prev) => {
825 self.spaces[SpaceId::Data]
826 .pending
827 .path_status
828 .insert(path_id);
829 prev
830 }
831 None => path.local_status(),
832 };
833 Ok(prev)
834 }
835
836 pub fn remote_path_status(&self, path_id: PathId) -> Option<PathStatus> {
841 self.path(path_id).and_then(|path| path.remote_status())
842 }
843
844 pub fn set_path_max_idle_timeout(
853 &mut self,
854 now: Instant,
855 path_id: PathId,
856 timeout: Option<Duration>,
857 ) -> Result<Option<Duration>, ClosedPath> {
858 let path = self
859 .paths
860 .get_mut(&path_id)
861 .ok_or(ClosedPath { _private: () })?;
862 let prev_timeout = mem::replace(&mut path.data.idle_timeout, timeout);
863
864 self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
872
873 Ok(prev_timeout)
874 }
875
876 fn rearm_path_max_idle_timer(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
884 let timer = Timer::PerPath(path_id, PathTimer::PathIdle);
885
886 if self.state.is_closed() || !self.is_multipath_negotiated() {
887 return self.timers.stop(timer, self.qlog.with_time(now));
888 }
889
890 if let Some(timeout) = self.path_data(path_id).idle_timeout {
891 let dt = cmp::max(timeout, 3 * self.pto(space, path_id));
892 self.timers.set(timer, now + dt, self.qlog.with_time(now));
893 } else {
894 self.timers.stop(timer, self.qlog.with_time(now));
895 }
896 }
897
898 pub fn set_path_keep_alive_interval(
904 &mut self,
905 path_id: PathId,
906 interval: Option<Duration>,
907 ) -> Result<Option<Duration>, ClosedPath> {
908 let path = self
909 .paths
910 .get_mut(&path_id)
911 .ok_or(ClosedPath { _private: () })?;
912 Ok(mem::replace(&mut path.data.keep_alive, interval))
913 }
914
915 fn find_validated_path_on_network_path(
919 &self,
920 network_path: FourTuple,
921 ) -> Option<(&PathId, &PathState)> {
922 self.paths.iter().find(|(path_id, path_state)| {
923 path_state.data.validated
924 && network_path.is_probably_same_path(&path_state.data.network_path)
926 && !self.abandoned_paths.contains(path_id)
927 })
928 }
933
934 fn create_path(
938 &mut self,
939 path_id: PathId,
940 network_path: FourTuple,
941 now: Instant,
942 pn: Option<u64>,
943 ) -> &mut PathData {
944 let valid_path = self.find_validated_path_on_network_path(network_path);
945 let validated = valid_path.is_some();
946 let initial_rtt = valid_path.map(|(_, path)| path.data.rtt.conservative());
947 let vacant_entry = match self.paths.entry(path_id) {
948 btree_map::Entry::Vacant(vacant_entry) => vacant_entry,
949 btree_map::Entry::Occupied(occupied_entry) => {
950 return &mut occupied_entry.into_mut().data;
951 }
952 };
953
954 debug!(%validated, %path_id, %network_path, "path added");
955
956 self.timers.stop(
958 Timer::Conn(ConnTimer::NoAvailablePath),
959 self.qlog.with_time(now),
960 );
961 let peer_max_udp_payload_size =
962 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
963 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
964 let mut data = PathData::new(
965 network_path,
966 self.allow_mtud,
967 Some(peer_max_udp_payload_size),
968 self.path_generation_counter,
969 now,
970 &self.config,
971 );
972
973 data.validated = validated;
974 if let Some(initial_rtt) = initial_rtt {
975 data.rtt.reset_initial_rtt(initial_rtt);
976 }
977
978 data.pending_challenge = true;
981 data.pending.observed_address = self
982 .config
983 .address_discovery_role
984 .should_report(&self.peer_params.address_discovery_role);
985
986 let path = vacant_entry.insert(PathState { data, prev: None });
987
988 let mut pn_space = spaces::PacketNumberSpace::new(now, SpaceId::Data, &mut self.rng);
989 if let Some(pn) = pn {
990 pn_space.dedup.insert(pn);
991 }
992 self.spaces[SpaceId::Data]
993 .number_spaces
994 .insert(path_id, pn_space);
995 self.qlog.emit_tuple_assigned(path_id, network_path, now);
996
997 if !self.remote_cids.contains_key(&path_id) {
1001 debug!(%path_id, "Remote opened path without issuing CIDs");
1002 self.spaces[SpaceId::Data]
1003 .pending
1004 .path_cids_blocked
1005 .insert(path_id, VarInt(0));
1006 }
1009
1010 &mut path.data
1011 }
1012
1013 #[must_use]
1023 pub fn poll_transmit(
1024 &mut self,
1025 now: Instant,
1026 max_datagrams: NonZeroUsize,
1027 buf: &mut Vec<u8>,
1028 ) -> Option<Transmit> {
1029 let max_datagrams = match self.config.enable_segmentation_offload {
1030 false => NonZeroUsize::MIN,
1031 true => max_datagrams,
1032 };
1033
1034 let connection_close_pending = match self.state.as_type() {
1040 StateType::Drained => {
1041 for path in self.paths.values_mut() {
1042 path.data.app_limited = true;
1043 }
1044 return None;
1045 }
1046 StateType::Draining | StateType::Closed => {
1047 if !self.connection_close_pending {
1050 for path in self.paths.values_mut() {
1051 path.data.app_limited = true;
1052 }
1053 return None;
1054 }
1055 true
1056 }
1057 _ => false,
1058 };
1059
1060 if let Some(config) = &self.config.ack_frequency_config {
1062 let rtt = self
1063 .paths
1064 .values()
1065 .map(|p| p.data.rtt.get())
1066 .min()
1067 .expect("one path exists");
1068 self.spaces[SpaceId::Data].pending.ack_frequency = self
1069 .ack_frequency
1070 .should_send_ack_frequency(rtt, config, &self.peer_params)
1071 && self.highest_space == SpaceKind::Data
1072 && self.peer_supports_ack_frequency();
1073 }
1074
1075 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1076 while let Some(path_id) = next_path_id {
1077 if !connection_close_pending
1078 && let Some(transmit) = self.poll_transmit_off_path(now, buf, path_id)
1079 {
1080 #[cfg(test)]
1081 {
1082 self.partial_stats.transmits_tx += 1;
1083 }
1084 return Some(transmit);
1085 }
1086
1087 let info = self.scheduling_info(path_id);
1088 if let Some(transmit) = self.poll_transmit_on_path(
1089 now,
1090 buf,
1091 path_id,
1092 max_datagrams,
1093 &info,
1094 connection_close_pending,
1095 ) {
1096 #[cfg(test)]
1097 {
1098 self.partial_stats.transmits_tx += 1;
1099 }
1100 return Some(transmit);
1101 }
1102
1103 debug_assert!(
1106 buf.is_empty(),
1107 "nothing to send on path but buffer not empty"
1108 );
1109
1110 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1111 }
1112
1113 debug_assert!(
1115 buf.is_empty(),
1116 "there was data in the buffer, but it was not sent"
1117 );
1118
1119 if self.state.is_established() {
1120 let mut next_path_id = self.paths.first_entry().map(|e| *e.key());
1122 while let Some(path_id) = next_path_id {
1123 if let Some(transmit) = self.poll_transmit_mtu_probe(now, buf, path_id) {
1124 #[cfg(test)]
1125 {
1126 self.partial_stats.transmits_tx += 1;
1127 }
1128 return Some(transmit);
1129 }
1130 next_path_id = self.paths.keys().find(|i| **i > path_id).copied();
1131 }
1132 }
1133
1134 None
1135 }
1136
1137 fn scheduling_info(&self, path_id: PathId) -> PathSchedulingInfo {
1155 let have_validated_status_available_space = self.paths.iter().any(|(path_id, path)| {
1157 self.remote_cids.contains_key(path_id)
1158 && !self.abandoned_paths.contains(path_id)
1159 && path.data.validated
1160 && path.data.local_status() == PathStatus::Available
1161 });
1162
1163 let have_validated_space = self.paths.iter().any(|(path_id, path)| {
1165 self.remote_cids.contains_key(path_id)
1166 && !self.abandoned_paths.contains(path_id)
1167 && path.data.validated
1168 });
1169
1170 let is_handshaking = self.is_handshaking();
1171 let has_cids = self.remote_cids.contains_key(&path_id);
1172 let is_abandoned = self.abandoned_paths.contains(&path_id);
1173 let path_data = self.path_data(path_id);
1174 let validated = path_data.validated;
1175 let status = path_data.local_status();
1176
1177 let may_send_data = has_cids
1180 && !is_abandoned
1181 && if is_handshaking {
1182 true
1186 } else if !validated {
1187 false
1194 } else {
1195 match status {
1196 PathStatus::Available => {
1197 true
1199 }
1200 PathStatus::Backup => {
1201 !have_validated_status_available_space
1203 }
1204 }
1205 };
1206
1207 let may_send_close = has_cids
1212 && !is_abandoned
1213 && if !validated && have_validated_status_available_space {
1214 false
1216 } else {
1217 true
1219 };
1220
1221 let may_self_abandon = has_cids && validated && !have_validated_space;
1225
1226 PathSchedulingInfo {
1227 is_abandoned,
1228 may_send_data,
1229 may_send_close,
1230 may_self_abandon,
1231 }
1232 }
1233
1234 fn build_transmit(&mut self, path_id: PathId, transmit: TransmitBuf<'_>) -> Transmit {
1235 debug_assert!(
1236 !transmit.is_empty(),
1237 "must not be called with an empty transmit buffer"
1238 );
1239
1240 let network_path = self.path_data(path_id).network_path;
1241 trace!(
1242 segment_size = transmit.segment_size(),
1243 last_datagram_len = transmit.len() % transmit.segment_size(),
1244 %network_path,
1245 "sending {} bytes in {} datagrams",
1246 transmit.len(),
1247 transmit.num_datagrams()
1248 );
1249 self.path_data_mut(path_id)
1250 .inc_total_sent(transmit.len() as u64);
1251
1252 self.path_stats
1253 .get_mut(path_id)
1254 .udp_tx
1255 .on_sent(transmit.num_datagrams() as u64, transmit.len());
1256
1257 Transmit {
1258 destination: network_path.remote,
1259 size: transmit.len(),
1260 ecn: if self.path_data(path_id).sending_ecn {
1261 Some(EcnCodepoint::Ect0)
1262 } else {
1263 None
1264 },
1265 segment_size: match transmit.num_datagrams() {
1266 1 => None,
1267 _ => Some(transmit.segment_size()),
1268 },
1269 src_ip: network_path.local_ip,
1270 }
1271 }
1272
1273 fn poll_transmit_off_path(
1275 &mut self,
1276 now: Instant,
1277 buf: &mut Vec<u8>,
1278 path_id: PathId,
1279 ) -> Option<Transmit> {
1280 if let Some(challenge) = self.send_prev_path_challenge(now, buf, path_id) {
1281 return Some(challenge);
1282 }
1283 if let Some(response) = self.send_off_path_path_response(now, buf, path_id) {
1284 return Some(response);
1285 }
1286 if let Some(challenge) = self.send_nat_traversal_path_challenge(now, buf, path_id) {
1287 return Some(challenge);
1288 }
1289 None
1290 }
1291
1292 #[must_use]
1299 fn poll_transmit_on_path(
1300 &mut self,
1301 now: Instant,
1302 buf: &mut Vec<u8>,
1303 path_id: PathId,
1304 max_datagrams: NonZeroUsize,
1305 scheduling_info: &PathSchedulingInfo,
1306 connection_close_pending: bool,
1307 ) -> Option<Transmit> {
1308 let Some(remote_cid) = self.remote_cids.get(&path_id).map(CidQueue::active) else {
1310 if !self.abandoned_paths.contains(&path_id) {
1311 debug!(%path_id, "no remote CIDs for path");
1312 }
1313 return None;
1314 };
1315
1316 let mut pad_datagram = PadDatagram::No;
1322
1323 let mut last_packet_number = None;
1327
1328 let mut send_blocked = false;
1331 let mut cwnd_blocked = false;
1334
1335 let path = self.path_data(path_id);
1336
1337 let controller_metrics = path.congestion.metrics();
1343 let max_datagrams = match controller_metrics.send_quantum {
1344 Some(send_quantum) => {
1345 let datagrams = send_quantum / u64::from(path.current_mtu());
1346 let datagrams = usize::try_from(datagrams).unwrap_or(usize::MAX);
1347 max_datagrams.min(NonZeroUsize::new(datagrams).unwrap_or(NonZeroUsize::MIN))
1348 }
1349 None => max_datagrams,
1350 };
1351
1352 let pmtu = path.current_mtu().into();
1354 let mut transmit = TransmitBuf::new(buf, max_datagrams, pmtu);
1355
1356 for space_id in SpaceId::iter() {
1358 if path_id != PathId::ZERO && space_id != SpaceId::Data {
1360 continue;
1361 }
1362 match self.poll_transmit_path_space(
1363 now,
1364 &mut transmit,
1365 path_id,
1366 space_id,
1367 remote_cid,
1368 scheduling_info,
1369 connection_close_pending,
1370 pad_datagram,
1371 ) {
1372 PollPathSpaceStatus::NothingToSend { path_blocked } => {
1373 match path_blocked {
1376 PathBlocked::No => {}
1377 PathBlocked::AntiAmplification => {
1378 send_blocked = true;
1379 }
1380 PathBlocked::Congestion => {
1381 cwnd_blocked = true;
1382 send_blocked = true;
1383 }
1384 PathBlocked::Pacing => send_blocked = true,
1385 }
1386 }
1387 PollPathSpaceStatus::WrotePacket {
1388 last_packet_number: pn,
1389 pad_datagram: pad,
1390 } => {
1391 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1392 last_packet_number = Some(pn);
1393 pad_datagram = pad;
1394 continue;
1399 }
1400 PollPathSpaceStatus::Send {
1401 last_packet_number: pn,
1402 } => {
1403 debug_assert!(!transmit.is_empty(), "transmit must contain packets");
1404 last_packet_number = Some(pn);
1405 break;
1406 }
1407 }
1408 }
1409
1410 if last_packet_number.is_some() || send_blocked {
1411 self.qlog.emit_recovery_metrics(
1412 path_id,
1413 &mut self
1414 .paths
1415 .get_mut(&path_id)
1416 .expect("path_id was iterated from self.paths above")
1417 .data,
1418 now,
1419 );
1420 }
1421
1422 let path = self.path_data_mut(path_id);
1423
1424 path.app_limited = last_packet_number.is_none() && !send_blocked;
1425
1426 if cwnd_blocked {
1427 path.congestion.on_cwnd_limited();
1428 }
1429
1430 match last_packet_number {
1431 Some(last_packet_number) => {
1432 self.path_data_mut(path_id).congestion.on_sent(
1435 now,
1436 transmit.len() as u64,
1437 last_packet_number,
1438 );
1439 Some(self.build_transmit(path_id, transmit))
1440 }
1441 None => None,
1442 }
1443 }
1444
1445 #[must_use]
1447 fn poll_transmit_path_space(
1448 &mut self,
1449 now: Instant,
1450 transmit: &mut TransmitBuf<'_>,
1451 path_id: PathId,
1452 space_id: SpaceId,
1453 remote_cid: ConnectionId,
1454 scheduling_info: &PathSchedulingInfo,
1455 connection_close_pending: bool,
1457 mut pad_datagram: PadDatagram,
1459 ) -> PollPathSpaceStatus {
1460 let mut last_packet_number = None;
1463
1464 loop {
1480 let max_packet_size = if transmit.datagram_remaining_mut() > 0 {
1482 transmit.datagram_remaining_mut()
1484 } else {
1485 transmit.segment_size()
1487 };
1488 let can_send =
1489 self.space_can_send(space_id, path_id, max_packet_size, connection_close_pending);
1490 let needs_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1491 let space_will_send = {
1492 if scheduling_info.is_abandoned {
1493 scheduling_info.may_self_abandon
1498 && self.spaces[space_id]
1499 .pending
1500 .path_abandon
1501 .contains_key(&path_id)
1502 } else if can_send.close && scheduling_info.may_send_close {
1503 true
1505 } else if needs_loss_probe || can_send.space_specific {
1506 true
1509 } else {
1510 !can_send.is_empty() && scheduling_info.may_send_data
1513 }
1514 };
1515
1516 if !space_will_send {
1517 return match last_packet_number {
1520 Some(pn) => PollPathSpaceStatus::WrotePacket {
1521 last_packet_number: pn,
1522 pad_datagram,
1523 },
1524 None => {
1525 if self.crypto_state.has_keys(space_id.encryption_level())
1527 || (space_id == SpaceId::Data
1528 && self.crypto_state.has_keys(EncryptionLevel::ZeroRtt))
1529 {
1530 trace!(?space_id, %path_id, "nothing to send in space");
1531 }
1532 PollPathSpaceStatus::NothingToSend {
1533 path_blocked: PathBlocked::No,
1534 }
1535 }
1536 };
1537 }
1538
1539 if transmit.datagram_remaining_mut() == 0 {
1543 let path_blocked =
1544 self.path_congestion_check(space_id, path_id, transmit, &can_send, now);
1545 if path_blocked != PathBlocked::No {
1546 return match last_packet_number {
1548 Some(pn) => PollPathSpaceStatus::WrotePacket {
1549 last_packet_number: pn,
1550 pad_datagram,
1551 },
1552 None => PollPathSpaceStatus::NothingToSend { path_blocked },
1553 };
1554 }
1555
1556 if transmit.num_datagrams() >= transmit.max_datagrams().get() {
1559 return match last_packet_number {
1562 Some(pn) => PollPathSpaceStatus::WrotePacket {
1563 last_packet_number: pn,
1564 pad_datagram,
1565 },
1566 None => PollPathSpaceStatus::NothingToSend { path_blocked },
1567 };
1568 }
1569
1570 if needs_loss_probe {
1571 let request_immediate_ack =
1573 space_id == SpaceId::Data && self.peer_supports_ack_frequency();
1574 self.spaces[space_id].queue_tail_loss_probe(
1575 path_id,
1576 request_immediate_ack,
1577 &self.streams,
1578 );
1579
1580 self.spaces[space_id].for_path(path_id).loss_probes -= 1; transmit.start_new_datagram_with_size(cmp::min(
1586 usize::from(INITIAL_MTU),
1587 transmit.segment_size(),
1588 ));
1589 } else {
1590 transmit.start_new_datagram();
1591 }
1592 trace!(count = transmit.num_datagrams(), "new datagram started");
1593
1594 pad_datagram = PadDatagram::No;
1596 }
1597
1598 if transmit.datagram_start_offset() < transmit.len() {
1601 debug_assert!(transmit.datagram_remaining_mut() >= MIN_PACKET_SPACE);
1602 }
1603
1604 if self.crypto_state.has_keys(EncryptionLevel::Initial)
1609 && space_id == SpaceId::Handshake
1610 && self.side.is_client()
1611 {
1612 self.discard_space(now, SpaceKind::Initial);
1615 }
1616 if let Some(ref mut prev) = self.crypto_state.prev_crypto {
1617 prev.update_unacked = false;
1618 }
1619
1620 let Some(mut builder) =
1621 PacketBuilder::new(now, space_id, path_id, remote_cid, transmit, self)
1622 else {
1623 return PollPathSpaceStatus::NothingToSend {
1630 path_blocked: PathBlocked::No,
1631 };
1632 };
1633 last_packet_number = Some(builder.packet_number);
1634
1635 if space_id == SpaceId::Initial
1636 && (self.side.is_client() || can_send.is_ack_eliciting() || needs_loss_probe)
1637 {
1638 pad_datagram |= PadDatagram::ToMinMtu;
1640 }
1641 if space_id == SpaceId::Data && self.config.pad_to_mtu {
1642 pad_datagram |= PadDatagram::ToSegmentSize;
1643 }
1644
1645 if scheduling_info.may_send_close && can_send.close {
1646 trace!("sending CONNECTION_CLOSE");
1647 let is_multipath_negotiated = self.is_multipath_negotiated();
1652 for path_id in self.spaces[space_id]
1653 .number_spaces
1654 .iter()
1655 .filter(|(_, pns)| !pns.pending_acks.ranges().is_empty())
1656 .map(|(&path_id, _)| path_id)
1657 .collect::<Vec<_>>()
1658 {
1659 Self::populate_acks(
1660 now,
1661 self.receiving_ecn,
1662 path_id,
1663 space_id,
1664 &mut self.spaces[space_id],
1665 is_multipath_negotiated,
1666 &mut builder,
1667 &mut self.path_stats.get_mut(path_id).frame_tx,
1668 self.crypto_state.has_keys(space_id.encryption_level()),
1669 );
1670 }
1671
1672 debug_assert!(
1680 builder.frame_space_remaining() > frame::ConnectionClose::SIZE_BOUND,
1681 "ACKs should leave space for ConnectionClose"
1682 );
1683 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
1684 if frame::ConnectionClose::SIZE_BOUND < builder.frame_space_remaining() {
1685 let max_frame_size = builder.frame_space_remaining();
1686 let close: Close = match self.state.as_type() {
1687 StateType::Closed => {
1688 let reason: Close =
1689 self.state.as_closed().expect("checked").clone().into();
1690 if space_id == SpaceId::Data || reason.is_transport_layer() {
1691 reason
1692 } else {
1693 TransportError::APPLICATION_ERROR("").into()
1694 }
1695 }
1696 StateType::Draining => TransportError::NO_ERROR("").into(),
1697 _ => unreachable!(
1698 "tried to make a close packet when the connection wasn't closed"
1699 ),
1700 };
1701 builder.write_frame(close.encoder(max_frame_size), stats);
1702 }
1703 let last_pn = builder.packet_number;
1704 builder.finish_and_track(now, self, path_id, pad_datagram);
1705 if space_id.kind() == self.highest_space {
1706 self.connection_close_pending = false;
1709 }
1710 return PollPathSpaceStatus::WrotePacket {
1723 last_packet_number: last_pn,
1724 pad_datagram,
1725 };
1726 }
1727
1728 self.populate_packet(now, space_id, path_id, scheduling_info, &mut builder);
1729
1730 debug_assert!(
1737 !(builder.sent_frames().is_ack_only(&self.streams)
1738 && !can_send.acks
1739 && (can_send.other || can_send.space_specific)
1740 && builder.buf.segment_size()
1741 == self.path_data(path_id).current_mtu() as usize
1742 && self.datagrams.outgoing.is_empty()),
1743 "SendableFrames was {can_send:?}, but only ACKs have been written"
1744 );
1745 if builder.sent_frames().requires_padding {
1746 pad_datagram |= PadDatagram::ToMinMtu;
1747 }
1748
1749 for path_id in builder.sent_frames().largest_acked.keys() {
1750 self.spaces[space_id]
1751 .for_path(*path_id)
1752 .pending_acks
1753 .acks_sent();
1754 self.timers.stop(
1755 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
1756 self.qlog.with_time(now),
1757 );
1758 }
1759
1760 let max_packet_size = builder
1766 .buf
1767 .datagram_remaining_mut()
1768 .saturating_sub(builder.predict_packet_end());
1769 if builder.can_coalesce
1772 && path_id == PathId::ZERO
1773 && let Some(next_space_id) = space_id.next()
1774 && max_packet_size > MIN_PACKET_SPACE
1775 && self
1776 .space_can_send(space_id, path_id, max_packet_size, connection_close_pending)
1777 .is_empty()
1778 && self.has_pending_packet(next_space_id, max_packet_size, connection_close_pending)
1779 {
1780 trace!("will coalesce with next packet");
1783 let last_pn = builder.packet_number;
1784 builder.finish_and_track(now, self, path_id, PadDatagram::No);
1785 return PollPathSpaceStatus::WrotePacket {
1788 last_packet_number: last_pn,
1789 pad_datagram,
1790 };
1791 } else {
1792 if builder.buf.num_datagrams() > 1 && matches!(pad_datagram, PadDatagram::No) {
1798 const MAX_PADDING: usize = 32;
1806 if builder.buf.datagram_remaining_mut()
1807 > builder.predict_packet_end() + MAX_PADDING
1808 {
1809 trace!(
1810 "GSO truncated by demand for {} padding bytes",
1811 builder.buf.datagram_remaining_mut() - builder.predict_packet_end()
1812 );
1813 let last_pn = builder.packet_number;
1814 builder.finish_and_track(now, self, path_id, PadDatagram::No);
1815 return PollPathSpaceStatus::Send {
1816 last_packet_number: last_pn,
1817 };
1818 }
1819
1820 builder.finish_and_track(now, self, path_id, PadDatagram::ToSegmentSize);
1823 } else {
1824 builder.finish_and_track(now, self, path_id, pad_datagram);
1825 }
1826
1827 if transmit.num_datagrams() == 1 {
1830 transmit.clip_segment_size();
1831 }
1832 }
1833 }
1834 }
1835
1836 fn poll_transmit_mtu_probe(
1837 &mut self,
1838 now: Instant,
1839 buf: &mut Vec<u8>,
1840 path_id: PathId,
1841 ) -> Option<Transmit> {
1842 let (active_cid, probe_size) = self.get_mtu_probe_data(now, path_id)?;
1843
1844 let mut transmit = TransmitBuf::new(buf, NonZeroUsize::MIN, probe_size as usize);
1846 transmit.start_new_datagram_with_size(probe_size as usize);
1847
1848 let mut builder =
1849 PacketBuilder::new(now, SpaceId::Data, path_id, active_cid, &mut transmit, self)?;
1850
1851 trace!(?probe_size, "writing MTUD probe");
1853 builder.write_frame(frame::Ping, &mut self.path_stats.get_mut(path_id).frame_tx);
1854
1855 if self.peer_supports_ack_frequency() {
1857 builder.write_frame(
1858 frame::ImmediateAck,
1859 &mut self.path_stats.get_mut(path_id).frame_tx,
1860 );
1861 }
1862
1863 builder.finish_and_track(now, self, path_id, PadDatagram::ToSize(probe_size));
1864
1865 self.path_stats.get_mut(path_id).sent_plpmtud_probes += 1;
1866
1867 Some(self.build_transmit(path_id, transmit))
1868 }
1869
1870 fn get_mtu_probe_data(&mut self, now: Instant, path_id: PathId) -> Option<(ConnectionId, u16)> {
1878 let active_cid = self.remote_cids.get(&path_id).map(CidQueue::active)?;
1879 let is_eligible = self.path_data(path_id).validated
1880 && !self.path_data(path_id).is_validating_path()
1881 && !self.abandoned_paths.contains(&path_id);
1882
1883 if !is_eligible {
1884 return None;
1885 }
1886 let next_pn = self.spaces[SpaceId::Data]
1887 .for_path(path_id)
1888 .peek_tx_number();
1889 let probe_size = self
1890 .path_data_mut(path_id)
1891 .mtud
1892 .poll_transmit(now, next_pn)?;
1893
1894 Some((active_cid, probe_size))
1895 }
1896
1897 fn has_pending_packet(
1914 &mut self,
1915 current_space_id: SpaceId,
1916 max_packet_size: usize,
1917 connection_close_pending: bool,
1918 ) -> bool {
1919 let mut space_id = current_space_id;
1920 loop {
1921 let can_send = self.space_can_send(
1922 space_id,
1923 PathId::ZERO,
1924 max_packet_size,
1925 connection_close_pending,
1926 );
1927 if !can_send.is_empty() {
1928 return true;
1929 }
1930 match space_id.next() {
1931 Some(next_space_id) => space_id = next_space_id,
1932 None => break,
1933 }
1934 }
1935 false
1936 }
1937
1938 fn path_congestion_check(
1940 &mut self,
1941 space_id: SpaceId,
1942 path_id: PathId,
1943 transmit: &TransmitBuf<'_>,
1944 can_send: &SendableFrames,
1945 now: Instant,
1946 ) -> PathBlocked {
1947 if self.side().is_server()
1953 && self
1954 .path_data(path_id)
1955 .anti_amplification_blocked(transmit.len() as u64 + 1)
1956 {
1957 trace!(?space_id, %path_id, "blocked by anti-amplification");
1958 return PathBlocked::AntiAmplification;
1959 }
1960
1961 let bytes_to_send = transmit.segment_size() as u64;
1964 let need_loss_probe = self.spaces[space_id].for_path(path_id).loss_probes > 0;
1965
1966 if can_send.other && !need_loss_probe && !can_send.close {
1967 let path = self.path_data(path_id);
1968 if path.in_flight.bytes + bytes_to_send >= path.congestion.window() {
1969 trace!(
1970 ?space_id,
1971 %path_id,
1972 in_flight=%path.in_flight.bytes,
1973 congestion_window=%path.congestion.window(),
1974 "blocked by congestion control",
1975 );
1976 return PathBlocked::Congestion;
1977 }
1978 }
1979
1980 if let Some(delay) = self.path_data_mut(path_id).pacing_delay(bytes_to_send, now) {
1982 let resume_time = now + delay;
1983 self.timers.set(
1984 Timer::PerPath(path_id, PathTimer::Pacing),
1985 resume_time,
1986 self.qlog.with_time(now),
1987 );
1988 trace!(?space_id, %path_id, ?delay, "blocked by pacing");
1991 return PathBlocked::Pacing;
1992 }
1993
1994 PathBlocked::No
1995 }
1996
1997 fn send_prev_path_challenge(
2002 &mut self,
2003 now: Instant,
2004 buf: &mut Vec<u8>,
2005 path_id: PathId,
2006 ) -> Option<Transmit> {
2007 let (prev_cid, prev_path) = self.paths.get_mut(&path_id)?.prev.as_mut()?;
2008 if !prev_path.pending_challenge {
2009 return None;
2010 };
2011 prev_path.pending_challenge = false;
2012 let token = self.rng.random();
2013 let network_path = prev_path.network_path;
2014 prev_path.record_path_challenge_sent(now, token, network_path);
2015
2016 debug_assert_eq!(
2017 self.highest_space,
2018 SpaceKind::Data,
2019 "PATH_CHALLENGE queued without 1-RTT keys"
2020 );
2021 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2022 buf.start_new_datagram();
2023
2024 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, *prev_cid, buf, self)?;
2030 let challenge = frame::PathChallenge(token);
2031 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2032 builder.write_frame_with_log_msg(challenge, stats, Some("validating previous path"));
2033
2034 builder.pad_to(MIN_INITIAL_SIZE);
2039
2040 builder.finish(self, now);
2041 self.path_stats
2042 .get_mut(path_id)
2043 .udp_tx
2044 .on_sent(1, buf.len());
2045
2046 trace!(
2047 dst = ?network_path.remote,
2048 src = ?network_path.local_ip,
2049 len = buf.len(),
2050 "sending prev_path off-path challenge",
2051 );
2052 Some(Transmit {
2053 destination: network_path.remote,
2054 size: buf.len(),
2055 ecn: None,
2056 segment_size: None,
2057 src_ip: network_path.local_ip,
2058 })
2059 }
2060
2061 fn send_off_path_path_response(
2062 &mut self,
2063 now: Instant,
2064 buf: &mut Vec<u8>,
2065 path_id: PathId,
2066 ) -> Option<Transmit> {
2067 let network_path = self
2068 .paths
2069 .get_mut(&path_id)
2070 .map(|state| state.data.network_path)?;
2071 let cid_queue = self.remote_cids.get_mut(&path_id)?;
2072 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
2073 let (token, network_path) = pns.pending_path_responses.pop_off_path(network_path)?;
2074
2075 let cid = cid_queue.active();
2077
2078 let frame = frame::PathResponse(token);
2080
2081 let buf = &mut TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2082 buf.start_new_datagram();
2083
2084 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, buf, self)?;
2085 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2086 builder.write_frame_with_log_msg(frame, stats, Some("(off-path)"));
2087
2088 if self
2095 .find_validated_path_on_network_path(network_path)
2096 .is_none()
2097 && self.n0_nat_traversal.client_side().is_ok()
2098 {
2099 let token = self.rng.random();
2100 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2101 builder.write_frame(frame::PathChallenge(token), stats);
2102 let ip_port = (network_path.remote.ip(), network_path.remote.port());
2103 self.n0_nat_traversal.mark_probe_sent(ip_port, token);
2104 }
2105
2106 builder.pad_to(MIN_INITIAL_SIZE);
2109 builder.finish(self, now);
2110
2111 let size = buf.len();
2112 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2113
2114 trace!(
2115 dst = ?network_path.remote,
2116 src = ?network_path.local_ip,
2117 len = buf.len(),
2118 "sending off-path PATH_RESPONSE",
2119 );
2120 Some(Transmit {
2121 destination: network_path.remote,
2122 size,
2123 ecn: None,
2124 segment_size: None,
2125 src_ip: network_path.local_ip,
2126 })
2127 }
2128
2129 fn send_nat_traversal_path_challenge(
2131 &mut self,
2132 now: Instant,
2133 buf: &mut Vec<u8>,
2134 path_id: PathId,
2135 ) -> Option<Transmit> {
2136 let remote = self.n0_nat_traversal.next_probe_addr()?;
2137
2138 if !self.paths.get(&path_id)?.data.validated {
2139 return None;
2141 }
2142
2143 let Some(cid) = self
2148 .remote_cids
2149 .get(&path_id)
2150 .map(|cid_queue| cid_queue.active())
2151 else {
2152 trace!(%path_id, "Not sending NAT traversal probe for path with no CIDs");
2153 return None;
2154 };
2155 let token = self.rng.random();
2156
2157 let frame = frame::PathChallenge(token);
2159
2160 let mut buf = TransmitBuf::new(buf, NonZeroUsize::MIN, MIN_INITIAL_SIZE.into());
2161 buf.start_new_datagram();
2162
2163 let mut builder = PacketBuilder::new(now, SpaceId::Data, path_id, cid, &mut buf, self)?;
2164 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
2165 builder.write_frame_with_log_msg(frame, stats, Some("(nat-traversal)"));
2166 builder.finish(self, now);
2169
2170 self.n0_nat_traversal.mark_probe_sent(remote, token);
2172
2173 let size = buf.len();
2174 self.path_stats.get_mut(path_id).udp_tx.on_sent(1, size);
2175
2176 trace!(dst = ?remote, len = buf.len(), "sending off-path NAT probe");
2177 Some(Transmit {
2178 destination: remote.into(),
2179 size,
2180 ecn: None,
2181 segment_size: None,
2182 src_ip: None,
2183 })
2184 }
2185
2186 fn space_can_send(
2194 &mut self,
2195 space_id: SpaceId,
2196 path_id: PathId,
2197 packet_size: usize,
2198 connection_close_pending: bool,
2199 ) -> SendableFrames {
2200 let space = &mut self.spaces[space_id];
2201 let space_has_crypto = self.crypto_state.has_keys(space_id.encryption_level());
2202
2203 if !space_has_crypto
2204 && (space_id != SpaceId::Data
2205 || !self.crypto_state.has_keys(EncryptionLevel::ZeroRtt)
2206 || self.side.is_server())
2207 {
2208 return SendableFrames::empty();
2210 }
2211
2212 let mut can_send = space.can_send(path_id, &self.streams);
2213
2214 if space_id == SpaceId::Data {
2216 let pn = space.for_path(path_id).peek_tx_number();
2217 let frame_space_1rtt =
2223 packet_size.saturating_sub(self.predict_1rtt_overhead(pn, path_id));
2224 can_send |= self.can_send_1rtt(path_id, frame_space_1rtt);
2225 }
2226
2227 can_send.close = connection_close_pending && space_has_crypto;
2228
2229 can_send
2230 }
2231
2232 pub fn handle_event(&mut self, event: ConnectionEvent) {
2238 use ConnectionEventInner::*;
2239 match event.0 {
2240 Datagram(DatagramConnectionEvent {
2241 now,
2242 network_path,
2243 path_id,
2244 ecn,
2245 first_decode,
2246 remaining,
2247 }) => {
2248 let span = trace_span!("pkt", %path_id);
2249 let _guard = span.enter();
2250
2251 if self.early_discard_packet(network_path, path_id) {
2252 return;
2254 }
2255
2256 let was_anti_amplification_blocked = self
2257 .path(path_id)
2258 .map(|path| path.anti_amplification_blocked(1))
2259 .unwrap_or(false);
2262
2263 let rx = &mut self.path_stats.get_mut(path_id).udp_rx;
2264 rx.datagrams += 1;
2265 rx.bytes += first_decode.len() as u64;
2266 let data_len = first_decode.len();
2267
2268 self.handle_decode(now, network_path, path_id, ecn, first_decode);
2269 if let Some(path) = self.path_mut(path_id) {
2274 path.inc_total_recvd(data_len as u64);
2275 }
2276
2277 if let Some(data) = remaining {
2278 self.path_stats.get_mut(path_id).udp_rx.bytes += data.len() as u64;
2279 self.handle_coalesced(now, network_path, path_id, ecn, data);
2280 }
2281
2282 if let Some(path) = self.paths.get_mut(&path_id) {
2283 self.qlog
2284 .emit_recovery_metrics(path_id, &mut path.data, now);
2285 }
2286
2287 if was_anti_amplification_blocked {
2288 self.set_loss_detection_timer(now, path_id);
2292 }
2293 }
2294 NewIdentifiers(ids, now, cid_len, cid_lifetime) => {
2295 let path_id = ids.first().map(|issued| issued.path_id).unwrap_or_default();
2296 debug_assert!(ids.iter().all(|issued| issued.path_id == path_id));
2297
2298 if self.abandoned_paths.contains(&path_id) {
2301 if !self.state.is_drained() {
2302 for issued in &ids {
2303 self.endpoint_events
2304 .push_back(EndpointEventInner::RetireConnectionId(
2305 now,
2306 path_id,
2307 issued.sequence,
2308 false,
2309 ));
2310 }
2311 }
2312 return;
2313 }
2314
2315 let cid_state = self
2316 .local_cid_state
2317 .entry(path_id)
2318 .or_insert_with(|| CidState::new(cid_len, cid_lifetime, now, 0));
2319 cid_state.new_cids(&ids, now);
2320
2321 ids.into_iter().rev().for_each(|frame| {
2322 self.spaces[SpaceId::Data].pending.new_cids.push(frame);
2323 });
2324 self.reset_cid_retirement(now);
2326 }
2327 }
2328 }
2329
2330 fn early_discard_packet(&mut self, network_path: FourTuple, path_id: PathId) -> bool {
2338 if self.is_handshaking() && path_id != PathId::ZERO {
2339 debug!(%network_path, %path_id, "discarding multipath packet during handshake");
2340 return true;
2341 }
2342
2343 if !self.paths.contains_key(&path_id) && self.abandoned_paths.contains(&path_id) {
2344 trace!(%path_id, "discarding packet for discarded path");
2345 return true;
2346 }
2347
2348 let peer_may_probe = self.peer_may_probe();
2349 let local_ip_may_migrate = self.local_ip_may_migrate();
2350
2351 if let Some(known_path) = self.path_mut(path_id) {
2355 if network_path.remote != known_path.network_path.remote && !peer_may_probe {
2356 trace!(
2357 %path_id,
2358 %network_path,
2359 %known_path.network_path,
2360 "discarding packet from unrecognized peer"
2361 );
2362 return true;
2363 }
2364
2365 if known_path.network_path.local_ip.is_some()
2366 && network_path.local_ip.is_some()
2367 && known_path.network_path.local_ip != network_path.local_ip
2368 && !local_ip_may_migrate
2369 {
2370 trace!(
2371 %path_id,
2372 %network_path,
2373 %known_path.network_path,
2374 "discarding packet sent to incorrect interface"
2375 );
2376 return true;
2377 }
2378 }
2379 false
2380 }
2381
2382 fn peer_may_probe(&self) -> bool {
2393 match &self.side {
2394 ConnectionSide::Client { .. } => {
2395 if let Some(hs) = self.state.as_handshake() {
2396 hs.allow_server_migration
2397 } else {
2398 self.n0_nat_traversal.is_negotiated() && self.is_handshake_confirmed()
2399 }
2400 }
2401 ConnectionSide::Server { server_config } => {
2402 self.is_handshake_confirmed()
2403 && (server_config.migration || self.n0_nat_traversal.is_negotiated())
2404 }
2405 }
2406 }
2407
2408 fn peer_may_migrate(&self) -> bool {
2420 match &self.side {
2421 ConnectionSide::Server { server_config } => {
2422 server_config.migration && self.is_handshake_confirmed()
2423 }
2424 ConnectionSide::Client { .. } => false,
2425 }
2426 }
2427
2428 fn local_ip_may_migrate(&self) -> bool {
2441 (self.side.is_client() || self.n0_nat_traversal.is_negotiated())
2442 && self.is_handshake_confirmed()
2443 }
2444 pub fn handle_timeout(&mut self, now: Instant) {
2454 while let Some((timer, _time)) = self.timers.expire_before(now, &self.qlog) {
2455 let span = match timer {
2456 Timer::Conn(timer) => trace_span!("timeout", scope = "conn", ?timer),
2457 Timer::PerPath(path_id, timer) => {
2458 trace_span!("timer_fired", scope="path", %path_id, ?timer)
2459 }
2460 };
2461 let _guard = span.enter();
2462 trace!("timeout");
2463 match timer {
2464 Timer::Conn(timer) => match timer {
2465 ConnTimer::Close => {
2466 self.state.move_to_drained(None, &mut self.endpoint_events);
2467 }
2468 ConnTimer::Idle => {
2469 self.kill(ConnectionError::TimedOut);
2470 }
2471 ConnTimer::KeepAlive => {
2472 self.ping();
2473 }
2474 ConnTimer::KeyDiscard => {
2475 self.crypto_state.discard_temporary_keys();
2476 }
2477 ConnTimer::PushNewCid => {
2478 while let Some((path_id, when)) = self.next_cid_retirement() {
2479 if when > now {
2480 break;
2481 }
2482 match self.local_cid_state.get_mut(&path_id) {
2483 None => error!(%path_id, "No local CID state for path"),
2484 Some(cid_state) => {
2485 let num_new_cid = cid_state.on_cid_timeout().into();
2487 if !self.state.is_closed() {
2488 trace!(
2489 "push a new CID to peer RETIRE_PRIOR_TO field {}",
2490 cid_state.retire_prior_to()
2491 );
2492 self.endpoint_events.push_back(
2493 EndpointEventInner::NeedIdentifiers(
2494 path_id,
2495 now,
2496 num_new_cid,
2497 ),
2498 );
2499 }
2500 }
2501 }
2502 }
2503 }
2504 ConnTimer::NoAvailablePath => {
2505 if self.state.is_closed() || self.state.is_drained() {
2510 error!("no viable path timer fired, but connection already closing");
2513 } else {
2514 trace!("no viable path grace period expired, closing connection");
2515 let err = TransportError::NO_VIABLE_PATH(
2516 "last path abandoned, no new path opened",
2517 );
2518 self.close_common();
2519 self.set_close_timer(now);
2520 self.connection_close_pending = true;
2521 self.state.move_to_closed(err);
2522 }
2523 }
2524 ConnTimer::NatTraversalProbeRetry => {
2525 self.n0_nat_traversal.queue_retries(self.is_ipv6());
2526 if let Some(delay) =
2527 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
2528 {
2529 self.timers.set(
2530 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
2531 now + delay,
2532 self.qlog.with_time(now),
2533 );
2534 trace!("re-queued NAT probes");
2535 } else {
2536 trace!("no more NAT probes remaining");
2537 }
2538 }
2539 },
2540 Timer::PerPath(path_id, timer) => {
2541 match timer {
2542 PathTimer::PathIdle => {
2543 if let Err(err) =
2544 self.close_path_inner(now, path_id, PathAbandonReason::TimedOut)
2545 {
2546 warn!(?err, "failed closing path");
2547 }
2548 }
2549
2550 PathTimer::PathKeepAlive => {
2551 self.ping_path(path_id).ok();
2552 }
2553 PathTimer::LossDetection => {
2554 self.on_loss_detection_timeout(now, path_id);
2555 if let Some(path) = self.paths.get_mut(&path_id) {
2556 self.qlog
2557 .emit_recovery_metrics(path_id, &mut path.data, now);
2558 } else {
2559 error!("LossDetection fired for unknown path");
2560 }
2561 }
2562 PathTimer::PathValidationFailed => {
2563 let Some(path) = self.paths.get_mut(&path_id) else {
2564 continue;
2565 };
2566 self.timers.stop(
2567 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2568 self.qlog.with_time(now),
2569 );
2570 debug!("path migration validation failed");
2571 path.data.reset_on_path_challenges();
2572 if let Some((_, prev)) = path.prev.take() {
2573 path.data = prev;
2574 self.set_loss_detection_timer(now, path_id);
2575 }
2576 }
2577 PathTimer::PathChallengeLost => {
2578 let Some(path) = self.paths.get_mut(&path_id) else {
2579 continue;
2580 };
2581 trace!(?path.data.lost_challenge_count, "path challenge deemed lost");
2582 path.data.pending_challenge = true;
2583 path.data.lost_challenge_count += 1;
2584 self.timers.set(
2585 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
2586 now + path.data.on_path_challenge_pto(),
2587 self.qlog.with_time(now),
2588 );
2589 }
2590 PathTimer::Pacing => {}
2591 PathTimer::MaxAckDelay => {
2592 self.spaces[SpaceId::Data]
2594 .for_path(path_id)
2595 .pending_acks
2596 .on_max_ack_delay_timeout()
2597 }
2598 PathTimer::PathDrained => {
2599 self.timers.stop_per_path(path_id, self.qlog.with_time(now));
2602 if let Some(local_cid_state) = self.local_cid_state.remove(&path_id) {
2603 debug_assert!(!self.state.is_drained()); let (min_seq, max_seq) = local_cid_state.active_seq();
2605 for seq in min_seq..=max_seq {
2606 self.endpoint_events.push_back(
2607 EndpointEventInner::RetireConnectionId(
2608 now, path_id, seq, false,
2609 ),
2610 );
2611 }
2612 }
2613 self.discard_path(path_id, now);
2614 }
2615 }
2616 }
2617 }
2618 }
2619 }
2620
2621 pub fn close(&mut self, now: Instant, error_code: VarInt, reason: Bytes) {
2633 self.close_inner(
2634 now,
2635 Close::Application(frame::ApplicationClose { error_code, reason }),
2636 )
2637 }
2638
2639 fn close_inner(&mut self, now: Instant, reason: Close) {
2655 let was_closed = self.state.is_closed();
2656 if !was_closed {
2657 self.close_common();
2658 self.set_close_timer(now);
2659 self.connection_close_pending = true;
2660 self.state.move_to_closed_local(reason);
2661 }
2662 }
2663
2664 pub fn datagrams(&mut self) -> Datagrams<'_> {
2666 Datagrams { conn: self }
2667 }
2668
2669 pub fn stats(&mut self) -> ConnectionStats {
2671 let mut stats = self.partial_stats.clone();
2672
2673 for path_stats in self.path_stats.iter_stats() {
2674 stats += *path_stats;
2679 }
2680
2681 stats
2682 }
2683
2684 pub fn path_stats(&mut self, path_id: PathId) -> Option<PathStats> {
2686 let path = self.paths.get(&path_id)?;
2687 let mut stats = self.path_stats.get(path_id).unwrap_or_default();
2688 stats.rtt = path.data.rtt.get();
2689 stats.cwnd = path.data.congestion.window();
2690 stats.current_mtu = path.data.mtud.current_mtu();
2691 Some(stats)
2692 }
2693
2694 pub fn ping(&mut self) {
2698 for path_data in self.spaces[self.highest_space].number_spaces.values_mut() {
2701 path_data.pending_ping = true;
2702 }
2703 }
2704
2705 pub fn ping_path(&mut self, path: PathId) -> Result<(), ClosedPath> {
2709 let path_data = self.spaces[self.highest_space]
2710 .number_spaces
2711 .get_mut(&path)
2712 .ok_or(ClosedPath { _private: () })?;
2713 path_data.pending_ping = true;
2714 Ok(())
2715 }
2716
2717 pub fn force_key_update(&mut self) {
2721 if !self.state.is_established() {
2722 debug!("ignoring forced key update in illegal state");
2723 return;
2724 }
2725 if self.crypto_state.prev_crypto.is_some() {
2726 debug!("ignoring redundant forced key update");
2729 return;
2730 }
2731 self.crypto_state.update_keys(None, false);
2732 }
2733
2734 pub fn crypto_session(&self) -> &dyn crypto::Session {
2736 self.crypto_state.session.as_ref()
2737 }
2738
2739 pub fn is_handshaking(&self) -> bool {
2749 self.state.is_handshake()
2750 }
2751
2752 pub fn is_closed(&self) -> bool {
2763 self.state.is_closed()
2764 }
2765
2766 pub fn is_drained(&self) -> bool {
2771 self.state.is_drained()
2772 }
2773
2774 pub fn accepted_0rtt(&self) -> bool {
2778 self.crypto_state.accepted_0rtt
2779 }
2780
2781 pub fn has_0rtt(&self) -> bool {
2783 self.crypto_state.zero_rtt_enabled
2784 }
2785
2786 pub fn has_pending_retransmits(&self) -> bool {
2788 !self.spaces[SpaceId::Data].pending.is_empty(&self.streams)
2789 }
2790
2791 pub fn side(&self) -> Side {
2793 self.side.side()
2794 }
2795
2796 pub fn path_observed_address(&self, path_id: PathId) -> Result<Option<SocketAddr>, ClosedPath> {
2798 self.path(path_id)
2799 .map(|path_data| {
2800 path_data
2801 .last_observed_addr_report
2802 .as_ref()
2803 .map(|observed| observed.socket_addr())
2804 })
2805 .ok_or(ClosedPath { _private: () })
2806 }
2807
2808 pub fn rtt(&self, path_id: PathId) -> Option<Duration> {
2810 self.path(path_id).map(|d| d.rtt.get())
2811 }
2812
2813 pub fn congestion_state(&self, path_id: PathId) -> Option<&dyn Controller> {
2815 self.path(path_id).map(|d| d.congestion.as_ref())
2816 }
2817
2818 pub fn set_max_concurrent_streams(&mut self, dir: Dir, count: VarInt) {
2823 self.streams.set_max_concurrent(dir, count);
2824 let pending = &mut self.spaces[SpaceId::Data].pending;
2827 self.streams.queue_max_stream_id(pending);
2828 }
2829
2830 pub fn set_max_concurrent_paths(
2840 &mut self,
2841 now: Instant,
2842 count: NonZeroU32,
2843 ) -> Result<(), MultipathNotNegotiated> {
2844 if !self.is_multipath_negotiated() {
2845 return Err(MultipathNotNegotiated { _private: () });
2846 }
2847 self.max_concurrent_paths = count;
2848
2849 let in_use_count = self
2850 .local_max_path_id
2851 .next()
2852 .saturating_sub(self.abandoned_paths.len())
2853 .as_u32();
2854 let extra_needed = count.get().saturating_sub(in_use_count);
2855 let new_max_path_id = self.local_max_path_id.saturating_add(extra_needed);
2856
2857 self.set_max_path_id(now, new_max_path_id);
2858
2859 Ok(())
2860 }
2861
2862 fn set_max_path_id(&mut self, now: Instant, max_path_id: PathId) {
2864 if max_path_id <= self.local_max_path_id {
2865 return;
2866 }
2867
2868 self.local_max_path_id = max_path_id;
2869 self.spaces[SpaceId::Data].pending.max_path_id = true;
2870
2871 self.issue_first_path_cids(now);
2872 }
2873
2874 pub fn max_concurrent_streams(&self, dir: Dir) -> u64 {
2881 self.streams.max_concurrent(dir)
2882 }
2883
2884 pub fn set_send_window(&mut self, send_window: u64) {
2886 self.streams.set_send_window(send_window);
2887 }
2888
2889 pub fn set_receive_window(&mut self, receive_window: VarInt) {
2891 if self.streams.set_receive_window(receive_window) {
2892 self.spaces[SpaceId::Data].pending.max_data = true;
2893 }
2894 }
2895
2896 pub fn is_multipath_negotiated(&self) -> bool {
2901 !self.is_handshaking()
2902 && self.config.max_concurrent_multipath_paths.is_some()
2903 && self.peer_params.initial_max_path_id.is_some()
2904 }
2905
2906 fn on_ack_received(
2907 &mut self,
2908 now: Instant,
2909 space: SpaceId,
2910 ack: frame::Ack,
2911 ) -> Result<(), TransportError> {
2912 let path = PathId::ZERO;
2914 self.inner_on_ack_received(now, space, path, ack)
2915 }
2916
2917 fn on_path_ack_received(
2918 &mut self,
2919 now: Instant,
2920 space: SpaceId,
2921 path_ack: frame::PathAck,
2922 ) -> Result<(), TransportError> {
2923 let (ack, path) = path_ack.into_ack();
2924 self.inner_on_ack_received(now, space, path, ack)
2925 }
2926
2927 fn inner_on_ack_received(
2929 &mut self,
2930 now: Instant,
2931 space: SpaceId,
2932 path: PathId,
2933 ack: frame::Ack,
2934 ) -> Result<(), TransportError> {
2935 if !self.spaces[space].number_spaces.contains_key(&path) {
2936 if self.abandoned_paths.contains(&path) {
2937 trace!("silently ignoring PATH_ACK on discarded path");
2943 return Ok(());
2944 } else {
2945 return Err(TransportError::PROTOCOL_VIOLATION(
2946 "received PATH_ACK with path ID never used",
2947 ));
2948 }
2949 }
2950 if ack.largest >= self.spaces[space].for_path(path).next_packet_number {
2951 return Err(TransportError::PROTOCOL_VIOLATION("unsent packet acked"));
2952 }
2953 let new_largest_pn = {
2955 let space = &mut self.spaces[space].for_path(path);
2956 if space
2957 .largest_acked_packet_pn
2958 .is_none_or(|pn| ack.largest > pn)
2959 {
2960 space.largest_acked_packet_pn = Some(ack.largest);
2961 if let Some(info) = space.sent_packets.get(ack.largest) {
2962 space.largest_acked_packet_send_time = info.time_sent;
2966 }
2967 Some(ack.largest)
2968 } else {
2969 None
2970 }
2971 };
2972
2973 if self.detect_spurious_loss(&ack, space, path) {
2974 self.path_stats.get_mut(path).spurious_congestion_events += 1;
2975 self.path_data_mut(path)
2976 .congestion
2977 .on_spurious_congestion_event();
2978 }
2979
2980 let mut newly_acked: ArrayRangeSet = ArrayRangeSet::new();
2982 for range in ack.iter() {
2983 self.spaces[space].for_path(path).check_ack(range.clone())?;
2984 for (pn, _) in self.spaces[space]
2985 .for_path(path)
2986 .sent_packets
2987 .iter_range(range)
2988 {
2989 newly_acked.insert_one(pn);
2990 }
2991 }
2992
2993 if newly_acked.is_empty() {
2994 return Ok(());
2995 }
2996
2997 let mut ack_eliciting_acked = false;
2998 for packet in newly_acked.elts() {
2999 if let Some(info) = self.spaces[space].for_path(path).take(packet) {
3000 for (acked_path_id, acked_pn) in info.largest_acked.iter() {
3001 if let Some(pns) = self.spaces[space].path_space_mut(*acked_path_id) {
3007 pns.pending_acks.subtract_below(*acked_pn);
3008 }
3009 }
3010 ack_eliciting_acked |= info.ack_eliciting;
3011
3012 let path_data = self.path_data_mut(path);
3014 let mtu_updated = path_data.mtud.on_acked(space.kind(), packet, info.size);
3015 if mtu_updated {
3016 path_data
3017 .congestion
3018 .on_mtu_update(path_data.mtud.current_mtu());
3019 }
3020
3021 self.ack_frequency.on_acked(path, packet);
3024
3025 self.on_packet_acked(now, path, packet, info);
3026 }
3027 }
3028
3029 let largest_ackd = self.spaces[space].for_path(path).largest_acked_packet_pn;
3030 let path_data = self.path_data_mut(path);
3031 let app_limited = path_data.app_limited;
3032 let in_flight = path_data.in_flight.bytes;
3033
3034 path_data
3035 .congestion
3036 .on_end_acks(now, in_flight, app_limited, largest_ackd);
3037
3038 if new_largest_pn.is_some() && ack_eliciting_acked {
3039 let ack_delay = if space != SpaceId::Data {
3040 Duration::from_micros(0)
3041 } else {
3042 cmp::min(
3043 self.ack_frequency.peer_max_ack_delay,
3044 Duration::from_micros(ack.delay << self.peer_params.ack_delay_exponent.0),
3045 )
3046 };
3047 let rtt = now.saturating_duration_since(
3048 self.spaces[space]
3049 .for_path(path)
3050 .largest_acked_packet_send_time,
3051 );
3052
3053 let next_pn = self.spaces[space].for_path(path).next_packet_number;
3054 let path_data = self.path_data_mut(path);
3055 path_data.rtt.update(ack_delay, rtt);
3057 if path_data.first_packet_after_rtt_sample.is_none() {
3058 path_data.first_packet_after_rtt_sample = Some((space.kind(), next_pn));
3059 }
3060 }
3061
3062 self.detect_lost_packets(now, space, path, true);
3064
3065 if self.peer_completed_handshake_address_validation() {
3070 self.path_data_mut(path).pto_count = 0;
3071 }
3072
3073 if self.path_data(path).sending_ecn {
3078 if let Some(ecn) = ack.ecn {
3079 if let Some(largest_sent_pn) = new_largest_pn {
3084 let sent = self.spaces[space]
3085 .for_path(path)
3086 .largest_acked_packet_send_time;
3087 self.process_ecn(
3088 now,
3089 space,
3090 path,
3091 newly_acked.range_count() as u64,
3092 ecn,
3093 sent,
3094 largest_sent_pn,
3095 );
3096 }
3097 } else {
3098 debug!("ECN not acknowledged by peer");
3101 self.path_data_mut(path).sending_ecn = false;
3102 }
3103 }
3104
3105 self.set_loss_detection_timer(now, path);
3106 Ok(())
3107 }
3108
3109 fn detect_spurious_loss(&mut self, ack: &frame::Ack, space: SpaceId, path: PathId) -> bool {
3110 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3111
3112 if lost_packets.is_empty() {
3113 return false;
3114 }
3115
3116 for range in ack.iter() {
3117 let spurious_losses: Vec<u64> = lost_packets
3118 .iter_range(range.clone())
3119 .map(|(pn, _info)| pn)
3120 .collect();
3121
3122 for pn in spurious_losses {
3123 lost_packets.remove(pn);
3124 }
3125 }
3126
3127 lost_packets.is_empty()
3132 }
3133
3134 fn drain_lost_packets(&mut self, now: Instant, space: SpaceId, path: PathId) {
3139 let two_pto = 2 * self.path_data(path).rtt.pto_base();
3140
3141 let lost_packets = &mut self.spaces[space].for_path(path).lost_packets;
3142 lost_packets.retain(|_pn, info| now.saturating_duration_since(info.time_sent) <= two_pto);
3143 }
3144
3145 fn process_ecn(
3147 &mut self,
3148 now: Instant,
3149 space: SpaceId,
3150 path: PathId,
3151 newly_acked_pn: u64,
3152 ecn: frame::EcnCounts,
3153 largest_sent_time: Instant,
3154 largest_sent_pn: u64,
3155 ) {
3156 match self.spaces[space]
3157 .for_path(path)
3158 .detect_ecn(newly_acked_pn, ecn)
3159 {
3160 Err(e) => {
3161 debug!("halting ECN due to verification failure: {}", e);
3162
3163 self.path_data_mut(path).sending_ecn = false;
3164 self.spaces[space].for_path(path).ecn_feedback = frame::EcnCounts::ZERO;
3167 }
3168 Ok(false) => {}
3169 Ok(true) => {
3170 self.path_stats.get_mut(path).congestion_events += 1;
3171 self.path_data_mut(path).congestion.on_congestion_event(
3172 now,
3173 largest_sent_time,
3174 false,
3175 true,
3176 0,
3177 largest_sent_pn,
3178 );
3179 }
3180 }
3181 }
3182
3183 fn on_packet_acked(&mut self, now: Instant, path_id: PathId, pn: u64, info: SentPacket) {
3186 let path = self.path_data_mut(path_id);
3187 let app_limited = path.app_limited;
3188 path.remove_in_flight(&info);
3189 if info.ack_eliciting && info.path_generation == path.generation() {
3190 let rtt = path.rtt;
3194 path.congestion
3195 .on_ack(now, info.time_sent, info.size.into(), pn, app_limited, &rtt);
3196 }
3197
3198 if let Some(retransmits) = info.retransmits.get() {
3200 for (id, _) in retransmits.reset_stream.iter() {
3201 self.streams.reset_acked(*id);
3202 }
3203 }
3204
3205 for frame in info.stream_frames {
3206 self.streams.received_ack_of(frame);
3207 }
3208 }
3209
3210 fn set_key_discard_timer(&mut self, now: Instant, space: SpaceKind) {
3211 let start = if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) {
3212 now
3213 } else {
3214 self.crypto_state
3215 .prev_crypto
3216 .as_ref()
3217 .expect("no previous keys")
3218 .end_packet
3219 .as_ref()
3220 .expect("update not acknowledged yet")
3221 .1
3222 };
3223
3224 self.timers.set(
3226 Timer::Conn(ConnTimer::KeyDiscard),
3227 start + self.max_pto_for_space(space) * 3,
3228 self.qlog.with_time(now),
3229 );
3230 }
3231
3232 fn on_loss_detection_timeout(&mut self, now: Instant, path_id: PathId) {
3245 if let Some((_, pn_space)) = self.loss_time_and_space(path_id) {
3246 self.detect_lost_packets(now, pn_space, path_id, false);
3248 self.set_loss_detection_timer(now, path_id);
3249 return;
3250 }
3251
3252 let Some((_, space)) = self.pto_time_and_space(now, path_id) else {
3253 debug!(%path_id, "PTO expired while unset");
3254 return;
3255 };
3256 trace!(
3257 in_flight = self.path_data(path_id).in_flight.bytes,
3258 count = self.path_data(path_id).pto_count,
3259 ?space,
3260 %path_id,
3261 "PTO fired"
3262 );
3263
3264 let count = match self.path_data(path_id).in_flight.ack_eliciting {
3265 0 => {
3268 debug_assert!(!self.peer_completed_handshake_address_validation());
3269 1
3270 }
3271 _ => 2,
3273 };
3274 let pns = self.spaces[space].for_path(path_id);
3275 pns.loss_probes = pns.loss_probes.saturating_add(count);
3276 let path_data = self.path_data_mut(path_id);
3277 path_data.pto_count = path_data.pto_count.saturating_add(1);
3278 self.set_loss_detection_timer(now, path_id);
3279 }
3280
3281 fn detect_lost_packets(
3298 &mut self,
3299 now: Instant,
3300 pn_space: SpaceId,
3301 path_id: PathId,
3302 due_to_ack: bool,
3303 ) {
3304 let mut lost_packets = Vec::<u64>::new();
3305 let mut lost_mtu_probe = None;
3306 let mut in_persistent_congestion = false;
3307 let mut size_of_lost_packets = 0u64;
3308 self.spaces[pn_space].for_path(path_id).loss_time = None;
3309
3310 let path = self.path_data(path_id);
3313 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3314 let loss_delay = path
3315 .rtt
3316 .conservative()
3317 .mul_f32(self.config.time_threshold)
3318 .max(TIMER_GRANULARITY);
3319 let first_packet_after_rtt_sample = path.first_packet_after_rtt_sample;
3320
3321 let largest_acked_packet_pn = self.spaces[pn_space]
3322 .for_path(path_id)
3323 .largest_acked_packet_pn
3324 .expect("detect_lost_packets only to be called if path received at least one ACK");
3325 let packet_threshold = self.config.packet_threshold as u64;
3326
3327 let congestion_period = self
3331 .pto(SpaceKind::Data, path_id)
3332 .saturating_mul(self.config.persistent_congestion_threshold);
3333 let mut persistent_congestion_start: Option<Instant> = None;
3334 let mut prev_packet = None;
3335 let space = self.spaces[pn_space].for_path(path_id);
3336
3337 for (packet, info) in space.sent_packets.iter_range(0..largest_acked_packet_pn) {
3338 if prev_packet != Some(packet.wrapping_sub(1)) {
3339 persistent_congestion_start = None;
3341 }
3342
3343 let packet_too_old = now.saturating_duration_since(info.time_sent) >= loss_delay;
3347 if packet_too_old || largest_acked_packet_pn >= packet + packet_threshold {
3348 if Some(packet) == in_flight_mtu_probe {
3350 lost_mtu_probe = in_flight_mtu_probe;
3353 } else {
3354 lost_packets.push(packet);
3355 size_of_lost_packets += info.size as u64;
3356 if info.ack_eliciting && due_to_ack {
3357 match persistent_congestion_start {
3358 Some(start) if info.time_sent - start > congestion_period => {
3361 in_persistent_congestion = true;
3362 }
3363 None if first_packet_after_rtt_sample
3365 .is_some_and(|x| x < (pn_space.kind(), packet)) =>
3366 {
3367 persistent_congestion_start = Some(info.time_sent);
3368 }
3369 _ => {}
3370 }
3371 }
3372 }
3373 } else {
3374 if space.loss_time.is_none() {
3376 space.loss_time = Some(info.time_sent + loss_delay);
3379 }
3380 persistent_congestion_start = None;
3381 }
3382
3383 prev_packet = Some(packet);
3384 }
3385
3386 self.handle_lost_packets(
3387 pn_space,
3388 path_id,
3389 now,
3390 lost_packets,
3391 lost_mtu_probe,
3392 loss_delay,
3393 in_persistent_congestion,
3394 size_of_lost_packets,
3395 );
3396 }
3397
3398 fn discard_path(&mut self, path_id: PathId, now: Instant) {
3400 trace!(%path_id, "dropping path state");
3401 let path = self.path_data(path_id);
3402 let in_flight_mtu_probe = path.mtud.in_flight_mtu_probe();
3403
3404 let mut size_of_lost_packets = 0u64; let lost_pns: Vec<_> = self.spaces[SpaceId::Data]
3406 .for_path(path_id)
3407 .sent_packets
3408 .iter()
3409 .filter(|(pn, _info)| Some(*pn) != in_flight_mtu_probe)
3410 .map(|(pn, info)| {
3411 size_of_lost_packets += info.size as u64;
3412 pn
3413 })
3414 .collect();
3415
3416 if !lost_pns.is_empty() {
3417 trace!(
3418 %path_id,
3419 count = lost_pns.len(),
3420 lost_bytes = size_of_lost_packets,
3421 "packets lost on path abandon"
3422 );
3423 self.handle_lost_packets(
3424 SpaceId::Data,
3425 path_id,
3426 now,
3427 lost_pns,
3428 in_flight_mtu_probe,
3429 Duration::ZERO,
3430 false,
3431 size_of_lost_packets,
3432 );
3433 }
3434 let path_stats = self.path_stats(path_id).unwrap_or_default();
3437 self.path_stats.discard(&path_id);
3438 self.partial_stats += path_stats;
3439 self.paths.remove(&path_id);
3440 self.spaces[SpaceId::Data].number_spaces.remove(&path_id);
3441
3442 self.events.push_back(
3443 PathEvent::Discarded {
3444 id: path_id,
3445 path_stats: Box::new(path_stats),
3446 }
3447 .into(),
3448 );
3449 }
3450
3451 fn handle_lost_packets(
3452 &mut self,
3453 pn_space: SpaceId,
3454 path_id: PathId,
3455 now: Instant,
3456 lost_packets: Vec<u64>,
3457 lost_mtu_probe: Option<u64>,
3458 loss_delay: Duration,
3459 in_persistent_congestion: bool,
3460 size_of_lost_packets: u64,
3461 ) {
3462 debug_assert!(lost_packets.is_sorted(), "lost_packets must be sorted");
3463
3464 self.drain_lost_packets(now, pn_space, path_id);
3465
3466 if let Some(largest_lost) = lost_packets.last().cloned() {
3468 let old_bytes_in_flight = self.path_data_mut(path_id).in_flight.bytes;
3469 let largest_lost_sent = self.spaces[pn_space]
3470 .for_path(path_id)
3471 .sent_packets
3472 .get(largest_lost)
3473 .unwrap()
3474 .time_sent;
3475 let path_stats = self.path_stats.get_mut(path_id);
3476 path_stats.lost_packets += lost_packets.len() as u64;
3477 path_stats.lost_bytes += size_of_lost_packets;
3478 trace!(
3479 %path_id,
3480 count = lost_packets.len(),
3481 lost_bytes = size_of_lost_packets,
3482 "packets lost",
3483 );
3484
3485 for &packet in &lost_packets {
3486 let Some(info) = self.spaces[pn_space].for_path(path_id).take(packet) else {
3487 continue;
3488 };
3489 self.qlog
3490 .emit_packet_lost(packet, &info, loss_delay, pn_space.kind(), now);
3491 self.paths
3492 .get_mut(&path_id)
3493 .unwrap()
3494 .remove_in_flight(&info);
3495
3496 for frame in info.stream_frames {
3497 self.streams.retransmit(frame);
3498 }
3499 self.spaces[pn_space].pending |= info.retransmits;
3500 let path = self.path_data_mut(path_id);
3501 path.pending |= info.path_retransmits;
3502 path.mtud.on_non_probe_lost(packet, info.size);
3503 path.congestion.on_packet_lost(info.size, packet, now);
3504
3505 self.spaces[pn_space].for_path(path_id).lost_packets.insert(
3506 packet,
3507 LostPacket {
3508 time_sent: info.time_sent,
3509 },
3510 );
3511 }
3512
3513 let path = self.path_data_mut(path_id);
3514 if path.mtud.black_hole_detected(now) {
3515 path.congestion.on_mtu_update(path.mtud.current_mtu());
3516 if let Some(max_datagram_size) = self.datagrams().max_size()
3517 && self.datagrams.drop_oversized(max_datagram_size)
3518 && self.datagrams.send_blocked
3519 {
3520 self.datagrams.send_blocked = false;
3521 self.events.push_back(Event::DatagramsUnblocked);
3522 }
3523 self.path_stats.get_mut(path_id).black_holes_detected += 1;
3524 }
3525
3526 let lost_ack_eliciting =
3528 old_bytes_in_flight != self.path_data_mut(path_id).in_flight.bytes;
3529
3530 if lost_ack_eliciting {
3531 self.path_stats.get_mut(path_id).congestion_events += 1;
3532 self.path_data_mut(path_id).congestion.on_congestion_event(
3533 now,
3534 largest_lost_sent,
3535 in_persistent_congestion,
3536 false,
3537 size_of_lost_packets,
3538 largest_lost,
3539 );
3540 }
3541 }
3542
3543 if let Some(packet) = lost_mtu_probe {
3545 let info = self.spaces[SpaceId::Data]
3546 .for_path(path_id)
3547 .take(packet)
3548 .unwrap(); self.paths
3551 .get_mut(&path_id)
3552 .unwrap()
3553 .remove_in_flight(&info);
3554 self.path_data_mut(path_id).mtud.on_probe_lost();
3555 self.path_stats.get_mut(path_id).lost_plpmtud_probes += 1;
3556 }
3557 }
3558
3559 fn loss_time_and_space(&self, path_id: PathId) -> Option<(Instant, SpaceId)> {
3565 SpaceId::iter()
3566 .filter_map(|id| {
3567 self.spaces[id]
3568 .number_spaces
3569 .get(&path_id)
3570 .and_then(|pns| pns.loss_time)
3571 .map(|time| (time, id))
3572 })
3573 .min_by_key(|&(time, _)| time)
3574 }
3575
3576 fn pto_time_and_space(&mut self, now: Instant, path_id: PathId) -> Option<(Instant, SpaceId)> {
3584 let path = self.path(path_id)?;
3585 let pto_count = path.pto_count;
3586
3587 let max_interval = if path.rtt.get() > SLOW_RTT_THRESHOLD {
3589 (path.rtt.get() * 3) / 2
3591 } else if let Some(idle) = path.idle_timeout.or(self.idle_timeout)
3592 && idle <= MIN_IDLE_FOR_FAST_PTO
3593 {
3594 MAX_PTO_FAST_INTERVAL
3597 } else {
3598 MAX_PTO_INTERVAL
3600 };
3601
3602 if path_id == PathId::ZERO
3603 && path.in_flight.ack_eliciting == 0
3604 && !self.peer_completed_handshake_address_validation()
3605 {
3606 let space = match self.highest_space {
3612 SpaceKind::Handshake => SpaceId::Handshake,
3613 _ => SpaceId::Initial,
3614 };
3615
3616 let backoff = 2u32.pow(path.pto_count.min(MAX_BACKOFF_EXPONENT));
3617 let duration = path.rtt.pto_base() * backoff;
3618 let duration = duration.min(max_interval);
3619 return Some((now + duration, space));
3620 }
3621
3622 let mut result = None;
3623 for space in SpaceId::iter() {
3624 let Some(pns) = self.spaces[space].number_spaces.get(&path_id) else {
3625 continue;
3626 };
3627
3628 if space == SpaceId::Data && !self.is_handshake_confirmed() {
3629 continue;
3633 }
3634
3635 if !pns.has_in_flight() {
3636 continue;
3637 }
3638
3639 let duration = {
3644 let max_ack_delay = if space == SpaceId::Data {
3645 self.ack_frequency.max_ack_delay_for_pto()
3646 } else {
3647 Duration::ZERO
3648 };
3649 let pto_base = path.rtt.pto_base() + max_ack_delay;
3650 let mut duration = pto_base;
3651 for i in 1..=pto_count {
3652 let exponential_duration = pto_base * 2u32.pow(i.min(MAX_BACKOFF_EXPONENT));
3653 let max_duration = duration + max_interval;
3654 duration = exponential_duration.min(max_duration);
3655 }
3656 duration
3657 };
3658
3659 let Some(last_ack_eliciting) = pns.time_of_last_ack_eliciting_packet else {
3660 continue;
3661 };
3662 let pto = last_ack_eliciting + duration;
3665 if result.is_none_or(|(earliest_pto, _)| pto < earliest_pto) {
3666 if path.anti_amplification_blocked(1) {
3667 continue;
3669 }
3670 if path.in_flight.ack_eliciting == 0 {
3671 continue;
3673 }
3674 result = Some((pto, space));
3675 }
3676 }
3677 result
3678 }
3679
3680 fn peer_completed_handshake_address_validation(&self) -> bool {
3682 if self.side.is_server() || self.state.is_closed() {
3683 return true;
3684 }
3685 self.spaces[SpaceId::Handshake]
3689 .path_space(PathId::ZERO)
3690 .and_then(|pns| pns.largest_acked_packet_pn)
3691 .is_some()
3692 || self.spaces[SpaceId::Data]
3693 .path_space(PathId::ZERO)
3694 .and_then(|pns| pns.largest_acked_packet_pn)
3695 .is_some()
3696 || (self.crypto_state.has_keys(EncryptionLevel::OneRtt)
3697 && !self.crypto_state.has_keys(EncryptionLevel::Handshake))
3698 }
3699
3700 fn set_loss_detection_timer(&mut self, now: Instant, path_id: PathId) {
3708 if self.state.is_closed() {
3709 return;
3713 }
3714
3715 if let Some((loss_time, _)) = self.loss_time_and_space(path_id) {
3716 self.timers.set(
3718 Timer::PerPath(path_id, PathTimer::LossDetection),
3719 loss_time,
3720 self.qlog.with_time(now),
3721 );
3722 return;
3723 }
3724
3725 if !self.abandoned_paths.contains(&path_id)
3728 && let Some((timeout, _)) = self.pto_time_and_space(now, path_id)
3729 {
3730 self.timers.set(
3731 Timer::PerPath(path_id, PathTimer::LossDetection),
3732 timeout,
3733 self.qlog.with_time(now),
3734 );
3735 } else {
3736 self.timers.stop(
3737 Timer::PerPath(path_id, PathTimer::LossDetection),
3738 self.qlog.with_time(now),
3739 );
3740 }
3741 }
3742
3743 fn max_pto_for_space(&self, space: SpaceKind) -> Duration {
3747 self.paths
3748 .keys()
3749 .map(|path_id| self.pto(space, *path_id))
3750 .max()
3751 .unwrap_or_else(|| {
3752 let rtt = self.config.initial_rtt;
3756 let max_ack_delay = match space {
3757 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3758 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3759 };
3760 rtt + cmp::max(4 * (rtt / 2), TIMER_GRANULARITY) + max_ack_delay
3761 })
3762 }
3763
3764 fn pto(&self, space: SpaceKind, path_id: PathId) -> Duration {
3769 let max_ack_delay = match space {
3770 SpaceKind::Initial | SpaceKind::Handshake => Duration::ZERO,
3771 SpaceKind::Data => self.ack_frequency.max_ack_delay_for_pto(),
3772 };
3773 self.path_data(path_id).rtt.pto_base() + max_ack_delay
3774 }
3775
3776 fn on_packet_authenticated(
3777 &mut self,
3778 now: Instant,
3779 space_id: SpaceKind,
3780 path_id: PathId,
3781 ecn: Option<EcnCodepoint>,
3782 packet_number: Option<u64>,
3783 spin: bool,
3784 is_1rtt: bool,
3785 remote: &FourTuple,
3786 ) {
3787 let is_on_path = self
3794 .path_data(path_id)
3795 .network_path
3796 .is_probably_same_path(remote);
3797
3798 self.total_authed_packets += 1;
3799 self.reset_keep_alive(path_id, now);
3800 self.reset_idle_timeout(now, space_id, path_id);
3801 self.path_data_mut(path_id).permit_idle_reset = true;
3802
3803 if is_on_path {
3806 self.receiving_ecn |= ecn.is_some();
3807 if let Some(x) = ecn {
3808 let space = &mut self.spaces[space_id];
3809 space.for_path(path_id).ecn_counters += x;
3810
3811 if x.is_ce() {
3812 space
3813 .for_path(path_id)
3814 .pending_acks
3815 .set_immediate_ack_required();
3816 }
3817 }
3818 }
3819
3820 let Some(packet_number) = packet_number else {
3821 return;
3822 };
3823 match &self.side {
3824 ConnectionSide::Client { .. } => {
3825 if space_id == SpaceKind::Handshake
3829 && let Some(hs) = self.state.as_handshake_mut()
3830 {
3831 hs.allow_server_migration = false;
3832 }
3833 }
3834 ConnectionSide::Server { .. } => {
3835 if self.crypto_state.has_keys(EncryptionLevel::Initial)
3836 && space_id == SpaceKind::Handshake
3837 {
3838 self.discard_space(now, SpaceKind::Initial);
3841 }
3842 if self.crypto_state.has_keys(EncryptionLevel::ZeroRtt) && is_1rtt {
3843 self.set_key_discard_timer(now, space_id)
3845 }
3846 }
3847 }
3848 let space = self.spaces[space_id].for_path(path_id);
3849
3850 space.pending_acks.insert_one(packet_number, now);
3851 if packet_number >= space.largest_received_packet_number.unwrap_or_default() {
3852 space.largest_received_packet_number = Some(packet_number);
3853
3854 if is_on_path {
3856 self.spin = self.side.is_client() ^ spin;
3857 }
3858 }
3859 }
3860
3861 fn reset_idle_timeout(&mut self, now: Instant, space: SpaceKind, path_id: PathId) {
3866 if let Some(timeout) = self.idle_timeout {
3868 if self.state.is_closed() {
3869 self.timers
3870 .stop(Timer::Conn(ConnTimer::Idle), self.qlog.with_time(now));
3871 } else {
3872 let dt = cmp::max(timeout, 3 * self.max_pto_for_space(space));
3873 self.timers.set(
3874 Timer::Conn(ConnTimer::Idle),
3875 now + dt,
3876 self.qlog.with_time(now),
3877 );
3878 }
3879 }
3880
3881 self.rearm_path_max_idle_timer(now, space, path_id);
3883 }
3884
3885 fn reset_keep_alive(&mut self, path_id: PathId, now: Instant) {
3887 if !self.state.is_established() {
3888 return;
3889 }
3890
3891 if let Some(interval) = self.config.keep_alive_interval {
3892 self.timers.set(
3893 Timer::Conn(ConnTimer::KeepAlive),
3894 now + interval,
3895 self.qlog.with_time(now),
3896 );
3897 }
3898
3899 if let Some(interval) = self.path_data(path_id).keep_alive {
3900 self.timers.set(
3901 Timer::PerPath(path_id, PathTimer::PathKeepAlive),
3902 now + interval,
3903 self.qlog.with_time(now),
3904 );
3905 }
3906 }
3907
3908 fn reset_cid_retirement(&mut self, now: Instant) {
3910 if let Some((_path, t)) = self.next_cid_retirement() {
3911 self.timers.set(
3912 Timer::Conn(ConnTimer::PushNewCid),
3913 t,
3914 self.qlog.with_time(now),
3915 );
3916 }
3917 }
3918
3919 fn next_cid_retirement(&self) -> Option<(PathId, Instant)> {
3921 self.local_cid_state
3922 .iter()
3923 .filter_map(|(path_id, cid_state)| cid_state.next_timeout().map(|t| (*path_id, t)))
3924 .min_by_key(|(_path_id, timeout)| *timeout)
3925 }
3926
3927 pub(crate) fn handle_first_packet(
3932 &mut self,
3933 now: Instant,
3934 network_path: FourTuple,
3935 ecn: Option<EcnCodepoint>,
3936 packet_number: u64,
3937 packet: InitialPacket,
3938 remaining: Option<BytesMut>,
3939 ) -> Result<(), ConnectionError> {
3940 let span = trace_span!("first recv");
3941 let _guard = span.enter();
3942 debug_assert!(self.side.is_server());
3943 let len = packet.header_data.len() + packet.payload.len();
3944 let path_id = PathId::ZERO;
3945 self.path_data_mut(path_id).total_recvd = len as u64;
3946
3947 if let Some(hs) = self.state.as_handshake_mut() {
3948 hs.expected_token = packet.header.token.clone();
3949 } else {
3950 unreachable!("first packet must be delivered in Handshake state");
3951 }
3952
3953 self.on_packet_authenticated(
3955 now,
3956 SpaceKind::Initial,
3957 path_id,
3958 ecn,
3959 Some(packet_number),
3960 false,
3961 false,
3962 &network_path,
3963 );
3964
3965 let packet: Packet = packet.into();
3966
3967 let mut qlog = QlogRecvPacket::new(len);
3968 qlog.header(&packet.header, Some(packet_number), path_id);
3969
3970 self.process_decrypted_packet(
3971 now,
3972 network_path,
3973 path_id,
3974 Some(packet_number),
3975 packet,
3976 &mut qlog,
3977 )?;
3978 self.qlog.emit_packet_received(qlog, now);
3979 if let Some(data) = remaining {
3980 self.handle_coalesced(now, network_path, path_id, ecn, data);
3981 }
3982
3983 self.qlog.emit_recovery_metrics(
3984 path_id,
3985 &mut self
3986 .paths
3987 .get_mut(&path_id)
3988 .expect("path_id was supplied by the caller for an active path")
3989 .data,
3990 now,
3991 );
3992
3993 Ok(())
3994 }
3995
3996 fn init_0rtt(&mut self, now: Instant) {
3997 let Some((header, packet)) = self.crypto_state.session.early_crypto() else {
3998 return;
3999 };
4000 if self.side.is_client() {
4001 match self.crypto_state.session.transport_parameters() {
4002 Ok(params) => {
4003 let params = params
4004 .expect("crypto layer didn't supply transport parameters with ticket");
4005 let params = TransportParameters {
4007 initial_src_cid: None,
4008 original_dst_cid: None,
4009 preferred_address: None,
4010 retry_src_cid: None,
4011 stateless_reset_token: None,
4012 min_ack_delay: None,
4013 ack_delay_exponent: TransportParameters::default().ack_delay_exponent,
4014 max_ack_delay: TransportParameters::default().max_ack_delay,
4015 initial_max_path_id: None,
4016 ..params
4017 };
4018 self.set_peer_params(params);
4019 self.qlog.emit_peer_transport_params_restored(self, now);
4020 }
4021 Err(e) => {
4022 error!("session ticket has malformed transport parameters: {}", e);
4023 return;
4024 }
4025 }
4026 }
4027 trace!("0-RTT enabled");
4028 self.crypto_state.enable_zero_rtt(header, packet);
4029 }
4030
4031 fn read_crypto(
4032 &mut self,
4033 space: SpaceId,
4034 crypto: &frame::Crypto,
4035 payload_len: usize,
4036 ) -> Result<(), TransportError> {
4037 let expected = if !self.state.is_handshake() {
4038 SpaceId::Data
4039 } else if self.highest_space == SpaceKind::Initial {
4040 SpaceId::Initial
4041 } else {
4042 SpaceId::Handshake
4045 };
4046 debug_assert!(space <= expected, "received out-of-order CRYPTO data");
4050
4051 let end = crypto.offset + crypto.data.len() as u64;
4052 if space < expected
4053 && end
4054 > self.crypto_state.spaces[space.kind()]
4055 .crypto_stream
4056 .bytes_read()
4057 {
4058 warn!(
4059 "received new {:?} CRYPTO data when expecting {:?}",
4060 space, expected
4061 );
4062 return Err(TransportError::PROTOCOL_VIOLATION(
4063 "new data at unexpected encryption level",
4064 ));
4065 }
4066
4067 let crypto_space = &mut self.crypto_state.spaces[space.kind()];
4068 let max = end.saturating_sub(crypto_space.crypto_stream.bytes_read());
4069 if max > self.config.crypto_buffer_size as u64 {
4070 return Err(TransportError::CRYPTO_BUFFER_EXCEEDED(""));
4071 }
4072
4073 crypto_space
4074 .crypto_stream
4075 .insert(crypto.offset, crypto.data.clone(), payload_len);
4076 while let Some(chunk) = crypto_space.crypto_stream.read(usize::MAX, true) {
4077 trace!("consumed {} CRYPTO bytes", chunk.bytes.len());
4078 if self.crypto_state.session.read_handshake(&chunk.bytes)? {
4079 self.events.push_back(Event::HandshakeDataReady);
4080 }
4081 }
4082
4083 Ok(())
4084 }
4085
4086 fn write_crypto(&mut self) {
4087 loop {
4088 let space = self.highest_space;
4089 let mut outgoing = Vec::new();
4090 if let Some(crypto) = self.crypto_state.session.write_handshake(&mut outgoing) {
4091 match space {
4092 SpaceKind::Initial => {
4093 self.upgrade_crypto(SpaceKind::Handshake, crypto);
4094 }
4095 SpaceKind::Handshake => {
4096 self.upgrade_crypto(SpaceKind::Data, crypto);
4097 }
4098 SpaceKind::Data => unreachable!("got updated secrets during 1-RTT"),
4099 }
4100 }
4101 if outgoing.is_empty() {
4102 if space == self.highest_space {
4103 break;
4104 } else {
4105 continue;
4107 }
4108 }
4109 let offset = self.crypto_state.spaces[space].crypto_offset;
4110 let outgoing = Bytes::from(outgoing);
4111 if let Some(hs) = self.state.as_handshake_mut()
4112 && space == SpaceKind::Initial
4113 && offset == 0
4114 && self.side.is_client()
4115 {
4116 hs.client_hello = Some(outgoing.clone());
4117 }
4118 self.crypto_state.spaces[space].crypto_offset += outgoing.len() as u64;
4119 trace!("wrote {} {:?} CRYPTO bytes", outgoing.len(), space);
4120 self.spaces[space].pending.crypto.push_back(frame::Crypto {
4121 offset,
4122 data: outgoing,
4123 });
4124 }
4125 }
4126
4127 fn upgrade_crypto(&mut self, space: SpaceKind, crypto: Keys) {
4129 debug_assert!(
4130 !self.crypto_state.has_keys(space.encryption_level()),
4131 "already reached packet space {space:?}"
4132 );
4133 trace!("{:?} keys ready", space);
4134 if space == SpaceKind::Data {
4135 self.crypto_state.next_crypto = Some(
4137 self.crypto_state
4138 .session
4139 .next_1rtt_keys()
4140 .expect("handshake should be complete"),
4141 );
4142 }
4143
4144 self.crypto_state.spaces[space].keys = Some(crypto);
4145 debug_assert!(space > self.highest_space);
4146 self.highest_space = space;
4147 if space == SpaceKind::Data && self.side.is_client() {
4148 self.crypto_state.discard_zero_rtt();
4150 }
4151 }
4152
4153 fn discard_space(&mut self, now: Instant, space: SpaceKind) {
4154 debug_assert!(space != SpaceKind::Data);
4155 trace!("discarding {:?} keys", space);
4156 if space == SpaceKind::Initial {
4157 if let ConnectionSide::Client { token, .. } = &mut self.side {
4159 *token = Bytes::new();
4160 }
4161 }
4162 self.crypto_state.spaces[space].keys = None;
4163 let space = &mut self.spaces[space];
4164 let pns = space.for_path(PathId::ZERO);
4165 pns.time_of_last_ack_eliciting_packet = None;
4166 pns.loss_time = None;
4167 pns.loss_probes = 0;
4168 let sent_packets = mem::take(&mut pns.sent_packets);
4169 let path = self
4170 .paths
4171 .get_mut(&PathId::ZERO)
4172 .expect("PathId::ZERO is alive while Initial/Handshake spaces exist");
4173 for (_, packet) in sent_packets.into_iter() {
4174 path.data.remove_in_flight(&packet);
4175 }
4176
4177 self.set_loss_detection_timer(now, PathId::ZERO)
4178 }
4179
4180 fn handle_coalesced(
4181 &mut self,
4182 now: Instant,
4183 network_path: FourTuple,
4184 path_id: PathId,
4185 ecn: Option<EcnCodepoint>,
4186 data: BytesMut,
4187 ) {
4188 let Some(path) = self.paths.get_mut(&path_id) else {
4189 trace!(%path_id, "discarding coalesced datagram tail for unknown path");
4190 return;
4191 };
4192 path.data.inc_total_recvd(data.len() as u64);
4193 let mut remaining = Some(data);
4194 let cid_len = self
4195 .local_cid_state
4196 .values()
4197 .map(|cid_state| cid_state.cid_len())
4198 .next()
4199 .expect("one cid_state must exist");
4200 while let Some(data) = remaining {
4201 match PartialDecode::new(
4202 data,
4203 &FixedLengthConnectionIdParser::new(cid_len),
4204 &[self.version],
4205 self.endpoint_config.grease_quic_bit,
4206 ) {
4207 Ok((partial_decode, rest)) => {
4208 remaining = rest;
4209 self.handle_decode(now, network_path, path_id, ecn, partial_decode);
4210 }
4211 Err(e) => {
4212 trace!("malformed header: {}", e);
4213 return;
4214 }
4215 }
4216 }
4217 }
4218
4219 fn handle_decode(
4225 &mut self,
4226 now: Instant,
4227 network_path: FourTuple,
4228 path_id: PathId,
4229 ecn: Option<EcnCodepoint>,
4230 partial_decode: PartialDecode,
4231 ) {
4232 let qlog = QlogRecvPacket::new(partial_decode.len());
4233 if let Some(decoded) = self
4234 .crypto_state
4235 .unprotect_header(partial_decode, self.peer_params.stateless_reset_token)
4236 {
4237 self.handle_packet(
4238 now,
4239 network_path,
4240 path_id,
4241 ecn,
4242 decoded.packet,
4243 decoded.stateless_reset,
4244 qlog,
4245 );
4246 }
4247 }
4248
4249 fn handle_packet(
4256 &mut self,
4257 now: Instant,
4258 network_path: FourTuple,
4259 path_id: PathId,
4260 ecn: Option<EcnCodepoint>,
4261 packet: Option<Packet>,
4262 stateless_reset: bool,
4263 mut qlog: QlogRecvPacket,
4264 ) {
4265 if let Some(ref packet) = packet {
4266 trace!(
4267 "got {:?} packet ({} bytes) from {} using id {}",
4268 packet.header.space(),
4269 packet.payload.len() + packet.header_data.len(),
4270 network_path,
4271 packet.header.dst_cid(),
4272 );
4273 }
4274
4275 let was_closed = self.state.is_closed();
4276 let was_drained = self.state.is_drained();
4277
4278 let decrypted = match packet {
4280 None => Err(None),
4281 Some(mut packet) => self
4282 .decrypt_packet(now, path_id, &mut packet)
4283 .map(move |number| (packet, number)),
4284 };
4285 let result = match decrypted {
4286 _ if stateless_reset => {
4287 debug!("got stateless reset");
4288 Err(ConnectionError::Reset)
4289 }
4290 Err(Some(e)) => {
4291 warn!("illegal packet: {}", e);
4292 Err(e.into())
4293 }
4294 Err(None) => {
4295 debug!("failed to authenticate packet");
4296 self.authentication_failures += 1;
4297 let integrity_limit = self
4298 .crypto_state
4299 .integrity_limit(self.highest_space)
4300 .unwrap();
4301 if self.authentication_failures > integrity_limit {
4302 Err(TransportError::AEAD_LIMIT_REACHED("integrity limit violated").into())
4303 } else {
4304 return;
4305 }
4306 }
4307 Ok((packet, pn)) => {
4308 qlog.header(&packet.header, pn, path_id);
4310 let span = match pn {
4311 Some(pn) => trace_span!("recv", space = ?packet.header.space(), pn),
4312 None => trace_span!("recv", space = ?packet.header.space()),
4313 };
4314 let _guard = span.enter();
4315
4316 if self.is_handshaking()
4324 && self
4325 .path(path_id)
4326 .map(|path_data| {
4327 !path_data.network_path.is_probably_same_path(&network_path)
4328 })
4329 .unwrap_or(false)
4330 {
4331 if let Some(hs) = self.state.as_handshake()
4332 && hs.allow_server_migration
4333 {
4334 trace!(
4335 %network_path,
4336 prev = %self.path_data(path_id).network_path,
4337 "server migrated to new remote",
4338 );
4339 self.path_data_mut(path_id).network_path = network_path;
4340 self.qlog.emit_tuple_assigned(path_id, network_path, now);
4341 } else {
4342 debug!(
4343 recv_path = %network_path,
4344 expected_path = %self.path_data_mut(path_id).network_path,
4345 "discarding packet with unexpected remote during handshake",
4346 );
4347 return;
4348 }
4349 }
4350
4351 let dedup = self.spaces[packet.header.space()]
4352 .path_space_mut(path_id)
4353 .map(|pns| &mut pns.dedup);
4354 if pn.zip(dedup).is_some_and(|(n, d)| d.insert(n)) {
4355 debug!("discarding possible duplicate packet");
4356 self.qlog.emit_packet_received(qlog, now);
4357 return;
4358 } else if self.state.is_handshake() && packet.header.is_short() {
4359 trace!("dropping short packet during handshake");
4361 self.qlog.emit_packet_received(qlog, now);
4362 return;
4363 } else {
4364 if let Header::Initial(InitialHeader { ref token, .. }) = packet.header
4365 && let Some(hs) = self.state.as_handshake()
4366 && self.side.is_server()
4367 && token != &hs.expected_token
4368 {
4369 warn!("discarding Initial with invalid retry token");
4373 self.qlog.emit_packet_received(qlog, now);
4374 return;
4375 }
4376
4377 if !self.state.is_closed() {
4378 let spin = match packet.header {
4379 Header::Short { spin, .. } => spin,
4380 _ => false,
4381 };
4382
4383 if self.side().is_server() && !self.abandoned_paths.contains(&path_id) {
4384 self.create_path(path_id, network_path, now, pn);
4386 }
4387 if self.paths.contains_key(&path_id) {
4388 self.on_packet_authenticated(
4389 now,
4390 packet.header.space(),
4391 path_id,
4392 ecn,
4393 pn,
4394 spin,
4395 packet.header.is_1rtt(),
4396 &network_path,
4397 );
4398 }
4399 }
4400
4401 let res = self.process_decrypted_packet(
4402 now,
4403 network_path,
4404 path_id,
4405 pn,
4406 packet,
4407 &mut qlog,
4408 );
4409
4410 self.qlog.emit_packet_received(qlog, now);
4411 res
4412 }
4413 }
4414 };
4415
4416 if let Err(conn_err) = result {
4418 match conn_err {
4419 ConnectionError::ApplicationClosed(reason) => self.state.move_to_closed(reason),
4420 ConnectionError::ConnectionClosed(reason) => self.state.move_to_closed(reason),
4421 ConnectionError::Reset
4422 | ConnectionError::TransportError(TransportError {
4423 code: TransportErrorCode::AEAD_LIMIT_REACHED,
4424 ..
4425 }) => {
4426 if !self.state.is_drained() {
4427 self.state
4428 .move_to_drained(Some(conn_err), &mut self.endpoint_events);
4429 }
4430 }
4431 ConnectionError::TimedOut => {
4432 unreachable!("timeouts aren't generated by packet processing");
4433 }
4434 ConnectionError::TransportError(err) => {
4435 debug!("closing connection due to transport error: {}", err);
4436 self.state.move_to_closed(err);
4437 }
4438 ConnectionError::VersionMismatch => {
4439 self.state
4440 .move_to_draining(Some(conn_err), &mut self.endpoint_events);
4441 }
4442 ConnectionError::LocallyClosed => {
4443 unreachable!("LocallyClosed isn't generated by packet processing");
4444 }
4445 ConnectionError::CidsExhausted => {
4446 unreachable!("CidsExhausted isn't generated by packet processing");
4447 }
4448 };
4449 }
4450
4451 if !was_closed && self.state.is_closed() {
4452 self.close_common();
4453 if !self.state.is_drained() {
4454 self.set_close_timer(now);
4455 }
4456 }
4457 if !was_drained && self.state.is_drained() {
4458 self.timers
4461 .stop(Timer::Conn(ConnTimer::Close), self.qlog.with_time(now));
4462 }
4463
4464 if matches!(self.state.as_type(), StateType::Closed) {
4471 if self
4489 .paths
4490 .get(&path_id)
4491 .map(|p| p.data.validated && p.data.network_path == network_path)
4492 .unwrap_or(false)
4493 {
4494 self.connection_close_pending = true;
4495 }
4496 }
4497 }
4498
4499 fn process_decrypted_packet(
4500 &mut self,
4501 now: Instant,
4502 network_path: FourTuple,
4503 path_id: PathId,
4504 number: Option<u64>,
4505 packet: Packet,
4506 qlog: &mut QlogRecvPacket,
4507 ) -> Result<(), ConnectionError> {
4508 if !self.paths.contains_key(&path_id) {
4509 trace!(%path_id, ?number, "discarding packet for unknown path");
4513 return Ok(());
4514 }
4515 let state = match self.state.as_type() {
4516 StateType::Established => {
4517 match packet.header.space() {
4518 SpaceKind::Data => self.process_payload(
4519 now,
4520 network_path,
4521 path_id,
4522 number.unwrap(),
4523 packet,
4524 qlog,
4525 )?,
4526 _ if packet.header.has_frames() => {
4527 self.process_early_payload(now, path_id, packet, qlog)?
4528 }
4529 _ => {
4530 trace!("discarding unexpected pre-handshake packet");
4531 }
4532 }
4533 return Ok(());
4534 }
4535 StateType::Closed => {
4536 for result in frame::Iter::new(packet.payload.freeze())? {
4537 let frame = match result {
4538 Ok(frame) => frame,
4539 Err(err) => {
4540 debug!("frame decoding error: {err:?}");
4541 continue;
4542 }
4543 };
4544 qlog.frame(&frame);
4545
4546 if let Frame::Padding = frame {
4547 continue;
4548 };
4549
4550 trace!(?frame, "processing frame in closed state");
4551
4552 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4553
4554 if let Frame::Close(_error) = frame {
4555 self.state.move_to_draining(None, &mut self.endpoint_events);
4556 break;
4557 }
4558 }
4559 return Ok(());
4560 }
4561 StateType::Draining | StateType::Drained => return Ok(()),
4562 StateType::Handshake => self.state.as_handshake_mut().expect("checked"),
4563 };
4564
4565 match packet.header {
4566 Header::Retry {
4567 src_cid: remote_cid,
4568 ..
4569 } => {
4570 debug_assert_eq!(path_id, PathId::ZERO);
4571 if self.side.is_server() {
4572 return Err(TransportError::PROTOCOL_VIOLATION("client sent Retry").into());
4573 }
4574
4575 let is_valid_retry = self
4576 .remote_cids
4577 .get(&path_id)
4578 .map(|cids| cids.active())
4579 .map(|orig_dst_cid| {
4580 self.crypto_state.session.is_valid_retry(
4581 orig_dst_cid,
4582 &packet.header_data,
4583 &packet.payload,
4584 )
4585 })
4586 .unwrap_or_default();
4587 if self.total_authed_packets > 1
4588 || packet.payload.len() <= 16 || !is_valid_retry
4590 {
4591 trace!("discarding invalid Retry");
4592 return Ok(());
4598 }
4599
4600 trace!("retrying with CID {}", remote_cid);
4601 let client_hello = state.client_hello.take().unwrap();
4602 self.retry_src_cid = Some(remote_cid);
4603 self.remote_cids
4604 .get_mut(&path_id)
4605 .expect("PathId::ZERO not yet abandoned, is_valid_retry would have been false")
4606 .update_initial_cid(remote_cid);
4607 self.remote_handshake_cid = remote_cid;
4608
4609 let space = &mut self.spaces[SpaceId::Initial];
4610 if let Some(info) = space.for_path(PathId::ZERO).take(0) {
4611 self.on_packet_acked(now, PathId::ZERO, 0, info);
4612 };
4613
4614 self.discard_space(now, SpaceKind::Initial); let crypto_space = &mut self.crypto_state.spaces[SpaceKind::Initial];
4617 crypto_space.keys = Some(
4618 self.crypto_state
4619 .session
4620 .initial_keys(remote_cid, self.side.side()),
4621 );
4622 crypto_space.crypto_offset = client_hello.len() as u64;
4623
4624 let next_pn = self.spaces[SpaceId::Initial]
4625 .for_path(path_id)
4626 .next_packet_number;
4627 self.spaces[SpaceId::Initial] = {
4628 let mut space = PacketSpace::new(now, SpaceId::Initial, &mut self.rng);
4629 space.for_path(path_id).next_packet_number = next_pn;
4630 space.pending.crypto.push_back(frame::Crypto {
4631 offset: 0,
4632 data: client_hello,
4633 });
4634 space
4635 };
4636
4637 let zero_rtt = mem::take(
4639 &mut self.spaces[SpaceId::Data]
4640 .for_path(PathId::ZERO)
4641 .sent_packets,
4642 );
4643 for (_, info) in zero_rtt.into_iter() {
4644 self.paths
4645 .get_mut(&PathId::ZERO)
4646 .unwrap()
4647 .remove_in_flight(&info);
4648 self.spaces[SpaceId::Data].pending |= info.retransmits;
4649 }
4650 self.streams.retransmit_all_for_0rtt();
4651
4652 let token_len = packet.payload.len() - 16;
4653 let ConnectionSide::Client { ref mut token, .. } = self.side else {
4654 unreachable!("we already short-circuited if we're server");
4655 };
4656 *token = packet.payload.freeze().split_to(token_len);
4657
4658 self.state = State::handshake(state::Handshake {
4659 expected_token: Bytes::new(),
4660 remote_cid_set: false,
4661 client_hello: None,
4662 allow_server_migration: self.config.server_handshake_migration,
4663 });
4664 Ok(())
4665 }
4666 Header::Long {
4667 ty: LongType::Handshake,
4668 src_cid: remote_cid,
4669 dst_cid: local_cid,
4670 ..
4671 } => {
4672 debug_assert_eq!(path_id, PathId::ZERO);
4673 if remote_cid != self.remote_handshake_cid {
4674 debug!(
4675 "discarding packet with mismatched remote CID: {} != {}",
4676 self.remote_handshake_cid, remote_cid
4677 );
4678 return Ok(());
4679 }
4680 self.on_path_validated(path_id);
4681
4682 self.process_early_payload(now, path_id, packet, qlog)?;
4683 if self.state.is_closed() {
4684 return Ok(());
4685 }
4686
4687 if self.crypto_state.session.is_handshaking() {
4688 trace!("handshake ongoing");
4689 return Ok(());
4690 }
4691
4692 if self.side.is_client() {
4693 let params = self
4695 .crypto_state
4696 .session
4697 .transport_parameters()?
4698 .ok_or_else(|| {
4699 TransportError::new(
4700 TransportErrorCode::crypto(0x6d),
4701 "transport parameters missing".to_owned(),
4702 )
4703 })?;
4704
4705 if self.has_0rtt() {
4706 if !self.crypto_state.session.early_data_accepted().unwrap() {
4707 debug_assert!(self.side.is_client());
4708 debug!("0-RTT rejected");
4709 self.crypto_state.accepted_0rtt = false;
4710 self.streams.zero_rtt_rejected();
4711
4712 self.spaces[SpaceId::Data].pending = Retransmits::default();
4714
4715 let sent_packets = mem::take(
4717 &mut self.spaces[SpaceId::Data].for_path(path_id).sent_packets,
4718 );
4719 for (_, packet) in sent_packets.into_iter() {
4720 self.paths
4721 .get_mut(&path_id)
4722 .unwrap()
4723 .remove_in_flight(&packet);
4724 }
4725 } else {
4726 self.crypto_state.accepted_0rtt = true;
4727 params.validate_resumption_from(&self.peer_params)?;
4728 }
4729 }
4730 if let Some(token) = params.stateless_reset_token {
4731 let remote = self.path_data(path_id).network_path.remote;
4732 debug_assert!(!self.state.is_drained()); self.endpoint_events
4734 .push_back(EndpointEventInner::ResetToken(path_id, remote, token));
4735 }
4736 self.handle_peer_params(params, local_cid, remote_cid, now)?;
4737 self.issue_first_cids(now);
4738 } else {
4739 self.spaces[SpaceId::Data].pending.handshake_done = true;
4741 self.discard_space(now, SpaceKind::Handshake);
4742 self.events.push_back(Event::HandshakeConfirmed);
4743 trace!("handshake confirmed");
4744 }
4745
4746 self.events.push_back(Event::Connected);
4747 self.state.move_to_established();
4748 trace!("established");
4749
4750 self.issue_first_path_cids(now);
4753 self.rearm_path_max_idle_timer(now, self.highest_space, path_id);
4754 Ok(())
4755 }
4756 Header::Initial(InitialHeader {
4757 src_cid: remote_cid,
4758 dst_cid: local_cid,
4759 ..
4760 }) => {
4761 debug_assert_eq!(path_id, PathId::ZERO);
4762 if !state.remote_cid_set {
4763 trace!("switching remote CID to {}", remote_cid);
4764 let mut state = state.clone();
4765 self.remote_cids
4766 .get_mut(&path_id)
4767 .expect("PathId::ZERO not yet abandoned")
4768 .update_initial_cid(remote_cid);
4769 self.remote_handshake_cid = remote_cid;
4770 self.original_remote_cid = remote_cid;
4771 state.remote_cid_set = true;
4772 self.state.move_to_handshake(state);
4773 } else if remote_cid != self.remote_handshake_cid {
4774 debug!(
4775 "discarding packet with mismatched remote CID: {} != {}",
4776 self.remote_handshake_cid, remote_cid
4777 );
4778 return Ok(());
4779 }
4780
4781 let starting_space = self.highest_space;
4782 self.process_early_payload(now, path_id, packet, qlog)?;
4783
4784 if self.side.is_server()
4785 && starting_space == SpaceKind::Initial
4786 && self.highest_space != SpaceKind::Initial
4787 {
4788 let params = self
4789 .crypto_state
4790 .session
4791 .transport_parameters()?
4792 .ok_or_else(|| {
4793 TransportError::new(
4794 TransportErrorCode::crypto(0x6d),
4795 "transport parameters missing".to_owned(),
4796 )
4797 })?;
4798 self.handle_peer_params(params, local_cid, remote_cid, now)?;
4799 self.issue_first_cids(now);
4800 self.init_0rtt(now);
4801 }
4802 Ok(())
4803 }
4804 Header::Long {
4805 ty: LongType::ZeroRtt,
4806 ..
4807 } => {
4808 self.process_payload(now, network_path, path_id, number.unwrap(), packet, qlog)?;
4809 Ok(())
4810 }
4811 Header::VersionNegotiate { .. } => {
4812 if self.total_authed_packets > 1 {
4813 return Ok(());
4814 }
4815 let supported = packet
4816 .payload
4817 .chunks(4)
4818 .any(|x| match <[u8; 4]>::try_from(x) {
4819 Ok(version) => self.version == u32::from_be_bytes(version),
4820 Err(_) => false,
4821 });
4822 if supported {
4823 return Ok(());
4824 }
4825 debug!("remote doesn't support our version");
4826 Err(ConnectionError::VersionMismatch)
4827 }
4828 Header::Short { .. } => unreachable!(
4829 "short packets received during handshake are discarded in handle_packet"
4830 ),
4831 }
4832 }
4833
4834 fn process_early_payload(
4836 &mut self,
4837 now: Instant,
4838 path_id: PathId,
4839 packet: Packet,
4840 #[allow(unused)] qlog: &mut QlogRecvPacket,
4841 ) -> Result<(), TransportError> {
4842 debug_assert_ne!(packet.header.space(), SpaceKind::Data);
4843 debug_assert_eq!(path_id, PathId::ZERO);
4844 let payload_len = packet.payload.len();
4845 let mut ack_eliciting = false;
4846 for result in frame::Iter::new(packet.payload.freeze())? {
4847 let frame = result?;
4848 qlog.frame(&frame);
4849 let span = match frame {
4850 Frame::Padding => continue,
4851 _ => Some(trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty)),
4852 };
4853
4854 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4855
4856 let _guard = span.as_ref().map(|x| x.enter());
4857 ack_eliciting |= frame.is_ack_eliciting();
4858
4859 if frame.is_1rtt() && packet.header.space() != SpaceKind::Data {
4861 return Err(TransportError::PROTOCOL_VIOLATION(
4862 "illegal frame type in handshake",
4863 ));
4864 }
4865
4866 match frame {
4867 Frame::Padding | Frame::Ping => {}
4868 Frame::Crypto(frame) => {
4869 self.read_crypto(packet.header.space().into(), &frame, payload_len)?;
4870 }
4871 Frame::Ack(ack) => {
4872 self.on_ack_received(now, packet.header.space().into(), ack)?;
4873 }
4874 Frame::PathAck(ack) => {
4875 span.as_ref()
4876 .map(|span| span.record("path", tracing::field::display(&ack.path_id)));
4877 self.on_path_ack_received(now, packet.header.space().into(), ack)?;
4878 }
4879 Frame::Close(reason) => {
4880 self.state
4881 .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
4882 return Ok(());
4883 }
4884 _ => {
4885 let mut err =
4886 TransportError::PROTOCOL_VIOLATION("illegal frame type in handshake");
4887 err.frame = frame::MaybeFrame::Known(frame.ty());
4888 return Err(err);
4889 }
4890 }
4891 }
4892
4893 if ack_eliciting {
4894 self.spaces[packet.header.space()]
4896 .for_path(path_id)
4897 .pending_acks
4898 .set_immediate_ack_required();
4899 }
4900
4901 self.write_crypto();
4902 Ok(())
4903 }
4904
4905 fn process_payload(
4907 &mut self,
4908 now: Instant,
4909 network_path: FourTuple,
4910 path_id: PathId,
4911 number: u64,
4912 packet: Packet,
4913 #[allow(unused)] qlog: &mut QlogRecvPacket,
4914 ) -> Result<(), TransportError> {
4915 let payload = packet.payload.freeze();
4916 let mut is_probing_packet = true;
4917 let mut close = None;
4918 let payload_len = payload.len();
4919 let mut ack_eliciting = false;
4920 let mut migration_observed_addr = None;
4923 for result in frame::Iter::new(payload)? {
4924 let frame = result?;
4925 qlog.frame(&frame);
4926 let span = match frame {
4927 Frame::Padding => continue,
4928 _ => trace_span!("frame", ty = %frame.ty(), path = tracing::field::Empty),
4929 };
4930
4931 self.path_stats.get_mut(path_id).frame_rx.record(frame.ty());
4932 match &frame {
4935 Frame::Crypto(f) => {
4936 trace!(offset = f.offset, len = f.data.len(), "got frame CRYPTO");
4937 }
4938 Frame::Stream(f) => {
4939 trace!(id = %f.id, offset = f.offset, len = f.data.len(), fin = f.fin, "got frame STREAM");
4940 }
4941 Frame::Datagram(f) => {
4942 trace!(len = f.data.len(), "got frame DATAGRAM");
4943 }
4944 f => {
4945 trace!("got frame {f}");
4946 }
4947 }
4948
4949 let _guard = span.enter();
4950 if packet.header.is_0rtt() {
4951 match frame {
4952 Frame::Crypto(_) | Frame::Close(Close::Application(_)) => {
4953 return Err(TransportError::PROTOCOL_VIOLATION(
4954 "illegal frame type in 0-RTT",
4955 ));
4956 }
4957 _ => {
4958 if frame.is_1rtt() {
4959 return Err(TransportError::PROTOCOL_VIOLATION(
4960 "illegal frame type in 0-RTT",
4961 ));
4962 }
4963 }
4964 }
4965 }
4966 ack_eliciting |= frame.is_ack_eliciting();
4967
4968 match frame {
4970 Frame::Padding
4971 | Frame::PathChallenge(_)
4972 | Frame::PathResponse(_)
4973 | Frame::NewConnectionId(_)
4974 | Frame::ObservedAddr(_) => {}
4975 _ => {
4976 is_probing_packet = false;
4977 }
4978 }
4979
4980 match frame {
4981 Frame::Crypto(frame) => {
4982 self.read_crypto(SpaceId::Data, &frame, payload_len)?;
4983 }
4984 Frame::Stream(frame) => {
4985 if self.streams.received(frame, payload_len)?.should_transmit() {
4986 self.spaces[SpaceId::Data].pending.max_data = true;
4987 }
4988 }
4989 Frame::Ack(ack) => {
4990 self.on_ack_received(now, SpaceId::Data, ack)?;
4991 }
4992 Frame::PathAck(ack) => {
4993 if !self.is_multipath_negotiated() {
4994 return Err(TransportError::PROTOCOL_VIOLATION(
4995 "received PATH_ACK frame when multipath was not negotiated",
4996 ));
4997 }
4998 span.record("path", tracing::field::display(&ack.path_id));
4999 self.on_path_ack_received(now, SpaceId::Data, ack)?;
5000 }
5001 Frame::Padding | Frame::Ping => {}
5002 Frame::Close(reason) => {
5003 close = Some(reason);
5004 }
5005 Frame::PathChallenge(challenge) => {
5006 self.spaces[SpaceKind::Data]
5007 .for_path(path_id)
5008 .pending_path_responses
5009 .push(number, challenge.0, network_path);
5010 let path = &mut self
5014 .path_mut(path_id)
5015 .expect("payload is processed only after the path becomes known");
5016 if network_path.remote == path.network_path.remote {
5017 match self.peer_supports_ack_frequency() {
5025 true => self.immediate_ack(path_id),
5026 false => {
5027 self.ping_path(path_id).ok();
5028 }
5029 }
5030 }
5031 }
5032 Frame::PathResponse(response) => {
5033 if self
5035 .n0_nat_traversal
5036 .handle_path_response(network_path, response.0)
5037 {
5038 self.open_nat_traversed_paths(now);
5039 } else {
5040 self.handle_path_response_on_path(now, response, path_id);
5042 }
5043 }
5044 Frame::MaxData(frame::MaxData(bytes)) => {
5045 self.streams.received_max_data(bytes);
5046 }
5047 Frame::MaxStreamData(frame::MaxStreamData { id, offset }) => {
5048 self.streams.received_max_stream_data(id, offset)?;
5049 }
5050 Frame::MaxStreams(frame::MaxStreams { dir, count }) => {
5051 self.streams.received_max_streams(dir, count)?;
5052 }
5053 Frame::ResetStream(frame) => {
5054 if self.streams.received_reset(frame)?.should_transmit() {
5055 self.spaces[SpaceId::Data].pending.max_data = true;
5056 }
5057 }
5058 Frame::DataBlocked(DataBlocked(offset)) => {
5059 debug!(offset, "peer claims to be blocked at connection level");
5060 }
5061 Frame::StreamDataBlocked(StreamDataBlocked { id, offset }) => {
5062 if id.initiator() == self.side.side() && id.dir() == Dir::Uni {
5063 debug!("got STREAM_DATA_BLOCKED on send-only {}", id);
5064 return Err(TransportError::STREAM_STATE_ERROR(
5065 "STREAM_DATA_BLOCKED on send-only stream",
5066 ));
5067 }
5068 debug!(
5069 stream = %id,
5070 offset, "peer claims to be blocked at stream level"
5071 );
5072 }
5073 Frame::StreamsBlocked(StreamsBlocked { dir, limit }) => {
5074 if limit > MAX_STREAM_COUNT {
5075 return Err(TransportError::FRAME_ENCODING_ERROR(
5076 "unrepresentable stream limit",
5077 ));
5078 }
5079 debug!(
5080 "peer claims to be blocked opening more than {} {} streams",
5081 limit, dir
5082 );
5083 }
5084 Frame::StopSending(frame::StopSending { id, error_code }) => {
5085 if id.initiator() != self.side.side() {
5086 if id.dir() == Dir::Uni {
5087 debug!("got STOP_SENDING on recv-only {}", id);
5088 return Err(TransportError::STREAM_STATE_ERROR(
5089 "STOP_SENDING on recv-only stream",
5090 ));
5091 }
5092 } else if self.streams.is_local_unopened(id) {
5093 return Err(TransportError::STREAM_STATE_ERROR(
5094 "STOP_SENDING on unopened stream",
5095 ));
5096 }
5097 self.streams.received_stop_sending(id, error_code);
5098 }
5099 Frame::RetireConnectionId(frame::RetireConnectionId { path_id, sequence }) => {
5100 if let Some(ref path_id) = path_id {
5101 span.record("path", tracing::field::display(&path_id));
5102 }
5103 let path_id = path_id.unwrap_or_default();
5104 match self.local_cid_state.get_mut(&path_id) {
5105 None => debug!(?path_id, "RETIRE_CONNECTION_ID for unknown path"),
5106 Some(cid_state) => {
5107 let allow_more_cids = cid_state
5108 .on_cid_retirement(sequence, self.peer_params.issue_cids_limit())?;
5109
5110 let has_path = !self.abandoned_paths.contains(&path_id);
5114 let allow_more_cids = allow_more_cids && has_path;
5115
5116 debug_assert!(!self.state.is_drained()); self.endpoint_events
5118 .push_back(EndpointEventInner::RetireConnectionId(
5119 now,
5120 path_id,
5121 sequence,
5122 allow_more_cids,
5123 ));
5124 }
5125 }
5126 }
5127 Frame::NewConnectionId(frame) => {
5128 let path_id = if let Some(path_id) = frame.path_id {
5129 if !self.is_multipath_negotiated() {
5130 return Err(TransportError::PROTOCOL_VIOLATION(
5131 "received PATH_NEW_CONNECTION_ID frame when multipath was not negotiated",
5132 ));
5133 }
5134 if path_id > self.local_max_path_id {
5135 return Err(TransportError::PROTOCOL_VIOLATION(
5136 "PATH_NEW_CONNECTION_ID contains path_id exceeding current max",
5137 ));
5138 }
5139 path_id
5140 } else {
5141 PathId::ZERO
5142 };
5143
5144 if let Some(ref path_id) = frame.path_id {
5145 span.record("path", tracing::field::display(&path_id));
5146 }
5147
5148 if self.abandoned_paths.contains(&path_id) {
5149 trace!("ignoring issued CID for abandoned path");
5150 continue;
5151 }
5152 let remote_cids = self
5153 .remote_cids
5154 .entry(path_id)
5155 .or_insert_with(|| CidQueue::new(frame.id));
5156 if remote_cids.active().is_empty() {
5157 return Err(TransportError::PROTOCOL_VIOLATION(
5158 "NEW_CONNECTION_ID when CIDs aren't in use",
5159 ));
5160 }
5161 if frame.retire_prior_to > frame.sequence {
5162 return Err(TransportError::PROTOCOL_VIOLATION(
5163 "NEW_CONNECTION_ID retiring unissued CIDs",
5164 ));
5165 }
5166
5167 use crate::cid_queue::InsertError;
5168 match remote_cids.insert(frame) {
5169 Ok(None) => {
5170 self.open_nat_traversed_paths(now);
5171 }
5172 Ok(Some((retired, reset_token))) => {
5173 let pending_retired =
5174 &mut self.spaces[SpaceId::Data].pending.retire_cids;
5175 const MAX_PENDING_RETIRED_CIDS: u64 = CidQueue::LEN as u64 * 10;
5178 if (pending_retired.len() as u64)
5181 .saturating_add(retired.end.saturating_sub(retired.start))
5182 > MAX_PENDING_RETIRED_CIDS
5183 {
5184 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(
5185 "queued too many retired CIDs",
5186 ));
5187 }
5188 pending_retired.extend(retired.map(|seq| (path_id, seq)));
5189 self.set_reset_token(path_id, network_path.remote, reset_token);
5190 self.open_nat_traversed_paths(now);
5191 }
5192 Err(InsertError::ExceedsLimit) => {
5193 return Err(TransportError::CONNECTION_ID_LIMIT_ERROR(""));
5194 }
5195 Err(InsertError::Retired) => {
5196 trace!("discarding already-retired");
5197 self.spaces[SpaceId::Data]
5201 .pending
5202 .retire_cids
5203 .push((path_id, frame.sequence));
5204 continue;
5205 }
5206 };
5207
5208 if self.side.is_server()
5209 && path_id == PathId::ZERO
5210 && self
5211 .remote_cids
5212 .get(&PathId::ZERO)
5213 .map(|cids| cids.active_seq() == 0)
5214 .unwrap_or_default()
5215 {
5216 self.update_remote_cid(PathId::ZERO);
5219 }
5220 }
5221 Frame::NewToken(NewToken { token }) => {
5222 let ConnectionSide::Client {
5223 token_store,
5224 server_name,
5225 ..
5226 } = &self.side
5227 else {
5228 return Err(TransportError::PROTOCOL_VIOLATION("client sent NEW_TOKEN"));
5229 };
5230 if token.is_empty() {
5231 return Err(TransportError::FRAME_ENCODING_ERROR("empty token"));
5232 }
5233 trace!("got new token");
5234 token_store.insert(server_name, token);
5235 }
5236 Frame::Datagram(datagram) => {
5237 if self
5238 .datagrams
5239 .received(datagram, &self.config.datagram_receive_buffer_size)?
5240 {
5241 self.events.push_back(Event::DatagramReceived);
5242 }
5243 }
5244 Frame::AckFrequency(ack_frequency) => {
5245 if !self.ack_frequency.ack_frequency_received(&ack_frequency)? {
5248 continue;
5251 }
5252
5253 for (path_id, space) in self.spaces[SpaceId::Data].number_spaces.iter_mut() {
5255 space.pending_acks.set_ack_frequency_params(&ack_frequency);
5256
5257 if !self.abandoned_paths.contains(path_id)
5261 && let Some(timeout) = space
5262 .pending_acks
5263 .max_ack_delay_timeout(self.ack_frequency.max_ack_delay)
5264 {
5265 self.timers.set(
5266 Timer::PerPath(*path_id, PathTimer::MaxAckDelay),
5267 timeout,
5268 self.qlog.with_time(now),
5269 );
5270 }
5271 }
5272 }
5273 Frame::ImmediateAck => {
5274 for pns in self.spaces[SpaceId::Data].iter_paths_mut() {
5276 pns.pending_acks.set_immediate_ack_required();
5277 }
5278 }
5279 Frame::HandshakeDone => {
5280 if self.side.is_server() {
5281 return Err(TransportError::PROTOCOL_VIOLATION(
5282 "client sent HANDSHAKE_DONE",
5283 ));
5284 }
5285 if self.crypto_state.has_keys(EncryptionLevel::Handshake) {
5286 self.discard_space(now, SpaceKind::Handshake);
5287 self.events.push_back(Event::HandshakeConfirmed);
5288 trace!("handshake confirmed");
5289 }
5290 }
5291 Frame::ObservedAddr(observed) => {
5292 trace!(seq_no = %observed.seq_no, ip = %observed.ip, port = observed.port);
5294 if !self
5295 .peer_params
5296 .address_discovery_role
5297 .should_report(&self.config.address_discovery_role)
5298 {
5299 return Err(TransportError::PROTOCOL_VIOLATION(
5300 "received OBSERVED_ADDRESS frame when not negotiated",
5301 ));
5302 }
5303 if packet.header.space() != SpaceKind::Data {
5305 return Err(TransportError::PROTOCOL_VIOLATION(
5306 "OBSERVED_ADDRESS frame outside data space",
5307 ));
5308 }
5309
5310 let space_open_status =
5311 self.spaces[SpaceKind::Data].for_path(path_id).open_status;
5312 let path = self.path_data_mut(path_id);
5313 if path.network_path.remote == network_path.remote {
5314 if let Some(updated) = path.update_observed_addr_report(observed)
5315 && space_open_status == OpenStatus::Informed
5316 {
5317 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5318 id: path_id,
5319 addr: updated,
5320 }));
5321 }
5323 } else {
5324 migration_observed_addr = Some(observed)
5326 }
5327 }
5328 Frame::PathAbandon(frame::PathAbandon {
5329 path_id,
5330 error_code,
5331 }) => {
5332 span.record("path", tracing::field::display(&path_id));
5333 match self.close_path_inner(
5334 now,
5335 path_id,
5336 PathAbandonReason::RemoteAbandoned {
5337 error_code: error_code.into(),
5338 },
5339 ) {
5340 Ok(()) => {
5341 trace!("peer abandoned path");
5342 }
5343 Err(ClosePathError::ClosedPath) => {
5344 trace!("peer abandoned already closed path");
5345 }
5346 Err(ClosePathError::MultipathNotNegotiated) => {
5347 return Err(TransportError::PROTOCOL_VIOLATION(
5348 "received PATH_ABANDON frame when multipath was not negotiated",
5349 ));
5350 }
5351 Err(ClosePathError::LastOpenPath) => {
5352 error!(
5355 "peer abandoned last path but close_path_inner returned LastOpenPath"
5356 );
5357 }
5358 };
5359
5360 if let Some(path) = self.paths.get_mut(&path_id)
5362 && !mem::replace(&mut path.data.draining, true)
5363 {
5364 let ack_delay = self.ack_frequency.max_ack_delay_for_pto();
5365 let pto = path.data.rtt.pto_base() + ack_delay;
5366 self.timers.set(
5367 Timer::PerPath(path_id, PathTimer::PathDrained),
5368 now + 3 * pto,
5369 self.qlog.with_time(now),
5370 );
5371
5372 self.set_max_path_id(now, self.local_max_path_id.saturating_add(1u8));
5373 }
5374 }
5375 Frame::PathStatusAvailable(info) => {
5376 span.record("path", tracing::field::display(&info.path_id));
5377 if self.is_multipath_negotiated() {
5378 self.on_path_status(
5379 info.path_id,
5380 PathStatus::Available,
5381 info.status_seq_no,
5382 );
5383 } else {
5384 return Err(TransportError::PROTOCOL_VIOLATION(
5385 "received PATH_STATUS_AVAILABLE frame when multipath was not negotiated",
5386 ));
5387 }
5388 }
5389 Frame::PathStatusBackup(info) => {
5390 span.record("path", tracing::field::display(&info.path_id));
5391 if self.is_multipath_negotiated() {
5392 self.on_path_status(info.path_id, PathStatus::Backup, info.status_seq_no);
5393 } else {
5394 return Err(TransportError::PROTOCOL_VIOLATION(
5395 "received PATH_STATUS_BACKUP frame when multipath was not negotiated",
5396 ));
5397 }
5398 }
5399 Frame::MaxPathId(frame::MaxPathId(path_id)) => {
5400 span.record("path", tracing::field::display(&path_id));
5401 if !self.is_multipath_negotiated() {
5402 return Err(TransportError::PROTOCOL_VIOLATION(
5403 "received MAX_PATH_ID frame when multipath was not negotiated",
5404 ));
5405 }
5406 if path_id > self.remote_max_path_id {
5408 self.remote_max_path_id = path_id;
5409 self.issue_first_path_cids(now);
5410 self.open_nat_traversed_paths(now);
5411 }
5412 }
5413 Frame::PathsBlocked(frame::PathsBlocked(max_path_id)) => {
5414 if self.is_multipath_negotiated() {
5419 if max_path_id > self.local_max_path_id {
5420 return Err(TransportError::PROTOCOL_VIOLATION(
5421 "PATHS_BLOCKED maximum path identifier was larger than local maximum",
5422 ));
5423 }
5424 } else {
5425 return Err(TransportError::PROTOCOL_VIOLATION(
5426 "received PATHS_BLOCKED frame when not multipath was not negotiated",
5427 ));
5428 }
5429 }
5430 Frame::PathCidsBlocked(frame::PathCidsBlocked { path_id, next_seq }) => {
5431 if self.is_multipath_negotiated() {
5440 if path_id > self.local_max_path_id {
5441 return Err(TransportError::PROTOCOL_VIOLATION(
5442 "PATH_CIDS_BLOCKED path identifier was larger than local maximum",
5443 ));
5444 }
5445 if self
5446 .local_cid_state
5447 .get(&path_id)
5448 .is_some_and(|cid_state| next_seq.0 > cid_state.active_seq().1 + 1)
5452 {
5453 return Err(TransportError::PROTOCOL_VIOLATION(
5454 "PATH_CIDS_BLOCKED next sequence number larger than in local state",
5455 ));
5456 }
5457 debug!(%path_id, %next_seq, "received PATH_CIDS_BLOCKED");
5458 } else {
5459 return Err(TransportError::PROTOCOL_VIOLATION(
5460 "received PATH_CIDS_BLOCKED frame when not multipath was not negotiated",
5461 ));
5462 }
5463 }
5464 Frame::AddAddress(addr) => {
5465 let client_state = match self.n0_nat_traversal.client_side_mut() {
5466 Ok(state) => state,
5467 Err(err) => {
5468 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5469 "Nat traversal(ADD_ADDRESS): {err}"
5470 )));
5471 }
5472 };
5473
5474 if !client_state.check_remote_address(&addr) {
5475 warn!(?addr, "server sent illegal ADD_ADDRESS frame");
5477 }
5478
5479 match client_state.add_remote_address(addr) {
5480 Ok(maybe_added) => {
5481 if let Some(added) = maybe_added {
5482 self.events.push_back(Event::NatTraversal(
5483 n0_nat_traversal::Event::AddressAdded(added),
5484 ));
5485 }
5486 }
5487 Err(e) => {
5488 warn!(%e, "failed to add remote address")
5489 }
5490 }
5491 }
5492 Frame::RemoveAddress(addr) => {
5493 let client_state = match self.n0_nat_traversal.client_side_mut() {
5494 Ok(state) => state,
5495 Err(err) => {
5496 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5497 "Nat traversal(REMOVE_ADDRESS): {err}"
5498 )));
5499 }
5500 };
5501 if let Some(removed_addr) = client_state.remove_remote_address(addr) {
5502 self.events.push_back(Event::NatTraversal(
5503 n0_nat_traversal::Event::AddressRemoved(removed_addr),
5504 ));
5505 }
5506 }
5507 Frame::ReachOut(reach_out) => {
5508 let ipv6 = self.is_ipv6();
5509 let server_state = match self.n0_nat_traversal.server_side_mut() {
5510 Ok(state) => state,
5511 Err(err) => {
5512 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5513 "Nat traversal(REACH_OUT): {err}"
5514 )));
5515 }
5516 };
5517
5518 let round_before = server_state.current_round();
5519
5520 if let Err(err) = server_state.handle_reach_out(reach_out, ipv6) {
5521 return Err(TransportError::PROTOCOL_VIOLATION(format!(
5522 "Nat traversal(REACH_OUT): {err}"
5523 )));
5524 }
5525
5526 if server_state.current_round() > round_before {
5527 if let Some(delay) =
5529 self.n0_nat_traversal.retry_delay(self.config.initial_rtt)
5530 {
5531 self.timers.set(
5532 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
5533 now + delay,
5534 self.qlog.with_time(now),
5535 );
5536 }
5537 }
5538 }
5539 }
5540 }
5541
5542 let space = self.spaces[SpaceId::Data].for_path(path_id);
5543 if space
5544 .pending_acks
5545 .packet_received(now, number, ack_eliciting, &space.dedup)
5546 {
5547 if self.abandoned_paths.contains(&path_id) {
5548 space.pending_acks.set_immediate_ack_required();
5551 } else {
5552 self.timers.set(
5553 Timer::PerPath(path_id, PathTimer::MaxAckDelay),
5554 now + self.ack_frequency.max_ack_delay,
5555 self.qlog.with_time(now),
5556 );
5557 }
5558 }
5559
5560 let pending = &mut self.spaces[SpaceId::Data].pending;
5565 self.streams.queue_max_stream_id(pending);
5566
5567 if let Some(reason) = close {
5568 self.state
5569 .move_to_draining(Some(reason.into()), &mut self.endpoint_events);
5570 self.connection_close_pending = true;
5571 }
5572
5573 let migrate_on_any_packet =
5576 self.is_multipath_negotiated() && !self.n0_nat_traversal.is_negotiated();
5577
5578 let is_largest_received_pn = Some(number)
5580 == self.spaces[SpaceId::Data]
5581 .for_path(path_id)
5582 .largest_received_packet_number;
5583
5584 if (migrate_on_any_packet || !is_probing_packet)
5589 && is_largest_received_pn
5590 && self.local_ip_may_migrate()
5591 && let Some(new_local_ip) = network_path.local_ip
5592 {
5593 let path_data = self.path_data_mut(path_id);
5594 if path_data
5595 .network_path
5596 .local_ip
5597 .is_some_and(|ip| ip != new_local_ip)
5598 {
5599 debug!(
5600 %path_id,
5601 new_4tuple = %network_path,
5602 prev_4tuple = %path_data.network_path,
5603 "local address passive migration"
5604 );
5605 }
5606 path_data.network_path.local_ip = Some(new_local_ip)
5607 }
5608
5609 if self.peer_may_migrate()
5611 && (migrate_on_any_packet || !is_probing_packet)
5612 && is_largest_received_pn
5613 && network_path.remote != self.path_data(path_id).network_path.remote
5614 {
5615 self.migrate(path_id, now, network_path, migration_observed_addr);
5616 self.update_remote_cid(path_id);
5618 self.spin = false;
5619 }
5620
5621 Ok(())
5622 }
5623
5624 fn handle_path_response_on_path(
5628 &mut self,
5629 now: Instant,
5630 response: frame::PathResponse,
5631 path_id: PathId,
5632 ) {
5633 let is_multipath_negotiated = self.is_multipath_negotiated();
5634 let path = self
5635 .paths
5636 .get_mut(&path_id)
5637 .expect("payload is processed only after the path becomes known");
5638 match path.data.on_path_response_received(now, response.0) {
5639 paths::OnPathResponseReceived::OnPath if !self.abandoned_paths.contains(&path_id) => {
5640 let qlog = self.qlog.with_time(now);
5641 self.timers.stop(
5642 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5643 qlog.clone(),
5644 );
5645 let next_challenge = path
5646 .data
5647 .earliest_on_path_expiring_challenge()
5648 .map(|time| time + self.ack_frequency.max_ack_delay_for_pto());
5649 self.timers.set_or_stop(
5650 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
5651 next_challenge,
5652 qlog,
5653 );
5654 let pns = self.spaces[SpaceKind::Data].for_path(path_id);
5655 if !matches!(pns.open_status, OpenStatus::Informed) {
5656 if is_multipath_negotiated {
5657 self.events
5658 .push_back(Event::Path(PathEvent::Established { id: path_id }));
5659 }
5660 pns.open_status = OpenStatus::Informed;
5661 if let Some(observed) = path.data.last_observed_addr_report.as_ref() {
5662 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5663 id: path_id,
5664 addr: observed.socket_addr(),
5665 }));
5666 }
5667 }
5668 if let Some((_, ref mut prev)) = path.prev {
5669 prev.reset_on_path_challenges();
5674 }
5675 }
5676 paths::OnPathResponseReceived::OnPath => {
5677 trace!(
5678 %response,
5679 "ignoring PATH_RESPONSE received after path is abandoned"
5680 );
5681 }
5682 paths::OnPathResponseReceived::Unknown => {
5683 debug!(%response, "ignoring invalid PATH_RESPONSE");
5684 }
5685 paths::OnPathResponseReceived::Ignored {
5686 sent_on,
5687 current_path,
5688 } => {
5689 debug!(%sent_on, %current_path, %response, "ignoring valid PATH_RESPONSE");
5690 }
5691 }
5692 }
5693
5694 fn open_nat_traversed_paths(&mut self, now: Instant) {
5696 while let Some(network_path) = self
5697 .n0_nat_traversal
5698 .client_side_mut()
5699 .ok()
5700 .and_then(|s| s.pop_pending_path_open())
5701 {
5702 match self.open_path_ensure(network_path, PathStatus::Backup, now) {
5703 Ok((path_id, already_existed)) => {
5704 debug!(
5705 %path_id,
5706 ?network_path,
5707 new_path = !already_existed,
5708 "Opened NAT traversal path",
5709 );
5710 }
5711 Err(err) => match err {
5712 PathError::MultipathNotNegotiated
5713 | PathError::ServerSideNotAllowed
5714 | PathError::ValidationFailed
5715 | PathError::InvalidRemoteAddress(_) => {
5716 error!(
5717 ?err,
5718 ?network_path,
5719 "Failed to open path for successful NAT traversal"
5720 );
5721 }
5722 PathError::MaxPathIdReached | PathError::RemoteCidsExhausted => {
5723 self.n0_nat_traversal
5725 .client_side_mut()
5726 .map(|s| s.push_pending_path_open(network_path))
5727 .ok();
5728 debug!(
5729 ?err,
5730 ?network_path,
5731 "Blocked opening NAT traversal path, enqueued"
5732 );
5733 return;
5734 }
5735 },
5736 }
5737 }
5738 }
5739
5740 fn migrate(
5745 &mut self,
5746 path_id: PathId,
5747 now: Instant,
5748 network_path: FourTuple,
5749 observed_addr: Option<ObservedAddr>,
5750 ) {
5751 trace!(
5752 new_4tuple = %network_path,
5753 prev_4tuple = %self.path_data(path_id).network_path,
5754 %path_id,
5755 "migration initiated",
5756 );
5757 self.path_generation_counter = self.path_generation_counter.wrapping_add(1);
5758 let prev_pto = self.pto(SpaceKind::Data, path_id);
5765 let path = self.paths.get_mut(&path_id).expect("known path");
5766 let mut new_path_data = if network_path.remote.is_ipv4()
5767 && network_path.remote.ip() == path.data.network_path.remote.ip()
5768 {
5769 PathData::from_previous(network_path, &path.data, self.path_generation_counter, now)
5770 } else {
5771 let peer_max_udp_payload_size =
5772 u16::try_from(self.peer_params.max_udp_payload_size.into_inner())
5773 .unwrap_or(u16::MAX);
5774 PathData::new(
5775 network_path,
5776 self.allow_mtud,
5777 Some(peer_max_udp_payload_size),
5778 self.path_generation_counter,
5779 now,
5780 &self.config,
5781 )
5782 };
5783 new_path_data.last_observed_addr_report = path.data.last_observed_addr_report.clone();
5784 if let Some(report) = observed_addr
5785 && let Some(updated) = new_path_data.update_observed_addr_report(report)
5786 {
5787 tracing::info!("adding observed addr event from migration");
5788 self.events.push_back(Event::Path(PathEvent::ObservedAddr {
5789 id: path_id,
5790 addr: updated,
5791 }));
5792 }
5793 new_path_data.pending_challenge = true;
5794 new_path_data.pending.observed_address = self
5795 .config
5796 .address_discovery_role
5797 .should_report(&self.peer_params.address_discovery_role);
5798
5799 let mut prev_path_data = mem::replace(&mut path.data, new_path_data);
5800
5801 if !prev_path_data.validated
5810 && let Some(cid) = self.remote_cids.get(&path_id).map(CidQueue::active)
5811 {
5812 prev_path_data.pending_challenge = true;
5813 path.prev = Some((cid, prev_path_data));
5816 }
5817
5818 self.qlog.emit_tuple_assigned(path_id, network_path, now);
5820
5821 self.timers.set(
5822 Timer::PerPath(path_id, PathTimer::PathValidationFailed),
5823 now + 3 * cmp::max(self.pto(SpaceKind::Data, path_id), prev_pto),
5824 self.qlog.with_time(now),
5825 );
5826 }
5827
5828 pub fn handle_network_change(&mut self, hint: Option<&dyn NetworkChangeHint>, now: Instant) {
5845 debug!("network changed");
5846 if self.state.is_drained() {
5847 return;
5848 }
5849 if self.highest_space < SpaceKind::Data {
5850 for path in self.paths.values_mut() {
5851 path.data.network_path.local_ip = None;
5853 }
5854
5855 self.update_remote_cid(PathId::ZERO);
5856 self.ping();
5857
5858 return;
5859 }
5860
5861 let mut non_recoverable_paths = Vec::default();
5864 let mut recoverable_paths = Vec::default();
5865 let mut open_paths = 0;
5866
5867 let is_multipath_negotiated = self.is_multipath_negotiated();
5868 let is_client = self.side().is_client();
5869 let immediate_ack_allowed = self.peer_supports_ack_frequency();
5870
5871 for (path_id, path) in self.paths.iter_mut() {
5872 if self.abandoned_paths.contains(path_id) {
5873 continue;
5874 }
5875 open_paths += 1;
5876
5877 let network_path = path.data.network_path;
5880
5881 path.data.network_path.local_ip = None;
5884 let remote = network_path.remote;
5885
5886 let attempt_to_recover = if is_multipath_negotiated {
5890 hint.map(|h| h.is_path_recoverable(*path_id, network_path))
5894 .unwrap_or(!is_client)
5895 } else {
5896 true
5898 };
5899
5900 if attempt_to_recover {
5901 recoverable_paths.push((*path_id, remote));
5902 } else {
5903 non_recoverable_paths.push((*path_id, remote, path.data.local_status()))
5904 }
5905 }
5906
5907 let open_first = open_paths == non_recoverable_paths.len();
5916
5917 for (path_id, remote, status) in non_recoverable_paths.into_iter() {
5918 let network_path = FourTuple {
5919 remote,
5920 local_ip: None, };
5922
5923 if open_first && let Err(e) = self.open_path(network_path, status, now) {
5924 if self.side().is_client() {
5925 debug!(%e, "Failed to open new path for network change");
5926 }
5927 recoverable_paths.push((path_id, remote));
5929 continue;
5930 }
5931
5932 if let Err(e) =
5933 self.close_path_inner(now, path_id, PathAbandonReason::UnusableAfterNetworkChange)
5934 {
5935 debug!(%e,"Failed to close unrecoverable path after network change");
5936 recoverable_paths.push((path_id, remote));
5937 continue;
5938 }
5939
5940 if !open_first && let Err(e) = self.open_path(network_path, status, now) {
5941 debug!(%e,"Failed to open new path for network change");
5945 }
5946 }
5947
5948 for (path_id, remote) in recoverable_paths.into_iter() {
5951 if let Some(path_space) = self.spaces[SpaceId::Data].number_spaces.get_mut(&path_id) {
5953 path_space.pending_ping = true;
5954
5955 if immediate_ack_allowed {
5956 path_space.pending_immediate_ack = true;
5957 }
5958 }
5959
5960 if let Some(path) = self.paths.get_mut(&path_id) {
5965 path.data.pto_count = 0;
5966 }
5967 self.set_loss_detection_timer(now, path_id);
5968
5969 let Some((reset_token, retired)) =
5970 self.remote_cids.get_mut(&path_id).and_then(CidQueue::next)
5971 else {
5972 continue;
5973 };
5974
5975 self.spaces[SpaceId::Data]
5977 .pending
5978 .retire_cids
5979 .extend(retired.map(|seq| (path_id, seq)));
5980
5981 debug_assert!(!self.state.is_drained()); self.endpoint_events
5983 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
5984 }
5985 }
5986
5987 fn update_remote_cid(&mut self, path_id: PathId) {
5989 let Some((reset_token, retired)) = self
5990 .remote_cids
5991 .get_mut(&path_id)
5992 .and_then(|cids| cids.next())
5993 else {
5994 return;
5995 };
5996
5997 self.spaces[SpaceId::Data]
5999 .pending
6000 .retire_cids
6001 .extend(retired.map(|seq| (path_id, seq)));
6002 let remote = self.path_data(path_id).network_path.remote;
6003 self.set_reset_token(path_id, remote, reset_token);
6004 }
6005
6006 fn set_reset_token(&mut self, path_id: PathId, remote: SocketAddr, reset_token: ResetToken) {
6015 debug_assert!(!self.state.is_drained()); self.endpoint_events
6017 .push_back(EndpointEventInner::ResetToken(path_id, remote, reset_token));
6018
6019 if path_id == PathId::ZERO {
6025 self.peer_params.stateless_reset_token = Some(reset_token);
6026 }
6027 }
6028
6029 fn issue_first_cids(&mut self, now: Instant) {
6031 if self
6032 .local_cid_state
6033 .get(&PathId::ZERO)
6034 .expect("PathId::ZERO exists when the connection is created")
6035 .cid_len()
6036 == 0
6037 {
6038 return;
6039 }
6040
6041 let mut n = self.peer_params.issue_cids_limit() - 1;
6043 if let ConnectionSide::Server { server_config } = &self.side
6044 && server_config.has_preferred_address()
6045 {
6046 n -= 1;
6048 }
6049 debug_assert!(!self.state.is_drained()); self.endpoint_events
6051 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6052 }
6053
6054 fn issue_first_path_cids(&mut self, now: Instant) {
6058 if let Some(max_path_id) = self.max_path_id() {
6059 let mut path_id = self.max_path_id_with_cids.next();
6060 while path_id <= max_path_id {
6061 self.endpoint_events
6062 .push_back(EndpointEventInner::NeedIdentifiers(
6063 path_id,
6064 now,
6065 self.peer_params.issue_cids_limit(),
6066 ));
6067 path_id = path_id.next();
6068 }
6069 self.max_path_id_with_cids = max_path_id;
6070 }
6071 }
6072
6073 fn populate_packet<'a, 'b>(
6081 &mut self,
6082 now: Instant,
6083 space_id: SpaceId,
6084 path_id: PathId,
6085 scheduling_info: &PathSchedulingInfo,
6086 builder: &mut PacketBuilder<'a, 'b>,
6087 ) {
6088 let is_multipath_negotiated = self.is_multipath_negotiated();
6089 let space_has_keys = self.crypto_state.has_keys(space_id.encryption_level());
6090 let is_0rtt = space_id == SpaceId::Data && !space_has_keys;
6091 let stats = &mut self.path_stats.get_mut(path_id).frame_tx;
6092 let space = &mut self.spaces[space_id];
6093 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6094 space
6095 .for_path(path_id)
6096 .pending_acks
6097 .maybe_ack_non_eliciting();
6098
6099 if !is_0rtt
6101 && !scheduling_info.is_abandoned
6102 && scheduling_info.may_send_data
6103 && mem::replace(&mut space.pending.handshake_done, false)
6104 {
6105 builder.write_frame(frame::HandshakeDone, stats);
6106 }
6107
6108 if !scheduling_info.is_abandoned
6110 && mem::replace(&mut space.for_path(path_id).pending_ping, false)
6111 {
6112 builder.write_frame(frame::Ping, stats);
6113 }
6114
6115 if !scheduling_info.is_abandoned
6117 && mem::replace(&mut space.for_path(path_id).pending_immediate_ack, false)
6118 {
6119 debug_assert_eq!(
6120 space_id,
6121 SpaceId::Data,
6122 "immediate acks must be sent in the data space"
6123 );
6124 builder.write_frame(frame::ImmediateAck, stats);
6125 }
6126
6127 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6129 for path_id in space
6130 .number_spaces
6131 .iter_mut()
6132 .filter(|(_, pns)| pns.pending_acks.can_send())
6133 .map(|(&path_id, _)| path_id)
6134 .collect::<Vec<_>>()
6135 {
6136 Self::populate_acks(
6137 now,
6138 self.receiving_ecn,
6139 path_id,
6140 space_id,
6141 space,
6142 is_multipath_negotiated,
6143 builder,
6144 stats,
6145 space_has_keys,
6146 );
6147 }
6148 }
6149
6150 if !scheduling_info.is_abandoned
6152 && scheduling_info.may_send_data
6153 && mem::replace(&mut space.pending.ack_frequency, false)
6154 {
6155 let sequence_number = self.ack_frequency.next_sequence_number();
6156
6157 let config = self.config.ack_frequency_config.as_ref().unwrap();
6159
6160 let max_ack_delay = self.ack_frequency.candidate_max_ack_delay(
6162 path.rtt.get(),
6163 config,
6164 &self.peer_params,
6165 );
6166
6167 let frame = frame::AckFrequency {
6168 sequence: sequence_number,
6169 ack_eliciting_threshold: config.ack_eliciting_threshold,
6170 request_max_ack_delay: max_ack_delay.as_micros().try_into().unwrap_or(VarInt::MAX),
6171 reordering_threshold: config.reordering_threshold,
6172 };
6173 builder.write_frame(frame, stats);
6174
6175 self.ack_frequency
6176 .ack_frequency_sent(path_id, builder.packet_number, max_ack_delay);
6177 path.congestion.on_ack_frequency_update(
6178 config.ack_eliciting_threshold.into_inner(),
6179 max_ack_delay,
6180 );
6181 }
6182
6183 if !scheduling_info.is_abandoned
6185 && space_id == SpaceId::Data
6186 && path.pending_challenge
6187 && !self.state.is_closed()
6189 && builder.frame_space_remaining() > frame::PathChallenge::SIZE_BOUND
6190 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6193 {
6194 path.pending_challenge = false;
6195
6196 let token = self.rng.random();
6197 path.record_path_challenge_sent(now, token, path.network_path);
6198 let challenge = frame::PathChallenge(token);
6200 builder.write_frame(challenge, stats);
6201 builder.require_padding();
6202
6203 self.timers.set(
6208 Timer::PerPath(path_id, PathTimer::PathChallengeLost),
6209 now + path.on_path_challenge_pto(),
6210 self.qlog.with_time(now),
6211 );
6212
6213 if is_multipath_negotiated && !path.validated && path.pending_challenge {
6214 space.pending.path_status.insert(path_id);
6216 }
6217
6218 path.pending.observed_address = self
6221 .config
6222 .address_discovery_role
6223 .should_report(&self.peer_params.address_discovery_role);
6224 }
6225
6226 if !scheduling_info.is_abandoned
6228 && space_id == SpaceId::Data
6229 && builder.frame_space_remaining() > frame::PathResponse::SIZE_BOUND
6230 && builder.buf.segment_size() >= usize::from(MIN_INITIAL_SIZE)
6233 && let Some(token) = space.for_path(path_id).pending_path_responses.pop_on_path(path.network_path)
6234 {
6235 let response = frame::PathResponse(token);
6236 builder.write_frame(response, stats);
6237 builder.require_padding();
6238
6239 path.pending.observed_address = self
6243 .config
6244 .address_discovery_role
6245 .should_report(&self.peer_params.address_discovery_role);
6246 }
6247
6248 while space_id == SpaceId::Data
6250 && !scheduling_info.is_abandoned
6251 && scheduling_info.may_send_data
6252 && frame::AddAddress::SIZE_BOUND <= builder.frame_space_remaining()
6253 {
6254 if let Some(added_address) = space.pending.add_address.pop_last() {
6255 builder.write_frame(added_address, stats);
6256 } else {
6257 break;
6258 }
6259 }
6260
6261 while space_id == SpaceId::Data
6263 && !scheduling_info.is_abandoned
6264 && scheduling_info.may_send_data
6265 && frame::RemoveAddress::SIZE_BOUND <= builder.frame_space_remaining()
6266 {
6267 if let Some(removed_address) = space.pending.remove_address.pop_last() {
6268 builder.write_frame(removed_address, stats);
6269 } else {
6270 break;
6271 }
6272 }
6273
6274 while !scheduling_info.is_abandoned
6276 && scheduling_info.may_send_data
6277 && let Some(reach_out) = space
6278 .pending
6279 .reach_out
6280 .pop_if(|frame| builder.frame_space_remaining() >= frame.size())
6281 {
6282 builder.write_frame(reach_out, stats);
6283 }
6284
6285 if space_id == SpaceId::Data
6287 && scheduling_info.is_abandoned
6288 && scheduling_info.may_self_abandon
6289 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6290 && let Some(error_code) = space.pending.path_abandon.remove(&path_id)
6291 {
6292 let frame = frame::PathAbandon {
6293 path_id,
6294 error_code,
6295 };
6296 builder.write_frame(frame, stats);
6297
6298 self.remote_cids.remove(&path_id);
6301 }
6302 while space_id == SpaceId::Data
6303 && scheduling_info.may_send_data
6304 && frame::PathAbandon::SIZE_BOUND <= builder.frame_space_remaining()
6305 && let Some((abandoned_path_id, error_code)) = space.pending.path_abandon.pop_first()
6306 {
6307 let frame = frame::PathAbandon {
6308 path_id: abandoned_path_id,
6309 error_code,
6310 };
6311 builder.write_frame(frame, stats);
6312
6313 self.remote_cids.remove(&abandoned_path_id);
6316 }
6317
6318 if !scheduling_info.is_abandoned
6320 && space_id == SpaceId::Data
6321 && path.pending.observed_address
6322 {
6323 let frame = ObservedAddr::new(path.network_path.remote, self.next_observed_addr_seq_no);
6324 if builder.frame_space_remaining() > frame.size() {
6325 builder.write_frame(frame, stats);
6326
6327 self.next_observed_addr_seq_no = self.next_observed_addr_seq_no.saturating_add(1u8);
6328 path.pending.observed_address = false;
6329 }
6330 }
6331
6332 while !is_0rtt
6334 && !scheduling_info.is_abandoned
6335 && scheduling_info.may_send_data
6336 && builder.frame_space_remaining() > frame::Crypto::SIZE_BOUND
6337 {
6338 let Some(mut frame) = space.pending.crypto.pop_front() else {
6339 break;
6340 };
6341
6342 let max_crypto_data_size = builder.frame_space_remaining()
6347 - 1 - VarInt::size(unsafe { VarInt::from_u64_unchecked(frame.offset) })
6349 - 2; let len = frame
6352 .data
6353 .len()
6354 .min(2usize.pow(14) - 1)
6355 .min(max_crypto_data_size);
6356
6357 let data = frame.data.split_to(len);
6358 let offset = frame.offset;
6359 let truncated = frame::Crypto { offset, data };
6360 builder.write_frame(truncated, stats);
6361
6362 if !frame.data.is_empty() {
6363 frame.offset += len as u64;
6364 space.pending.crypto.push_front(frame);
6365 }
6366 }
6367
6368 while space_id == SpaceId::Data
6370 && !scheduling_info.is_abandoned
6371 && scheduling_info.may_send_data
6372 && frame::PathStatusAvailable::SIZE_BOUND <= builder.frame_space_remaining()
6373 {
6374 let Some(path_id) = space.pending.path_status.pop_first() else {
6375 break;
6376 };
6377 let Some(path) = self.paths.get(&path_id).map(|path_state| &path_state.data) else {
6378 trace!(%path_id, "discarding queued path status for unknown path");
6379 continue;
6380 };
6381
6382 let seq = path.status.seq();
6383 match path.local_status() {
6384 PathStatus::Available => {
6385 let frame = frame::PathStatusAvailable {
6386 path_id,
6387 status_seq_no: seq,
6388 };
6389 builder.write_frame(frame, stats);
6390 }
6391 PathStatus::Backup => {
6392 let frame = frame::PathStatusBackup {
6393 path_id,
6394 status_seq_no: seq,
6395 };
6396 builder.write_frame(frame, stats);
6397 }
6398 }
6399 }
6400
6401 if space_id == SpaceId::Data
6403 && !scheduling_info.is_abandoned
6404 && scheduling_info.may_send_data
6405 && space.pending.max_path_id
6406 && frame::MaxPathId::SIZE_BOUND <= builder.frame_space_remaining()
6407 {
6408 let frame = frame::MaxPathId(self.local_max_path_id);
6409 builder.write_frame(frame, stats);
6410 space.pending.max_path_id = false;
6411 }
6412
6413 if space_id == SpaceId::Data
6415 && !scheduling_info.is_abandoned
6416 && scheduling_info.may_send_data
6417 && frame::PathsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6418 && let Some(remote_max_path_id) = space.pending.paths_blocked.take()
6419 {
6420 let frame = frame::PathsBlocked(remote_max_path_id);
6421 builder.write_frame(frame, stats);
6422 }
6423
6424 while space_id == SpaceId::Data
6426 && !scheduling_info.is_abandoned
6427 && scheduling_info.may_send_data
6428 && frame::PathCidsBlocked::SIZE_BOUND <= builder.frame_space_remaining()
6429 {
6430 let Some((path_id, next_seq)) = space.pending.path_cids_blocked.pop_first() else {
6431 break;
6432 };
6433 let frame = frame::PathCidsBlocked { path_id, next_seq };
6434 builder.write_frame(frame, stats);
6435 }
6436
6437 if space_id == SpaceId::Data
6439 && !scheduling_info.is_abandoned
6440 && scheduling_info.may_send_data
6441 {
6442 self.streams
6443 .write_control_frames(builder, &mut space.pending, stats);
6444 }
6445
6446 let cid_len = self
6448 .local_cid_state
6449 .values()
6450 .map(|cid_state| cid_state.cid_len())
6451 .max()
6452 .expect("some local CID state must exist");
6453 let new_cid_size_bound =
6454 frame::NewConnectionId::size_bound(is_multipath_negotiated, cid_len);
6455 while !scheduling_info.is_abandoned
6456 && scheduling_info.may_send_data
6457 && builder.frame_space_remaining() > new_cid_size_bound
6458 {
6459 let Some(issued) = space.pending.new_cids.pop() else {
6460 break;
6461 };
6462 let Some(cid_state) = self.local_cid_state.get(&issued.path_id) else {
6464 debug!(
6465 path = %issued.path_id, seq = issued.sequence,
6466 "dropping queued NEW_CONNECTION_ID for discarded path",
6467 );
6468 continue;
6469 };
6470 let retire_prior_to = cid_state.retire_prior_to();
6471
6472 let cid_path_id = match is_multipath_negotiated {
6473 true => Some(issued.path_id),
6474 false => {
6475 debug_assert_eq!(issued.path_id, PathId::ZERO);
6476 None
6477 }
6478 };
6479 let frame = frame::NewConnectionId {
6480 path_id: cid_path_id,
6481 sequence: issued.sequence,
6482 retire_prior_to,
6483 id: issued.id,
6484 reset_token: issued.reset_token,
6485 };
6486 builder.write_frame(frame, stats);
6487 }
6488
6489 let retire_cid_bound = frame::RetireConnectionId::size_bound(is_multipath_negotiated);
6491 while !scheduling_info.is_abandoned
6492 && scheduling_info.may_send_data
6493 && builder.frame_space_remaining() > retire_cid_bound
6494 {
6495 let (path_id, sequence) = match space.pending.retire_cids.pop() {
6496 Some((PathId::ZERO, seq)) if !is_multipath_negotiated => (None, seq),
6497 Some((path_id, seq)) => (Some(path_id), seq),
6498 None => break,
6499 };
6500 let frame = frame::RetireConnectionId { path_id, sequence };
6501 builder.write_frame(frame, stats);
6502 }
6503
6504 let mut sent_datagrams = false;
6506 while !scheduling_info.is_abandoned
6507 && scheduling_info.may_send_data
6508 && builder.frame_space_remaining() > Datagram::SIZE_BOUND
6509 && space_id == SpaceId::Data
6510 {
6511 match self.datagrams.write(builder, stats) {
6512 true => {
6513 sent_datagrams = true;
6514 }
6515 false => break,
6516 }
6517 }
6518 if self.datagrams.send_blocked && sent_datagrams {
6519 self.events.push_back(Event::DatagramsUnblocked);
6520 self.datagrams.send_blocked = false;
6521 }
6522
6523 let path = &mut self.paths.get_mut(&path_id).expect("known path").data;
6524
6525 if !scheduling_info.is_abandoned && scheduling_info.may_send_data {
6527 while let Some(network_path) = space.pending.new_tokens.pop() {
6528 debug_assert_eq!(space_id, SpaceId::Data);
6529 let ConnectionSide::Server { server_config } = &self.side else {
6530 panic!("NEW_TOKEN frames should not be enqueued by clients");
6531 };
6532
6533 if !network_path.is_probably_same_path(&path.network_path) {
6534 continue;
6539 }
6540
6541 let token = Token::new(
6542 TokenPayload::Validation {
6543 ip: network_path.remote.ip(),
6544 issued: server_config.time_source.now(),
6545 },
6546 &mut self.rng,
6547 );
6548 let new_token = NewToken {
6549 token: token.encode(&*server_config.token_key).into(),
6550 };
6551
6552 if builder.frame_space_remaining() < new_token.size() {
6553 space.pending.new_tokens.push(network_path);
6554 break;
6555 }
6556
6557 builder.write_frame(new_token, stats);
6558 builder.retransmits_mut().new_tokens.push(network_path);
6559 }
6560 }
6561
6562 if !scheduling_info.is_abandoned
6564 && scheduling_info.may_send_data
6565 && space_id == SpaceId::Data
6566 {
6567 self.streams
6568 .write_stream_frames(builder, self.config.send_fairness, stats);
6569 }
6570 }
6571
6572 fn populate_acks<'a, 'b>(
6574 now: Instant,
6575 receiving_ecn: bool,
6576 path_id: PathId,
6577 space_id: SpaceId,
6578 space: &mut PacketSpace,
6579 is_multipath_negotiated: bool,
6580 builder: &mut PacketBuilder<'a, 'b>,
6581 stats: &mut FrameStats,
6582 space_has_keys: bool,
6583 ) {
6584 debug_assert!(space_has_keys, "tried to send ACK in 0-RTT");
6586
6587 debug_assert!(
6588 is_multipath_negotiated || path_id == PathId::ZERO,
6589 "Only PathId::ZERO allowed without multipath (have {path_id:?})"
6590 );
6591 if is_multipath_negotiated {
6592 debug_assert!(
6593 space_id == SpaceId::Data || path_id == PathId::ZERO,
6594 "path acks must be sent in 1RTT space (have {space_id:?})"
6595 );
6596 }
6597
6598 let pns = space.for_path(path_id);
6599 let ranges = pns.pending_acks.ranges();
6600 debug_assert!(!ranges.is_empty(), "can not send empty ACK range");
6601 let ecn = if receiving_ecn {
6602 Some(&pns.ecn_counters)
6603 } else {
6604 None
6605 };
6606
6607 let delay_micros = pns.pending_acks.ack_delay(now).as_micros() as u64;
6608 let ack_delay_exp = TransportParameters::default().ack_delay_exponent;
6610 let delay = delay_micros >> ack_delay_exp.into_inner();
6611
6612 if is_multipath_negotiated && space_id == SpaceId::Data {
6613 if !ranges.is_empty() {
6614 let frame = frame::PathAck::encoder(path_id, delay, ranges, ecn);
6615 builder.write_frame(frame, stats);
6616 }
6617 } else {
6618 builder.write_frame(frame::Ack::encoder(delay, ranges, ecn), stats);
6619 }
6620 }
6621
6622 fn close_common(&mut self) {
6623 trace!("connection closed");
6624 self.timers.reset();
6625 }
6626
6627 fn set_close_timer(&mut self, now: Instant) {
6628 let pto_max = self.max_pto_for_space(self.highest_space);
6631 self.timers.set(
6632 Timer::Conn(ConnTimer::Close),
6633 now + 3 * pto_max,
6634 self.qlog.with_time(now),
6635 );
6636 }
6637
6638 fn handle_peer_params(
6643 &mut self,
6644 params: TransportParameters,
6645 local_cid: ConnectionId,
6646 remote_cid: ConnectionId,
6647 now: Instant,
6648 ) -> Result<(), TransportError> {
6649 if Some(self.original_remote_cid) != params.initial_src_cid
6650 || (self.side.is_client()
6651 && (Some(self.initial_dst_cid) != params.original_dst_cid
6652 || self.retry_src_cid != params.retry_src_cid))
6653 {
6654 return Err(TransportError::TRANSPORT_PARAMETER_ERROR(
6655 "CID authentication failure",
6656 ));
6657 }
6658 if params.initial_max_path_id.is_some() && (local_cid.is_empty() || remote_cid.is_empty()) {
6659 return Err(TransportError::PROTOCOL_VIOLATION(
6660 "multipath must not use zero-length CIDs",
6661 ));
6662 }
6663
6664 self.set_peer_params(params);
6665 self.qlog.emit_peer_transport_params_received(self, now);
6666
6667 Ok(())
6668 }
6669
6670 fn set_peer_params(&mut self, params: TransportParameters) {
6671 self.streams.set_params(¶ms);
6672 self.idle_timeout =
6673 negotiate_max_idle_timeout(self.config.max_idle_timeout, Some(params.max_idle_timeout));
6674 trace!("negotiated max idle timeout {:?}", self.idle_timeout);
6675
6676 if let Some(ref info) = params.preferred_address {
6677 self.remote_cids.get_mut(&PathId::ZERO).expect("not yet abandoned").insert(frame::NewConnectionId {
6679 path_id: None,
6680 sequence: 1,
6681 id: info.connection_id,
6682 reset_token: info.stateless_reset_token,
6683 retire_prior_to: 0,
6684 })
6685 .expect(
6686 "preferred address CID is the first received, and hence is guaranteed to be legal",
6687 );
6688 let remote = self.path_data(PathId::ZERO).network_path.remote;
6689 self.set_reset_token(PathId::ZERO, remote, info.stateless_reset_token);
6690 }
6691 self.ack_frequency.peer_max_ack_delay = get_max_ack_delay(¶ms);
6692
6693 let mut multipath_enabled = false;
6694 if let (Some(local_max_path_id), Some(remote_max_path_id)) = (
6695 self.config.get_initial_max_path_id(),
6696 params.initial_max_path_id,
6697 ) {
6698 self.local_max_path_id = local_max_path_id;
6700 self.remote_max_path_id = remote_max_path_id;
6701 let initial_max_path_id = local_max_path_id.min(remote_max_path_id);
6702 debug!(%initial_max_path_id, "multipath negotiated");
6703 multipath_enabled = true;
6704 }
6705
6706 if let Some((max_locally_allowed_remote_addresses, max_remotely_allowed_remote_addresses)) =
6707 self.config
6708 .max_remote_nat_traversal_addresses
6709 .zip(params.max_remote_nat_traversal_addresses)
6710 {
6711 if multipath_enabled {
6712 let max_local_addresses = max_remotely_allowed_remote_addresses.get();
6713 let max_remote_addresses = max_locally_allowed_remote_addresses.get();
6714 self.n0_nat_traversal = n0_nat_traversal::State::new(
6715 max_remote_addresses,
6716 max_local_addresses,
6717 self.side(),
6718 );
6719 debug!(
6720 %max_remote_addresses, %max_local_addresses,
6721 "n0's nat traversal negotiated"
6722 );
6723 } else {
6724 debug!("n0 nat traversal enabled for both endpoints, but multipath is missing")
6725 }
6726 }
6727
6728 self.peer_params = params;
6729 let peer_max_udp_payload_size =
6730 u16::try_from(self.peer_params.max_udp_payload_size.into_inner()).unwrap_or(u16::MAX);
6731 let address_discovery_negotiated = self
6732 .config
6733 .address_discovery_role
6734 .should_report(&self.peer_params.address_discovery_role);
6735
6736 let path = self.path_data_mut(PathId::ZERO);
6737 path.pending.observed_address = address_discovery_negotiated;
6738 path.mtud
6739 .on_peer_max_udp_payload_size_received(peer_max_udp_payload_size);
6740 }
6741
6742 fn decrypt_packet(
6744 &mut self,
6745 now: Instant,
6746 path_id: PathId,
6747 packet: &mut Packet,
6748 ) -> Result<Option<u64>, Option<TransportError>> {
6749 let result = self
6750 .crypto_state
6751 .decrypt_packet_body(packet, path_id, &self.spaces)?;
6752
6753 let Some(result) = result else {
6754 return Ok(None);
6755 };
6756
6757 if result.outgoing_key_update_acked
6758 && let Some(prev) = self.crypto_state.prev_crypto.as_mut()
6759 {
6760 prev.end_packet = Some((result.packet_number, now));
6761 self.set_key_discard_timer(now, packet.header.space());
6762 }
6763
6764 if result.incoming_key_update {
6765 trace!("key update authenticated");
6766 self.crypto_state
6767 .update_keys(Some((result.packet_number, now)), true);
6768 self.set_key_discard_timer(now, packet.header.space());
6769 }
6770
6771 Ok(Some(result.packet_number))
6772 }
6773
6774 fn peer_supports_ack_frequency(&self) -> bool {
6775 self.peer_params.min_ack_delay.is_some()
6776 }
6777
6778 pub(crate) fn immediate_ack(&mut self, path_id: PathId) {
6783 debug_assert_eq!(
6784 self.highest_space,
6785 SpaceKind::Data,
6786 "immediate ack must be written in the data space"
6787 );
6788 self.spaces[SpaceId::Data]
6789 .for_path(path_id)
6790 .pending_immediate_ack = true;
6791 }
6792
6793 #[cfg(test)]
6795 pub(crate) fn decode_packet(&self, event: &ConnectionEvent) -> Option<Vec<u8>> {
6796 let ConnectionEventInner::Datagram(DatagramConnectionEvent {
6797 path_id,
6798 first_decode,
6799 remaining,
6800 ..
6801 }) = &event.0
6802 else {
6803 return None;
6804 };
6805
6806 if remaining.is_some() {
6807 panic!("Packets should never be coalesced in tests");
6808 }
6809
6810 let decrypted_header = self
6811 .crypto_state
6812 .unprotect_header(first_decode.clone(), self.peer_params.stateless_reset_token)?;
6813
6814 let mut packet = decrypted_header.packet?;
6815 self.crypto_state
6816 .decrypt_packet_body(&mut packet, *path_id, &self.spaces)
6817 .ok()?;
6818
6819 Some(packet.payload.to_vec())
6820 }
6821
6822 #[cfg(test)]
6825 pub(crate) fn bytes_in_flight(&self) -> u64 {
6826 self.path_data(PathId::ZERO).in_flight.bytes
6828 }
6829
6830 #[cfg(test)]
6832 pub(crate) fn congestion_window(&self) -> u64 {
6833 let path = self.path_data(PathId::ZERO);
6834 path.congestion
6835 .window()
6836 .saturating_sub(path.in_flight.bytes)
6837 }
6838
6839 #[cfg(test)]
6841 pub(crate) fn is_idle(&self) -> bool {
6842 let current_timers = self.timers.values();
6843 current_timers
6844 .into_iter()
6845 .filter(|(timer, _)| {
6846 !matches!(
6847 timer,
6848 Timer::Conn(ConnTimer::KeepAlive)
6849 | Timer::PerPath(_, PathTimer::PathKeepAlive)
6850 | Timer::Conn(ConnTimer::PushNewCid)
6851 | Timer::Conn(ConnTimer::KeyDiscard)
6852 )
6853 })
6854 .min_by_key(|(_, time)| *time)
6855 .is_none_or(|(timer, _)| {
6856 matches!(
6857 timer,
6858 Timer::Conn(ConnTimer::Idle) | Timer::PerPath(_, PathTimer::PathIdle)
6859 )
6860 })
6861 }
6862
6863 #[cfg(test)]
6865 pub(crate) fn using_ecn(&self) -> bool {
6866 self.path_data(PathId::ZERO).sending_ecn
6867 }
6868
6869 #[cfg(test)]
6871 pub(crate) fn total_recvd(&self) -> u64 {
6872 self.path_data(PathId::ZERO).total_recvd
6873 }
6874
6875 #[cfg(test)]
6876 pub(crate) fn active_local_cid_seq(&self) -> (u64, u64) {
6877 self.local_cid_state
6878 .get(&PathId::ZERO)
6879 .unwrap()
6880 .active_seq()
6881 }
6882
6883 #[cfg(test)]
6884 #[track_caller]
6885 pub(crate) fn active_local_path_cid_seq(&self, path_id: u32) -> (u64, u64) {
6886 self.local_cid_state
6887 .get(&PathId(path_id))
6888 .unwrap()
6889 .active_seq()
6890 }
6891
6892 #[cfg(test)]
6895 pub(crate) fn rotate_local_cid(&mut self, v: u64, now: Instant) {
6896 let n = self
6897 .local_cid_state
6898 .get_mut(&PathId::ZERO)
6899 .unwrap()
6900 .assign_retire_seq(v);
6901 debug_assert!(!self.state.is_drained()); self.endpoint_events
6903 .push_back(EndpointEventInner::NeedIdentifiers(PathId::ZERO, now, n));
6904 }
6905
6906 #[cfg(test)]
6908 pub(crate) fn active_remote_cid_seq(&self) -> u64 {
6909 self.remote_cids.get(&PathId::ZERO).unwrap().active_seq()
6910 }
6911
6912 #[cfg(test)]
6914 pub(crate) fn path_mtu(&self, path_id: PathId) -> u16 {
6915 self.path_data(path_id).current_mtu()
6916 }
6917
6918 #[cfg(test)]
6920 pub(crate) fn trigger_path_validation(&mut self) {
6921 for path in self.paths.values_mut() {
6922 path.data.pending_challenge = true;
6923 }
6924 }
6925
6926 #[cfg(test)]
6928 pub fn simulate_protocol_violation(&mut self, now: Instant) {
6929 if !self.state.is_closed() {
6930 self.state
6931 .move_to_closed(TransportError::PROTOCOL_VIOLATION("simulated violation"));
6932 self.close_common();
6933 if !self.state.is_drained() {
6934 self.set_close_timer(now);
6935 }
6936 self.connection_close_pending = true;
6937 }
6938 }
6939
6940 fn can_send_1rtt(&self, path_id: PathId, max_size: usize) -> SendableFrames {
6951 let network_path = self.path_data(path_id).network_path;
6952 let space_specific = self
6953 .paths
6954 .get(&path_id)
6955 .is_some_and(|path| path.data.pending_challenge || !path.data.pending.is_empty())
6956 || self.spaces[SpaceKind::Data]
6957 .number_spaces
6958 .get(&path_id)
6959 .is_some_and(|pns| pns.pending_path_responses.has_pending_on_path(network_path));
6960
6961 let other = self.streams.can_send_stream_data()
6963 || self
6964 .datagrams
6965 .outgoing
6966 .front()
6967 .is_some_and(|x| x.size(true) <= max_size);
6968
6969 SendableFrames {
6971 acks: false,
6972 close: false,
6973 space_specific,
6974 other,
6975 }
6976 }
6977
6978 fn kill(&mut self, reason: ConnectionError) {
6980 self.close_common();
6981 self.state
6982 .move_to_drained(Some(reason), &mut self.endpoint_events);
6983 }
6984
6985 pub fn current_mtu(&self) -> u16 {
6992 self.paths
6993 .iter()
6994 .filter(|&(path_id, _path_state)| !self.abandoned_paths.contains(path_id))
6995 .map(|(_path_id, path_state)| path_state.data.current_mtu())
6996 .min()
6997 .unwrap_or(INITIAL_MTU)
6998 }
6999
7000 fn predict_1rtt_overhead(&mut self, pn: u64, path: PathId) -> usize {
7007 let pn_len = PacketNumber::new(
7008 pn,
7009 self.spaces[SpaceId::Data]
7010 .for_path(path)
7011 .largest_acked_packet_pn
7012 .unwrap_or(0),
7013 )
7014 .len();
7015
7016 1 + self
7018 .remote_cids
7019 .get(&path)
7020 .map(|cids| cids.active().len())
7021 .unwrap_or(20) + pn_len
7023 + self.tag_len_1rtt()
7024 }
7025
7026 fn predict_1rtt_overhead_no_pn(&self) -> usize {
7027 let pn_len = 4;
7028
7029 let cid_len = self
7030 .remote_cids
7031 .values()
7032 .map(|cids| cids.active().len())
7033 .max()
7034 .unwrap_or(20); 1 + cid_len + pn_len + self.tag_len_1rtt()
7038 }
7039
7040 fn tag_len_1rtt(&self) -> usize {
7041 let packet_crypto = self
7043 .crypto_state
7044 .encryption_keys(SpaceKind::Data, self.side.side())
7045 .map(|(_header, packet, _level)| packet);
7046 packet_crypto.map_or(16, |x| x.tag_len())
7050 }
7051
7052 fn on_path_validated(&mut self, path_id: PathId) {
7054 self.path_data_mut(path_id).validated = true;
7055 let ConnectionSide::Server { server_config } = &self.side else {
7056 return;
7057 };
7058 let network_path = self.path_data(path_id).network_path;
7059 let new_tokens = &mut self.spaces[SpaceId::Data as usize].pending.new_tokens;
7060 new_tokens.clear();
7061 for _ in 0..server_config.validation_token.sent {
7062 new_tokens.push(network_path);
7063 }
7064 }
7065
7066 fn on_path_status(&mut self, path_id: PathId, status: PathStatus, status_seq_no: VarInt) {
7068 if let Some(path) = self.paths.get_mut(&path_id) {
7069 path.data.status.remote_update(status, status_seq_no);
7070 } else {
7071 debug!("PATH_STATUS_AVAILABLE received unknown path {:?}", path_id);
7072 }
7073 self.events.push_back(
7074 PathEvent::RemoteStatus {
7075 id: path_id,
7076 status,
7077 }
7078 .into(),
7079 );
7080 }
7081
7082 fn max_path_id(&self) -> Option<PathId> {
7091 if self.is_multipath_negotiated() {
7092 Some(self.remote_max_path_id.min(self.local_max_path_id))
7093 } else {
7094 None
7095 }
7096 }
7097
7098 pub(crate) fn is_ipv6(&self) -> bool {
7103 self.paths
7104 .values()
7105 .any(|p| p.data.network_path.remote.is_ipv6())
7106 }
7107
7108 pub fn add_nat_traversal_address(
7110 &mut self,
7111 address: SocketAddr,
7112 ) -> Result<(), n0_nat_traversal::Error> {
7113 if let Some(added) = self.n0_nat_traversal.add_local_address(address)? {
7114 self.spaces[SpaceId::Data].pending.add_address.insert(added);
7115 };
7116 Ok(())
7117 }
7118
7119 pub fn remove_nat_traversal_address(
7123 &mut self,
7124 address: SocketAddr,
7125 ) -> Result<(), n0_nat_traversal::Error> {
7126 if let Some(removed) = self.n0_nat_traversal.remove_local_address(address)? {
7127 self.spaces[SpaceId::Data]
7128 .pending
7129 .remove_address
7130 .insert(removed);
7131 }
7132 Ok(())
7133 }
7134
7135 pub fn get_local_nat_traversal_addresses(
7137 &self,
7138 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7139 self.n0_nat_traversal.get_local_nat_traversal_addresses()
7140 }
7141
7142 pub fn get_remote_nat_traversal_addresses(
7144 &self,
7145 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7146 Ok(self
7147 .n0_nat_traversal
7148 .client_side()?
7149 .get_remote_nat_traversal_addresses())
7150 }
7151
7152 pub fn initiate_nat_traversal_round(
7164 &mut self,
7165 now: Instant,
7166 ) -> Result<Vec<SocketAddr>, n0_nat_traversal::Error> {
7167 if self.state.is_closed() {
7168 return Err(n0_nat_traversal::Error::Closed);
7169 }
7170
7171 let ipv6 = self.is_ipv6();
7172 let client_state = self.n0_nat_traversal.client_side_mut()?;
7173 let (mut reach_out_frames, probed_addrs) =
7174 client_state.initiate_nat_traversal_round(ipv6)?;
7175 if let Some(delay) = self.n0_nat_traversal.retry_delay(self.config.initial_rtt) {
7176 self.timers.set(
7177 Timer::Conn(ConnTimer::NatTraversalProbeRetry),
7178 now + delay,
7179 self.qlog.with_time(now),
7180 );
7181 }
7182
7183 self.spaces[SpaceId::Data]
7184 .pending
7185 .reach_out
7186 .append(&mut reach_out_frames);
7187
7188 Ok(probed_addrs)
7189 }
7190
7191 fn is_handshake_confirmed(&self) -> bool {
7200 !self.is_handshaking() && !self.crypto_state.has_keys(EncryptionLevel::Handshake)
7201 }
7202}
7203
7204impl fmt::Debug for Connection {
7205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7206 f.debug_struct("Connection")
7207 .field("handshake_cid", &self.handshake_cid)
7208 .finish()
7209 }
7210}
7211
7212#[derive(Debug, Default)]
7218struct AbandonedPaths(ArrayRangeSet<ABANDONED_PATH_INLINE_RANGES, u32>);
7219
7220const ABANDONED_PATH_INLINE_RANGES: usize = 16;
7225
7226impl AbandonedPaths {
7227 fn len(&self) -> u32 {
7229 self.0.elts_count()
7230 }
7231
7232 fn max(&self) -> Option<PathId> {
7234 self.0.max().map(PathId::from)
7235 }
7236
7237 fn contains(&self, val: &PathId) -> bool {
7239 self.0.contains(val.as_u32())
7240 }
7241
7242 fn insert(&mut self, val: PathId) {
7244 self.0.insert_one(val.as_u32());
7245 }
7246}
7247
7248pub trait NetworkChangeHint: fmt::Debug + 'static {
7250 fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool;
7259}
7260
7261#[derive(Debug)]
7263enum PollPathSpaceStatus {
7264 NothingToSend {
7266 path_blocked: PathBlocked,
7269 },
7270 WrotePacket {
7272 last_packet_number: u64,
7274 pad_datagram: PadDatagram,
7288 },
7289 Send {
7296 last_packet_number: u64,
7298 },
7299}
7300
7301#[derive(Debug, Copy, Clone)]
7307struct PathSchedulingInfo {
7308 is_abandoned: bool,
7314 may_send_data: bool,
7332 may_send_close: bool,
7338 may_self_abandon: bool,
7339}
7340
7341#[derive(Debug, Copy, Clone, PartialEq, Eq)]
7342enum PathBlocked {
7343 No,
7344 AntiAmplification,
7345 Congestion,
7346 Pacing,
7347}
7348
7349enum ConnectionSide {
7351 Client {
7352 token: Bytes,
7354 token_store: Arc<dyn TokenStore>,
7355 server_name: String,
7356 },
7357 Server {
7358 server_config: Arc<ServerConfig>,
7359 },
7360}
7361
7362impl ConnectionSide {
7363 fn is_client(&self) -> bool {
7364 self.side().is_client()
7365 }
7366
7367 fn is_server(&self) -> bool {
7368 self.side().is_server()
7369 }
7370
7371 fn side(&self) -> Side {
7372 match *self {
7373 Self::Client { .. } => Side::Client,
7374 Self::Server { .. } => Side::Server,
7375 }
7376 }
7377}
7378
7379impl From<SideArgs> for ConnectionSide {
7380 fn from(side: SideArgs) -> Self {
7381 match side {
7382 SideArgs::Client {
7383 token_store,
7384 server_name,
7385 } => Self::Client {
7386 token: token_store.take(&server_name).unwrap_or_default(),
7387 token_store,
7388 server_name,
7389 },
7390 SideArgs::Server {
7391 server_config,
7392 pref_addr_cid: _,
7393 path_validated: _,
7394 } => Self::Server { server_config },
7395 }
7396 }
7397}
7398
7399pub(crate) enum SideArgs {
7401 Client {
7402 token_store: Arc<dyn TokenStore>,
7403 server_name: String,
7404 },
7405 Server {
7406 server_config: Arc<ServerConfig>,
7407 pref_addr_cid: Option<ConnectionId>,
7408 path_validated: bool,
7409 },
7410}
7411
7412impl SideArgs {
7413 pub(crate) fn pref_addr_cid(&self) -> Option<ConnectionId> {
7414 match *self {
7415 Self::Client { .. } => None,
7416 Self::Server { pref_addr_cid, .. } => pref_addr_cid,
7417 }
7418 }
7419
7420 pub(crate) fn path_validated(&self) -> bool {
7421 match *self {
7422 Self::Client { .. } => true,
7423 Self::Server { path_validated, .. } => path_validated,
7424 }
7425 }
7426
7427 pub(crate) fn side(&self) -> Side {
7428 match *self {
7429 Self::Client { .. } => Side::Client,
7430 Self::Server { .. } => Side::Server,
7431 }
7432 }
7433}
7434
7435#[derive(Debug, Error, Clone, PartialEq, Eq)]
7437pub enum ConnectionError {
7438 #[error("peer doesn't implement any supported version")]
7440 VersionMismatch,
7441 #[error(transparent)]
7443 TransportError(#[from] TransportError),
7444 #[error("aborted by peer: {0}")]
7446 ConnectionClosed(frame::ConnectionClose),
7447 #[error("closed by peer: {0}")]
7449 ApplicationClosed(frame::ApplicationClose),
7450 #[error("reset by peer")]
7452 Reset,
7453 #[error("timed out")]
7459 TimedOut,
7460 #[error("closed")]
7462 LocallyClosed,
7463 #[error("CIDs exhausted")]
7467 CidsExhausted,
7468}
7469
7470impl From<Close> for ConnectionError {
7471 fn from(x: Close) -> Self {
7472 match x {
7473 Close::Connection(reason) => Self::ConnectionClosed(reason),
7474 Close::Application(reason) => Self::ApplicationClosed(reason),
7475 }
7476 }
7477}
7478
7479impl From<ConnectionError> for io::Error {
7481 fn from(x: ConnectionError) -> Self {
7482 use ConnectionError::*;
7483 let kind = match x {
7484 TimedOut => io::ErrorKind::TimedOut,
7485 Reset => io::ErrorKind::ConnectionReset,
7486 ApplicationClosed(_) | ConnectionClosed(_) => io::ErrorKind::ConnectionAborted,
7487 TransportError(_) | VersionMismatch | LocallyClosed | CidsExhausted => {
7488 io::ErrorKind::Other
7489 }
7490 };
7491 Self::new(kind, x)
7492 }
7493}
7494
7495#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
7498pub enum PathError {
7499 #[error("multipath extension not negotiated")]
7501 MultipathNotNegotiated,
7502 #[error("the server side may not open a path")]
7504 ServerSideNotAllowed,
7505 #[error("maximum number of concurrent paths reached")]
7507 MaxPathIdReached,
7508 #[error("remoted CIDs exhausted")]
7510 RemoteCidsExhausted,
7511 #[error("path validation failed")]
7513 ValidationFailed,
7514 #[error("invalid remote address")]
7516 InvalidRemoteAddress(SocketAddr),
7517}
7518
7519#[derive(Debug, Error, Clone, Eq, PartialEq)]
7521pub enum ClosePathError {
7522 #[error("Multipath extension not negotiated")]
7524 MultipathNotNegotiated,
7525 #[error("closed path")]
7527 ClosedPath,
7528 #[error("last open path")]
7532 LastOpenPath,
7533}
7534
7535#[derive(Debug, Error, Clone, Copy)]
7537#[error("Multipath extension not negotiated")]
7538pub struct MultipathNotNegotiated {
7539 _private: (),
7540}
7541
7542#[derive(Debug)]
7544pub enum Event {
7545 HandshakeDataReady,
7547 Connected,
7549 HandshakeConfirmed,
7551 ConnectionLost {
7558 reason: ConnectionError,
7560 },
7561 Stream(StreamEvent),
7563 DatagramReceived,
7565 DatagramsUnblocked,
7567 Path(PathEvent),
7569 NatTraversal(n0_nat_traversal::Event),
7571}
7572
7573impl From<PathEvent> for Event {
7574 fn from(source: PathEvent) -> Self {
7575 Self::Path(source)
7576 }
7577}
7578
7579fn get_max_ack_delay(params: &TransportParameters) -> Duration {
7580 Duration::from_micros(params.max_ack_delay.0 * 1000)
7581}
7582
7583const MAX_BACKOFF_EXPONENT: u32 = 16;
7585
7586const MAX_PTO_INTERVAL: Duration = Duration::from_secs(2);
7590
7591const MIN_IDLE_FOR_FAST_PTO: Duration = Duration::from_secs(25);
7593
7594const MAX_PTO_FAST_INTERVAL: Duration = Duration::from_secs(1);
7599
7600const SLOW_RTT_THRESHOLD: Duration =
7605 Duration::from_millis((MAX_PTO_INTERVAL.as_millis() as u64 * 2) / 3);
7606
7607const MIN_PACKET_SPACE: usize = MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE + 32;
7615
7616const MAX_HANDSHAKE_OR_0RTT_HEADER_SIZE: usize =
7622 1 + 4 + 1 + MAX_CID_SIZE + 1 + MAX_CID_SIZE + VarInt::from_u32(u16::MAX as u32).size() + 4;
7623
7624#[derive(Default)]
7625struct SentFrames {
7626 retransmits: ThinRetransmits,
7627 path_retransmits: PathRetransmits,
7628 largest_acked: FxHashMap<PathId, u64>,
7630 stream_frames: StreamMetaVec,
7631 non_retransmits: bool,
7633 requires_padding: bool,
7635}
7636
7637impl SentFrames {
7638 fn is_ack_only(&self, streams: &StreamsState) -> bool {
7640 !self.largest_acked.is_empty()
7641 && !self.non_retransmits
7642 && self.stream_frames.is_empty()
7643 && self.retransmits.is_empty(streams)
7644 }
7645
7646 fn retransmits_mut(&mut self) -> &mut Retransmits {
7647 self.retransmits.get_or_create()
7648 }
7649
7650 fn record_sent_frame(&mut self, frame: frame::EncodableFrame<'_>) {
7651 use frame::EncodableFrame::*;
7652 match frame {
7653 PathAck(path_ack_encoder) => {
7654 if let Some(max) = path_ack_encoder.ranges.max() {
7655 self.largest_acked.insert(path_ack_encoder.path_id, max);
7656 }
7657 }
7658 Ack(ack_encoder) => {
7659 if let Some(max) = ack_encoder.ranges.max() {
7660 self.largest_acked.insert(PathId::ZERO, max);
7661 }
7662 }
7663 Close(_) => { }
7664 PathResponse(_) => self.non_retransmits = true,
7665 HandshakeDone(_) => self.retransmits_mut().handshake_done = true,
7666 ReachOut(frame) => self.retransmits_mut().reach_out.push(frame),
7667 ObservedAddr(_) => self.path_retransmits.observed_address = true,
7668 Ping(_) => self.non_retransmits = true,
7669 ImmediateAck(_) => self.non_retransmits = true,
7670 AckFrequency(_) => self.retransmits_mut().ack_frequency = true,
7671 PathChallenge(_) => self.non_retransmits = true,
7672 Crypto(crypto) => self.retransmits_mut().crypto.push_back(crypto),
7673 PathAbandon(path_abandon) => {
7674 self.retransmits_mut()
7675 .path_abandon
7676 .entry(path_abandon.path_id)
7677 .or_insert(path_abandon.error_code);
7678 }
7679 PathStatusAvailable(frame::PathStatusAvailable { path_id, .. })
7680 | PathStatusBackup(frame::PathStatusBackup { path_id, .. }) => {
7681 self.retransmits_mut().path_status.insert(path_id);
7682 }
7683 MaxPathId(_) => self.retransmits_mut().max_path_id = true,
7684 PathsBlocked(frame::PathsBlocked(path_id)) => {
7685 let paths_blocked = &mut self.retransmits_mut().paths_blocked;
7686 *paths_blocked = cmp::max(*paths_blocked, Some(path_id));
7687 }
7688 PathCidsBlocked(path_cids_blocked) => {
7689 self.retransmits_mut()
7690 .path_cids_blocked
7691 .entry(path_cids_blocked.path_id)
7692 .and_modify(|next_seq| {
7693 *next_seq = cmp::max(*next_seq, path_cids_blocked.next_seq);
7694 })
7695 .or_insert(path_cids_blocked.next_seq);
7696 }
7697 ResetStream(reset) => self
7698 .retransmits_mut()
7699 .reset_stream
7700 .push((reset.id, reset.error_code)),
7701 StopSending(stop_sending) => self.retransmits_mut().stop_sending.push(stop_sending),
7702 NewConnectionId(new_cid) => self.retransmits_mut().new_cids.push(new_cid.issued()),
7703 RetireConnectionId(retire_cid) => self
7704 .retransmits_mut()
7705 .retire_cids
7706 .push((retire_cid.path_id.unwrap_or_default(), retire_cid.sequence)),
7707 Datagram(_) => self.non_retransmits = true,
7708 NewToken(_) => {}
7709 AddAddress(add_address) => {
7710 self.retransmits_mut().add_address.insert(add_address);
7711 }
7712 RemoveAddress(remove_address) => {
7713 self.retransmits_mut().remove_address.insert(remove_address);
7714 }
7715 StreamMeta(stream_meta_encoder) => self.stream_frames.push(stream_meta_encoder.meta),
7716 MaxData(_) => self.retransmits_mut().max_data = true,
7717 MaxStreamData(max) => {
7718 self.retransmits_mut().max_stream_data.insert(max.id);
7719 }
7720 MaxStreams(max_streams) => {
7721 self.retransmits_mut().max_stream_id[max_streams.dir as usize] = true
7722 }
7723 StreamsBlocked(streams_blocked) => {
7724 self.retransmits_mut().streams_blocked[streams_blocked.dir as usize] = true
7725 }
7726 }
7727 }
7728}
7729
7730fn negotiate_max_idle_timeout(x: Option<VarInt>, y: Option<VarInt>) -> Option<Duration> {
7742 match (x, y) {
7743 (Some(VarInt(0)) | None, Some(VarInt(0)) | None) => None,
7744 (Some(VarInt(0)) | None, Some(y)) => Some(Duration::from_millis(y.0)),
7745 (Some(x), Some(VarInt(0)) | None) => Some(Duration::from_millis(x.0)),
7746 (Some(x), Some(y)) => Some(Duration::from_millis(cmp::min(x, y).0)),
7747 }
7748}
7749
7750#[cfg(test)]
7751mod tests {
7752 use super::*;
7753
7754 #[test]
7755 fn negotiate_max_idle_timeout_commutative() {
7756 let test_params = [
7757 (None, None, None),
7758 (None, Some(VarInt(0)), None),
7759 (None, Some(VarInt(2)), Some(Duration::from_millis(2))),
7760 (Some(VarInt(0)), Some(VarInt(0)), None),
7761 (
7762 Some(VarInt(2)),
7763 Some(VarInt(0)),
7764 Some(Duration::from_millis(2)),
7765 ),
7766 (
7767 Some(VarInt(1)),
7768 Some(VarInt(4)),
7769 Some(Duration::from_millis(1)),
7770 ),
7771 ];
7772
7773 for (left, right, result) in test_params {
7774 assert_eq!(negotiate_max_idle_timeout(left, right), result);
7775 assert_eq!(negotiate_max_idle_timeout(right, left), result);
7776 }
7777 }
7778
7779 #[test]
7780 fn abandoned_paths() {
7781 let mut t = AbandonedPaths::default();
7782
7783 t.insert(PathId(0));
7784 t.insert(PathId(1));
7785 assert_eq!(t.len(), 2);
7786 assert_eq!(t.0.range_count(), 1); assert!(t.contains(&PathId(0)));
7788 assert!(t.contains(&PathId(1)));
7789 assert!(!t.contains(&PathId(2)));
7790 assert!(!t.contains(&PathId(3)));
7791 assert_eq!(t.max(), Some(PathId(1)));
7792
7793 t.insert(PathId(3));
7794 assert_eq!(t.len(), 3);
7795 assert_eq!(t.0.range_count(), 2); assert!(t.contains(&PathId(0)));
7797 assert!(t.contains(&PathId(1)));
7798 assert!(!t.contains(&PathId(2)));
7799 assert!(t.contains(&PathId(3)));
7800 assert_eq!(t.max(), Some(PathId(3)));
7801
7802 t.insert(PathId(2));
7803 assert_eq!(t.len(), 4);
7804 assert_eq!(t.0.range_count(), 1); assert!(t.contains(&PathId(0)));
7806 assert!(t.contains(&PathId(1)));
7807 assert!(t.contains(&PathId(2)));
7808 assert!(t.contains(&PathId(3)));
7809 assert_eq!(t.max(), Some(PathId(3)));
7810 }
7811}