1use std::collections::BTreeMap;
28use std::collections::VecDeque;
29
30use std::net::SocketAddr;
31
32use std::time::Duration;
33use std::time::Instant;
34
35use smallvec::SmallVec;
36
37use slab::Slab;
38
39use crate::Config;
40use crate::Error;
41use crate::Result;
42use crate::StartupExit;
43
44use crate::pmtud;
45use crate::recovery;
46use crate::recovery::Bandwidth;
47use crate::recovery::HandshakeStatus;
48use crate::recovery::OnLossDetectionTimeoutOutcome;
49use crate::recovery::RecoveryOps;
50
51#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
53pub enum PathState {
54 Failed,
56
57 Unknown,
59
60 Validating,
62
63 ValidatingMTU,
65
66 Validated,
68}
69
70impl PathState {
71 #[cfg(feature = "ffi")]
72 pub fn to_c(self) -> libc::ssize_t {
73 match self {
74 PathState::Failed => -1,
75 PathState::Unknown => 0,
76 PathState::Validating => 1,
77 PathState::ValidatingMTU => 2,
78 PathState::Validated => 3,
79 }
80 }
81}
82
83#[derive(Clone, Debug, PartialEq, Eq)]
85pub enum PathEvent {
86 New(SocketAddr, SocketAddr),
91
92 Validated(SocketAddr, SocketAddr),
95
96 FailedValidation(SocketAddr, SocketAddr),
100
101 Closed(SocketAddr, SocketAddr),
104
105 ReusedSourceConnectionId(
109 u64,
110 (SocketAddr, SocketAddr),
111 (SocketAddr, SocketAddr),
112 ),
113
114 PeerMigrated(SocketAddr, SocketAddr),
120}
121
122#[derive(Debug)]
124pub struct Path {
125 local_addr: SocketAddr,
127
128 peer_addr: SocketAddr,
130
131 pub active_scid_seq: Option<u64>,
133
134 pub active_dcid_seq: Option<u64>,
136
137 state: PathState,
139
140 active: bool,
142
143 pub recovery: recovery::Recovery,
145
146 pub pmtud: Option<pmtud::Pmtud>,
148
149 in_flight_challenges: VecDeque<([u8; 8], usize, Instant)>,
152
153 max_challenge_size: usize,
155
156 probing_lost: usize,
158
159 last_probe_lost_time: Option<Instant>,
161
162 received_challenges: VecDeque<[u8; 8]>,
164
165 received_challenges_max_len: usize,
167
168 pub sent_count: usize,
170
171 pub recv_count: usize,
173
174 pub retrans_count: usize,
176
177 pub total_pto_count: usize,
184
185 pub dgram_sent_count: usize,
187
188 pub dgram_recv_count: usize,
190
191 pub sent_bytes: u64,
193
194 pub recv_bytes: u64,
196
197 pub stream_retrans_bytes: u64,
200
201 pub max_send_bytes: usize,
204
205 pub verified_peer_address: bool,
207
208 pub peer_verified_local_address: bool,
210
211 challenge_requested: bool,
213
214 failure_notified: bool,
216
217 migrating: bool,
220
221 pub needs_ack_eliciting: bool,
223}
224
225impl Path {
226 pub fn new(
229 local_addr: SocketAddr, peer_addr: SocketAddr,
230 recovery_config: &recovery::RecoveryConfig,
231 path_challenge_recv_max_queue_len: usize, is_initial: bool,
232 config: Option<&Config>,
233 ) -> Self {
234 let (state, active_scid_seq, active_dcid_seq) = if is_initial {
235 (PathState::Validated, Some(0), Some(0))
236 } else {
237 (PathState::Unknown, None, None)
238 };
239
240 let pmtud = config.and_then(|c| {
241 if c.pmtud {
242 let maximum_supported_mtu: usize = std::cmp::min(
243 c.local_transport_params
246 .max_udp_payload_size
247 .try_into()
248 .unwrap_or(c.max_send_udp_payload_size),
249 c.max_send_udp_payload_size,
250 );
251 Some(pmtud::Pmtud::new(maximum_supported_mtu))
252 } else {
253 None
254 }
255 });
256
257 Self {
258 local_addr,
259 peer_addr,
260 active_scid_seq,
261 active_dcid_seq,
262 state,
263 active: false,
264 recovery: recovery::Recovery::new_with_config(recovery_config),
265 pmtud,
266 in_flight_challenges: VecDeque::new(),
267 max_challenge_size: 0,
268 probing_lost: 0,
269 last_probe_lost_time: None,
270 received_challenges: VecDeque::with_capacity(
271 path_challenge_recv_max_queue_len,
272 ),
273 received_challenges_max_len: path_challenge_recv_max_queue_len,
274 sent_count: 0,
275 recv_count: 0,
276 retrans_count: 0,
277 total_pto_count: 0,
278 dgram_sent_count: 0,
279 dgram_recv_count: 0,
280 sent_bytes: 0,
281 recv_bytes: 0,
282 stream_retrans_bytes: 0,
283 max_send_bytes: 0,
284 verified_peer_address: false,
285 peer_verified_local_address: false,
286 challenge_requested: false,
287 failure_notified: false,
288 migrating: false,
289 needs_ack_eliciting: false,
290 }
291 }
292
293 #[inline]
295 pub fn local_addr(&self) -> SocketAddr {
296 self.local_addr
297 }
298
299 #[inline]
301 pub fn peer_addr(&self) -> SocketAddr {
302 self.peer_addr
303 }
304
305 #[inline]
307 fn working(&self) -> bool {
308 self.state > PathState::Failed
309 }
310
311 #[inline]
313 pub fn active(&self) -> bool {
314 self.active && self.working() && self.active_dcid_seq.is_some()
315 }
316
317 #[inline]
319 pub fn usable(&self) -> bool {
320 self.active() ||
321 (self.state == PathState::Validated &&
322 self.active_dcid_seq.is_some())
323 }
324
325 #[inline]
327 fn unused(&self) -> bool {
328 !self.active() && self.active_dcid_seq.is_none()
330 }
331
332 #[inline]
334 pub fn probing_required(&self) -> bool {
335 !self.received_challenges.is_empty() || self.validation_requested()
336 }
337
338 fn promote_to(&mut self, state: PathState) {
341 if self.state < state {
342 self.state = state;
343 }
344 }
345
346 #[inline]
348 pub fn validated(&self) -> bool {
349 self.state == PathState::Validated
350 }
351
352 #[inline]
354 fn validation_failed(&self) -> bool {
355 self.state == PathState::Failed
356 }
357
358 #[inline]
360 pub fn under_validation(&self) -> bool {
361 matches!(self.state, PathState::Validating | PathState::ValidatingMTU)
362 }
363
364 #[inline]
366 pub fn request_validation(&mut self) {
367 self.challenge_requested = true;
368 }
369
370 #[inline]
372 pub fn validation_requested(&self) -> bool {
373 self.challenge_requested
374 }
375
376 pub fn should_send_pmtu_probe(
377 &mut self, hs_confirmed: bool, hs_done: bool, out_len: usize,
378 is_closing: bool, frames_empty: bool,
379 ) -> bool {
380 let Some(pmtud) = self.pmtud.as_mut() else {
381 return false;
382 };
383
384 (hs_confirmed && hs_done) &&
385 pmtud.get_probe_size() > pmtud.get_current_mtu() &&
386 self.recovery.cwnd_available() > pmtud.get_probe_size() &&
387 out_len >= pmtud.get_probe_size() &&
388 pmtud.should_probe() &&
389 !is_closing &&
390 frames_empty
391 }
392
393 pub fn on_challenge_sent(&mut self) {
394 self.promote_to(PathState::Validating);
395 self.challenge_requested = false;
396 }
397
398 pub fn add_challenge_sent(
400 &mut self, data: [u8; 8], pkt_size: usize, sent_time: Instant,
401 ) {
402 self.on_challenge_sent();
403 self.in_flight_challenges
404 .push_back((data, pkt_size, sent_time));
405 }
406
407 pub fn on_challenge_received(&mut self, data: [u8; 8]) {
408 if self.received_challenges.len() == self.received_challenges_max_len {
410 return;
411 }
412
413 self.received_challenges.push_back(data);
414 self.peer_verified_local_address = true;
415 }
416
417 pub fn has_pending_challenge(&self, data: [u8; 8]) -> bool {
418 self.in_flight_challenges.iter().any(|(d, ..)| *d == data)
419 }
420
421 pub fn on_response_received(&mut self, data: [u8; 8]) -> bool {
423 self.verified_peer_address = true;
424 self.probing_lost = 0;
425
426 let mut challenge_size = 0;
427 self.in_flight_challenges.retain(|(d, s, _)| {
428 if *d == data {
429 challenge_size = *s;
430 false
431 } else {
432 true
433 }
434 });
435
436 self.promote_to(PathState::ValidatingMTU);
438
439 self.max_challenge_size =
440 std::cmp::max(self.max_challenge_size, challenge_size);
441
442 if self.state == PathState::ValidatingMTU {
443 if self.max_challenge_size >= crate::MIN_CLIENT_INITIAL_LEN {
444 self.promote_to(PathState::Validated);
446 return true;
447 }
448
449 self.request_validation();
451 }
452
453 false
454 }
455
456 fn on_failed_validation(&mut self) {
457 self.state = PathState::Failed;
458 self.active = false;
459 }
460
461 #[inline]
462 pub fn pop_received_challenge(&mut self) -> Option<[u8; 8]> {
463 self.received_challenges.pop_front()
464 }
465
466 pub fn on_loss_detection_timeout(
467 &mut self, handshake_status: HandshakeStatus, now: Instant,
468 is_server: bool, trace_id: &str,
469 ) -> OnLossDetectionTimeoutOutcome {
470 let outcome = self.recovery.on_loss_detection_timeout(
471 handshake_status,
472 now,
473 trace_id,
474 );
475
476 let mut lost_probe_time = None;
477 self.in_flight_challenges.retain(|(_, _, sent_time)| {
478 if *sent_time <= now {
479 if lost_probe_time.is_none() {
480 lost_probe_time = Some(*sent_time);
481 }
482 false
483 } else {
484 true
485 }
486 });
487
488 if let Some(lost_probe_time) = lost_probe_time {
491 self.last_probe_lost_time = match self.last_probe_lost_time {
492 Some(last) => {
493 if lost_probe_time - last >= self.recovery.rtt() {
495 self.probing_lost += 1;
496 Some(lost_probe_time)
497 } else {
498 Some(last)
499 }
500 },
501 None => {
502 self.probing_lost += 1;
503 Some(lost_probe_time)
504 },
505 };
506 if self.probing_lost >= crate::MAX_PROBING_TIMEOUTS ||
510 (is_server && self.max_send_bytes < crate::MIN_PROBING_SIZE)
511 {
512 self.on_failed_validation();
513 } else {
514 self.request_validation();
515 }
516 }
517
518 self.total_pto_count += 1;
520
521 outcome
522 }
523
524 pub fn reinit_recovery(
525 &mut self, recovery_config: &recovery::RecoveryConfig,
526 ) {
527 self.recovery = recovery::Recovery::new_with_config(recovery_config)
528 }
529
530 pub fn stats(&self) -> PathStats {
531 PathStats {
532 local_addr: self.local_addr,
533 peer_addr: self.peer_addr,
534 validation_state: self.state,
535 active: self.active,
536 recv: self.recv_count,
537 sent: self.sent_count,
538 lost: self.recovery.lost_count(),
539 retrans: self.retrans_count,
540 total_pto_count: self.total_pto_count,
541 dgram_recv: self.dgram_recv_count,
542 dgram_sent: self.dgram_sent_count,
543 rtt: self.recovery.rtt(),
544 min_rtt: self.recovery.min_rtt(),
545 max_rtt: self.recovery.max_rtt(),
546 rttvar: self.recovery.rttvar(),
547 cwnd: self.recovery.cwnd(),
548 sent_bytes: self.sent_bytes,
549 recv_bytes: self.recv_bytes,
550 lost_bytes: self.recovery.bytes_lost(),
551 stream_retrans_bytes: self.stream_retrans_bytes,
552 pmtu: self.recovery.max_datagram_size(),
553 delivery_rate: self.recovery.delivery_rate().to_bytes_per_second(),
554 max_bandwidth: self
555 .recovery
556 .max_bandwidth()
557 .map(Bandwidth::to_bytes_per_second),
558 startup_exit: self.recovery.startup_exit(),
559 }
560 }
561
562 pub fn bytes_in_flight_duration(&self) -> Duration {
563 self.recovery.bytes_in_flight_duration()
564 }
565}
566
567#[derive(Default)]
569pub struct SocketAddrIter {
570 pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
571 pub(crate) index: usize,
572}
573
574impl Iterator for SocketAddrIter {
575 type Item = SocketAddr;
576
577 #[inline]
578 fn next(&mut self) -> Option<Self::Item> {
579 let v = self.sockaddrs.get(self.index)?;
580 self.index += 1;
581 Some(*v)
582 }
583}
584
585impl ExactSizeIterator for SocketAddrIter {
586 #[inline]
587 fn len(&self) -> usize {
588 self.sockaddrs.len() - self.index
589 }
590}
591
592pub struct PathMap {
594 paths: Slab<Path>,
597
598 max_concurrent_paths: usize,
600
601 addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
604
605 events: VecDeque<PathEvent>,
607
608 is_server: bool,
610}
611
612impl PathMap {
613 pub fn new(
616 mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
617 ) -> Self {
618 let mut paths = Slab::with_capacity(1); let mut addrs_to_paths = BTreeMap::new();
620
621 let local_addr = initial_path.local_addr;
622 let peer_addr = initial_path.peer_addr;
623
624 initial_path.active = true;
626
627 let active_path_id = paths.insert(initial_path);
628 addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
629
630 Self {
631 paths,
632 max_concurrent_paths,
633 addrs_to_paths,
634 events: VecDeque::new(),
635 is_server,
636 }
637 }
638
639 #[inline]
645 pub fn get(&self, path_id: usize) -> Result<&Path> {
646 self.paths.get(path_id).ok_or(Error::InvalidState)
647 }
648
649 #[inline]
655 pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
656 self.paths.get_mut(path_id).ok_or(Error::InvalidState)
657 }
658
659 #[inline]
660 pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
663 self.paths.iter().find(|(_, p)| p.active())
664 }
665
666 #[inline]
671 pub fn get_active(&self) -> Result<&Path> {
672 self.get_active_with_pid()
673 .map(|(_, p)| p)
674 .ok_or(Error::InvalidState)
675 }
676
677 #[inline]
682 pub fn get_active_path_id(&self) -> Result<usize> {
683 self.get_active_with_pid()
684 .map(|(pid, _)| pid)
685 .ok_or(Error::InvalidState)
686 }
687
688 #[inline]
693 pub fn get_active_mut(&mut self) -> Result<&mut Path> {
694 self.paths
695 .iter_mut()
696 .map(|(_, p)| p)
697 .find(|p| p.active())
698 .ok_or(Error::InvalidState)
699 }
700
701 #[inline]
703 pub fn iter(&self) -> slab::Iter<'_, Path> {
704 self.paths.iter()
705 }
706
707 #[inline]
709 pub fn iter_mut(&mut self) -> slab::IterMut<'_, Path> {
710 self.paths.iter_mut()
711 }
712
713 #[inline]
715 pub fn len(&self) -> usize {
716 self.paths.len()
717 }
718
719 #[inline]
721 pub fn path_id_from_addrs(
722 &self, addrs: &(SocketAddr, SocketAddr),
723 ) -> Option<usize> {
724 self.addrs_to_paths.get(addrs).copied()
725 }
726
727 fn make_room_for_new_path(&mut self) -> Result<()> {
733 if self.paths.len() < self.max_concurrent_paths {
734 return Ok(());
735 }
736
737 let (pid_to_remove, _) = self
738 .paths
739 .iter()
740 .find(|(_, p)| p.unused())
741 .ok_or(Error::Done)?;
742
743 let path = self.paths.remove(pid_to_remove);
744 self.addrs_to_paths
745 .remove(&(path.local_addr, path.peer_addr));
746
747 self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
748
749 Ok(())
750 }
751
752 pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
763 self.make_room_for_new_path()?;
764
765 let local_addr = path.local_addr;
766 let peer_addr = path.peer_addr;
767
768 let pid = self.paths.insert(path);
769 self.addrs_to_paths.insert((local_addr, peer_addr), pid);
770
771 if is_server {
773 self.notify_event(PathEvent::New(local_addr, peer_addr));
774 }
775
776 Ok(pid)
777 }
778
779 pub fn notify_event(&mut self, ev: PathEvent) {
781 self.events.push_back(ev);
782 }
783
784 pub fn pop_event(&mut self) -> Option<PathEvent> {
786 self.events.pop_front()
787 }
788
789 pub fn notify_failed_validations(&mut self) {
791 let validation_failed = self
792 .paths
793 .iter_mut()
794 .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
795
796 for (_, p) in validation_failed {
797 self.events.push_back(PathEvent::FailedValidation(
798 p.local_addr,
799 p.peer_addr,
800 ));
801
802 p.failure_notified = true;
803 }
804 }
805
806 pub fn find_candidate_path(&self) -> Option<usize> {
808 self.paths
810 .iter()
811 .find(|(_, p)| p.usable())
812 .map(|(pid, _)| pid)
813 }
814
815 pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
817 let active_pid = self.get_active_path_id()?;
818
819 let challenge_pending =
820 self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
821
822 if let Some((pid, p)) = challenge_pending {
823 if p.on_response_received(data) {
824 let local_addr = p.local_addr;
825 let peer_addr = p.peer_addr;
826 let was_migrating = p.migrating;
827
828 p.migrating = false;
829
830 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
832
833 if pid == active_pid && was_migrating {
836 self.notify_event(PathEvent::PeerMigrated(
837 local_addr, peer_addr,
838 ));
839 }
840 }
841 }
842 Ok(())
843 }
844
845 pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
856 let is_server = self.is_server;
857
858 if let Ok(old_active_path) = self.get_active_mut() {
859 old_active_path.active = false;
860 }
861
862 let new_active_path = self.get_mut(path_id)?;
863 new_active_path.active = true;
864
865 if is_server {
866 if new_active_path.validated() {
867 let local_addr = new_active_path.local_addr();
868 let peer_addr = new_active_path.peer_addr();
869
870 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
871 } else {
872 new_active_path.migrating = true;
873
874 if !new_active_path.under_validation() {
876 new_active_path.request_validation();
877 }
878 }
879 }
880
881 Ok(())
882 }
883
884 pub fn set_discover_pmtu_on_existing_paths(
886 &mut self, discover: bool, max_send_udp_payload_size: usize,
887 ) {
888 for (_, path) in self.paths.iter_mut() {
889 path.pmtud = if discover {
890 Some(pmtud::Pmtud::new(max_send_udp_payload_size))
891 } else {
892 None
893 };
894 }
895 }
896}
897
898#[derive(Clone)]
905pub struct PathStats {
906 pub local_addr: SocketAddr,
908
909 pub peer_addr: SocketAddr,
911
912 pub validation_state: PathState,
914
915 pub active: bool,
917
918 pub recv: usize,
920
921 pub sent: usize,
923
924 pub lost: usize,
926
927 pub retrans: usize,
929
930 pub total_pto_count: usize,
937
938 pub dgram_recv: usize,
940
941 pub dgram_sent: usize,
943
944 pub rtt: Duration,
946
947 pub min_rtt: Option<Duration>,
949
950 pub max_rtt: Option<Duration>,
952
953 pub rttvar: Duration,
956
957 pub cwnd: usize,
959
960 pub sent_bytes: u64,
962
963 pub recv_bytes: u64,
965
966 pub lost_bytes: u64,
968
969 pub stream_retrans_bytes: u64,
971
972 pub pmtu: usize,
974
975 pub delivery_rate: u64,
984
985 pub max_bandwidth: Option<u64>,
990
991 pub startup_exit: Option<StartupExit>,
993}
994
995impl std::fmt::Debug for PathStats {
996 #[inline]
997 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
998 write!(
999 f,
1000 "local_addr={:?} peer_addr={:?} ",
1001 self.local_addr, self.peer_addr,
1002 )?;
1003 write!(
1004 f,
1005 "validation_state={:?} active={} ",
1006 self.validation_state, self.active,
1007 )?;
1008 write!(
1009 f,
1010 "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
1011 self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
1012 )?;
1013
1014 write!(
1015 f,
1016 " sent_bytes={} recv_bytes={} lost_bytes={}",
1017 self.sent_bytes, self.recv_bytes, self.lost_bytes,
1018 )?;
1019
1020 write!(
1021 f,
1022 " stream_retrans_bytes={} pmtu={} delivery_rate={}",
1023 self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
1024 )
1025 }
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030 use crate::rand;
1031 use crate::MIN_CLIENT_INITIAL_LEN;
1032
1033 use crate::recovery::RecoveryConfig;
1034 use crate::Config;
1035
1036 use super::*;
1037
1038 #[test]
1039 fn path_validation_limited_mtu() {
1040 let client_addr = "127.0.0.1:1234".parse().unwrap();
1041 let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
1042 let server_addr = "127.0.0.1:4321".parse().unwrap();
1043
1044 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1045 let recovery_config = RecoveryConfig::from_config(&config);
1046
1047 let path = Path::new(
1048 client_addr,
1049 server_addr,
1050 &recovery_config,
1051 config.path_challenge_recv_max_queue_len,
1052 true,
1053 None,
1054 );
1055 let mut path_mgr = PathMap::new(path, 2, false);
1056
1057 let probed_path = Path::new(
1058 client_addr_2,
1059 server_addr,
1060 &recovery_config,
1061 config.path_challenge_recv_max_queue_len,
1062 false,
1063 None,
1064 );
1065 path_mgr.insert_path(probed_path, false).unwrap();
1066
1067 let pid = path_mgr
1068 .path_id_from_addrs(&(client_addr_2, server_addr))
1069 .unwrap();
1070 path_mgr.get_mut(pid).unwrap().request_validation();
1071 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1072 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1073
1074 let data = rand::rand_u64().to_be_bytes();
1077 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1078 data,
1079 MIN_CLIENT_INITIAL_LEN - 1,
1080 Instant::now(),
1081 );
1082
1083 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1084 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1085 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1086 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1087 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1088 assert_eq!(path_mgr.pop_event(), None);
1089
1090 path_mgr.on_response_received(data).unwrap();
1093
1094 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1095 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1096 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1097 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1098 assert_eq!(
1099 path_mgr.get_mut(pid).unwrap().state,
1100 PathState::ValidatingMTU
1101 );
1102 assert_eq!(path_mgr.pop_event(), None);
1103
1104 let data = rand::rand_u64().to_be_bytes();
1107 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1108 data,
1109 MIN_CLIENT_INITIAL_LEN,
1110 Instant::now(),
1111 );
1112
1113 path_mgr.on_response_received(data).unwrap();
1114
1115 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1116 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1117 assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1118 assert!(path_mgr.get_mut(pid).unwrap().validated());
1119 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1120 assert_eq!(
1121 path_mgr.pop_event(),
1122 Some(PathEvent::Validated(client_addr_2, server_addr))
1123 );
1124 }
1125
1126 #[test]
1127 fn multiple_probes() {
1128 let client_addr = "127.0.0.1:1234".parse().unwrap();
1129 let server_addr = "127.0.0.1:4321".parse().unwrap();
1130
1131 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1132 let recovery_config = RecoveryConfig::from_config(&config);
1133
1134 let path = Path::new(
1135 client_addr,
1136 server_addr,
1137 &recovery_config,
1138 config.path_challenge_recv_max_queue_len,
1139 true,
1140 None,
1141 );
1142 let mut client_path_mgr = PathMap::new(path, 2, false);
1143 let mut server_path = Path::new(
1144 server_addr,
1145 client_addr,
1146 &recovery_config,
1147 config.path_challenge_recv_max_queue_len,
1148 false,
1149 None,
1150 );
1151
1152 let client_pid = client_path_mgr
1153 .path_id_from_addrs(&(client_addr, server_addr))
1154 .unwrap();
1155
1156 let data = rand::rand_u64().to_be_bytes();
1158
1159 client_path_mgr
1160 .get_mut(client_pid)
1161 .unwrap()
1162 .add_challenge_sent(data, MIN_CLIENT_INITIAL_LEN, Instant::now());
1163
1164 let data_2 = rand::rand_u64().to_be_bytes();
1166
1167 client_path_mgr
1168 .get_mut(client_pid)
1169 .unwrap()
1170 .add_challenge_sent(data_2, MIN_CLIENT_INITIAL_LEN, Instant::now());
1171 assert_eq!(
1172 client_path_mgr
1173 .get(client_pid)
1174 .unwrap()
1175 .in_flight_challenges
1176 .len(),
1177 2
1178 );
1179
1180 server_path.on_challenge_received(data);
1182 assert_eq!(server_path.received_challenges.len(), 1);
1183 server_path.on_challenge_received(data_2);
1184 assert_eq!(server_path.received_challenges.len(), 2);
1185
1186 client_path_mgr.on_response_received(data).unwrap();
1188 assert_eq!(
1189 client_path_mgr
1190 .get(client_pid)
1191 .unwrap()
1192 .in_flight_challenges
1193 .len(),
1194 1
1195 );
1196
1197 client_path_mgr.on_response_received(data_2).unwrap();
1199 assert_eq!(
1200 client_path_mgr
1201 .get(client_pid)
1202 .unwrap()
1203 .in_flight_challenges
1204 .len(),
1205 0
1206 );
1207 }
1208
1209 #[test]
1210 fn too_many_probes() {
1211 let client_addr = "127.0.0.1:1234".parse().unwrap();
1212 let server_addr = "127.0.0.1:4321".parse().unwrap();
1213
1214 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1216 let recovery_config = RecoveryConfig::from_config(&config);
1217
1218 let path = Path::new(
1219 client_addr,
1220 server_addr,
1221 &recovery_config,
1222 config.path_challenge_recv_max_queue_len,
1223 true,
1224 None,
1225 );
1226 let mut client_path_mgr = PathMap::new(path, 2, false);
1227 let mut server_path = Path::new(
1228 server_addr,
1229 client_addr,
1230 &recovery_config,
1231 config.path_challenge_recv_max_queue_len,
1232 false,
1233 None,
1234 );
1235
1236 let client_pid = client_path_mgr
1237 .path_id_from_addrs(&(client_addr, server_addr))
1238 .unwrap();
1239
1240 let data = rand::rand_u64().to_be_bytes();
1242
1243 client_path_mgr
1244 .get_mut(client_pid)
1245 .unwrap()
1246 .add_challenge_sent(data, MIN_CLIENT_INITIAL_LEN, Instant::now());
1247
1248 let data_2 = rand::rand_u64().to_be_bytes();
1250
1251 client_path_mgr
1252 .get_mut(client_pid)
1253 .unwrap()
1254 .add_challenge_sent(data_2, MIN_CLIENT_INITIAL_LEN, Instant::now());
1255 assert_eq!(
1256 client_path_mgr
1257 .get(client_pid)
1258 .unwrap()
1259 .in_flight_challenges
1260 .len(),
1261 2
1262 );
1263
1264 let data_3 = rand::rand_u64().to_be_bytes();
1266
1267 client_path_mgr
1268 .get_mut(client_pid)
1269 .unwrap()
1270 .add_challenge_sent(data_3, MIN_CLIENT_INITIAL_LEN, Instant::now());
1271 assert_eq!(
1272 client_path_mgr
1273 .get(client_pid)
1274 .unwrap()
1275 .in_flight_challenges
1276 .len(),
1277 3
1278 );
1279
1280 let data_4 = rand::rand_u64().to_be_bytes();
1282
1283 client_path_mgr
1284 .get_mut(client_pid)
1285 .unwrap()
1286 .add_challenge_sent(data_4, MIN_CLIENT_INITIAL_LEN, Instant::now());
1287 assert_eq!(
1288 client_path_mgr
1289 .get(client_pid)
1290 .unwrap()
1291 .in_flight_challenges
1292 .len(),
1293 4
1294 );
1295
1296 server_path.on_challenge_received(data);
1299 assert_eq!(server_path.received_challenges.len(), 1);
1300 server_path.on_challenge_received(data_2);
1301 assert_eq!(server_path.received_challenges.len(), 2);
1302 server_path.on_challenge_received(data_3);
1303 assert_eq!(server_path.received_challenges.len(), 3);
1304 server_path.on_challenge_received(data_4);
1305 assert_eq!(server_path.received_challenges.len(), 3);
1306
1307 client_path_mgr.on_response_received(data).unwrap();
1309 assert_eq!(
1310 client_path_mgr
1311 .get(client_pid)
1312 .unwrap()
1313 .in_flight_challenges
1314 .len(),
1315 3
1316 );
1317
1318 client_path_mgr.on_response_received(data_2).unwrap();
1320 assert_eq!(
1321 client_path_mgr
1322 .get(client_pid)
1323 .unwrap()
1324 .in_flight_challenges
1325 .len(),
1326 2
1327 );
1328
1329 client_path_mgr.on_response_received(data_3).unwrap();
1331 assert_eq!(
1332 client_path_mgr
1333 .get(client_pid)
1334 .unwrap()
1335 .in_flight_challenges
1336 .len(),
1337 1
1338 );
1339
1340 }
1342}