1use std::time;
28
29use std::collections::BTreeMap;
30use std::collections::VecDeque;
31use std::net::SocketAddr;
32
33use smallvec::SmallVec;
34
35use slab::Slab;
36
37use crate::Error;
38use crate::Result;
39
40use crate::pmtud;
41use crate::recovery;
42use crate::recovery::HandshakeStatus;
43use crate::recovery::RecoveryOps;
44
45#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
47pub enum PathState {
48 Failed,
50
51 Unknown,
53
54 Validating,
56
57 ValidatingMTU,
59
60 Validated,
62}
63
64impl PathState {
65 #[cfg(feature = "ffi")]
66 pub fn to_c(self) -> libc::ssize_t {
67 match self {
68 PathState::Failed => -1,
69 PathState::Unknown => 0,
70 PathState::Validating => 1,
71 PathState::ValidatingMTU => 2,
72 PathState::Validated => 3,
73 }
74 }
75}
76
77#[derive(Clone, Debug, PartialEq, Eq)]
79pub enum PathEvent {
80 New(SocketAddr, SocketAddr),
85
86 Validated(SocketAddr, SocketAddr),
89
90 FailedValidation(SocketAddr, SocketAddr),
94
95 Closed(SocketAddr, SocketAddr),
98
99 ReusedSourceConnectionId(
103 u64,
104 (SocketAddr, SocketAddr),
105 (SocketAddr, SocketAddr),
106 ),
107
108 PeerMigrated(SocketAddr, SocketAddr),
114}
115
116#[derive(Debug)]
118pub struct Path {
119 local_addr: SocketAddr,
121
122 peer_addr: SocketAddr,
124
125 pub active_scid_seq: Option<u64>,
127
128 pub active_dcid_seq: Option<u64>,
130
131 state: PathState,
133
134 active: bool,
136
137 pub recovery: recovery::Recovery,
139
140 pub pmtud: pmtud::Pmtud,
142
143 in_flight_challenges: VecDeque<([u8; 8], usize, time::Instant)>,
146
147 max_challenge_size: usize,
149
150 probing_lost: usize,
152
153 last_probe_lost_time: Option<time::Instant>,
155
156 received_challenges: VecDeque<[u8; 8]>,
158
159 received_challenges_max_len: usize,
161
162 pub sent_count: usize,
164
165 pub recv_count: usize,
167
168 pub retrans_count: usize,
170
171 pub dgram_sent_count: usize,
173
174 pub dgram_recv_count: usize,
176
177 pub sent_bytes: u64,
179
180 pub recv_bytes: u64,
182
183 pub stream_retrans_bytes: u64,
186
187 pub max_send_bytes: usize,
190
191 pub verified_peer_address: bool,
193
194 pub peer_verified_local_address: bool,
196
197 challenge_requested: bool,
199
200 failure_notified: bool,
202
203 migrating: bool,
206
207 pub needs_ack_eliciting: bool,
209}
210
211impl Path {
212 pub fn new(
215 local_addr: SocketAddr, peer_addr: SocketAddr,
216 recovery_config: &recovery::RecoveryConfig,
217 path_challenge_recv_max_queue_len: usize, pmtud_init: usize,
218 is_initial: bool,
219 ) -> Self {
220 let (state, active_scid_seq, active_dcid_seq) = if is_initial {
221 (PathState::Validated, Some(0), Some(0))
222 } else {
223 (PathState::Unknown, None, None)
224 };
225
226 Self {
227 local_addr,
228 peer_addr,
229 active_scid_seq,
230 active_dcid_seq,
231 state,
232 active: false,
233 recovery: recovery::Recovery::new_with_config(recovery_config),
234 pmtud: pmtud::Pmtud::new(pmtud_init),
235 in_flight_challenges: VecDeque::new(),
236 max_challenge_size: 0,
237 probing_lost: 0,
238 last_probe_lost_time: None,
239 received_challenges: VecDeque::with_capacity(
240 path_challenge_recv_max_queue_len,
241 ),
242 received_challenges_max_len: path_challenge_recv_max_queue_len,
243 sent_count: 0,
244 recv_count: 0,
245 retrans_count: 0,
246 dgram_sent_count: 0,
247 dgram_recv_count: 0,
248 sent_bytes: 0,
249 recv_bytes: 0,
250 stream_retrans_bytes: 0,
251 max_send_bytes: 0,
252 verified_peer_address: false,
253 peer_verified_local_address: false,
254 challenge_requested: false,
255 failure_notified: false,
256 migrating: false,
257 needs_ack_eliciting: false,
258 }
259 }
260
261 #[inline]
263 pub fn local_addr(&self) -> SocketAddr {
264 self.local_addr
265 }
266
267 #[inline]
269 pub fn peer_addr(&self) -> SocketAddr {
270 self.peer_addr
271 }
272
273 #[inline]
275 fn working(&self) -> bool {
276 self.state > PathState::Failed
277 }
278
279 #[inline]
281 pub fn active(&self) -> bool {
282 self.active && self.working() && self.active_dcid_seq.is_some()
283 }
284
285 #[inline]
287 pub fn usable(&self) -> bool {
288 self.active() ||
289 (self.state == PathState::Validated &&
290 self.active_dcid_seq.is_some())
291 }
292
293 #[inline]
295 fn unused(&self) -> bool {
296 !self.active() && self.active_dcid_seq.is_none()
298 }
299
300 #[inline]
302 pub fn probing_required(&self) -> bool {
303 !self.received_challenges.is_empty() || self.validation_requested()
304 }
305
306 fn promote_to(&mut self, state: PathState) {
309 if self.state < state {
310 self.state = state;
311 }
312 }
313
314 #[inline]
316 pub fn validated(&self) -> bool {
317 self.state == PathState::Validated
318 }
319
320 #[inline]
322 fn validation_failed(&self) -> bool {
323 self.state == PathState::Failed
324 }
325
326 #[inline]
328 pub fn under_validation(&self) -> bool {
329 matches!(self.state, PathState::Validating | PathState::ValidatingMTU)
330 }
331
332 #[inline]
334 pub fn request_validation(&mut self) {
335 self.challenge_requested = true;
336 }
337
338 #[inline]
340 pub fn validation_requested(&self) -> bool {
341 self.challenge_requested
342 }
343
344 pub fn should_send_pmtu_probe(
345 &mut self, hs_confirmed: bool, hs_done: bool, out_len: usize,
346 is_closing: bool, frames_empty: bool,
347 ) -> bool {
348 (hs_confirmed && hs_done) &&
349 self.pmtud.get_probe_size() > self.pmtud.get_current() &&
350 self.recovery.cwnd_available() > self.pmtud.get_probe_size() &&
351 out_len >= self.pmtud.get_probe_size() &&
352 self.pmtud.get_probe_status() &&
353 !is_closing &&
354 frames_empty
355 }
356
357 pub fn on_challenge_sent(&mut self) {
358 self.promote_to(PathState::Validating);
359 self.challenge_requested = false;
360 }
361
362 pub fn add_challenge_sent(
364 &mut self, data: [u8; 8], pkt_size: usize, sent_time: time::Instant,
365 ) {
366 self.on_challenge_sent();
367 self.in_flight_challenges
368 .push_back((data, pkt_size, sent_time));
369 }
370
371 pub fn on_challenge_received(&mut self, data: [u8; 8]) {
372 if self.received_challenges.len() == self.received_challenges_max_len {
374 return;
375 }
376
377 self.received_challenges.push_back(data);
378 self.peer_verified_local_address = true;
379 }
380
381 pub fn has_pending_challenge(&self, data: [u8; 8]) -> bool {
382 self.in_flight_challenges.iter().any(|(d, ..)| *d == data)
383 }
384
385 pub fn on_response_received(&mut self, data: [u8; 8]) -> bool {
387 self.verified_peer_address = true;
388 self.probing_lost = 0;
389
390 let mut challenge_size = 0;
391 self.in_flight_challenges.retain(|(d, s, _)| {
392 if *d == data {
393 challenge_size = *s;
394 false
395 } else {
396 true
397 }
398 });
399
400 self.promote_to(PathState::ValidatingMTU);
402
403 self.max_challenge_size =
404 std::cmp::max(self.max_challenge_size, challenge_size);
405
406 if self.state == PathState::ValidatingMTU {
407 if self.max_challenge_size >= crate::MIN_CLIENT_INITIAL_LEN {
408 self.promote_to(PathState::Validated);
410 return true;
411 }
412
413 self.request_validation();
415 }
416
417 false
418 }
419
420 fn on_failed_validation(&mut self) {
421 self.state = PathState::Failed;
422 self.active = false;
423 }
424
425 #[inline]
426 pub fn pop_received_challenge(&mut self) -> Option<[u8; 8]> {
427 self.received_challenges.pop_front()
428 }
429
430 pub fn on_loss_detection_timeout(
431 &mut self, handshake_status: HandshakeStatus, now: time::Instant,
432 is_server: bool, trace_id: &str,
433 ) -> (usize, usize) {
434 let (lost_packets, lost_bytes) = self.recovery.on_loss_detection_timeout(
435 handshake_status,
436 now,
437 trace_id,
438 );
439
440 let mut lost_probe_time = None;
441 self.in_flight_challenges.retain(|(_, _, sent_time)| {
442 if *sent_time <= now {
443 if lost_probe_time.is_none() {
444 lost_probe_time = Some(*sent_time);
445 }
446 false
447 } else {
448 true
449 }
450 });
451
452 if let Some(lost_probe_time) = lost_probe_time {
455 self.last_probe_lost_time = match self.last_probe_lost_time {
456 Some(last) => {
457 if lost_probe_time - last >= self.recovery.rtt() {
459 self.probing_lost += 1;
460 Some(lost_probe_time)
461 } else {
462 Some(last)
463 }
464 },
465 None => {
466 self.probing_lost += 1;
467 Some(lost_probe_time)
468 },
469 };
470 if self.probing_lost >= crate::MAX_PROBING_TIMEOUTS ||
474 (is_server && self.max_send_bytes < crate::MIN_PROBING_SIZE)
475 {
476 self.on_failed_validation();
477 } else {
478 self.request_validation();
479 }
480 }
481
482 (lost_packets, lost_bytes)
483 }
484
485 pub fn reinit_recovery(
486 &mut self, recovery_config: &recovery::RecoveryConfig,
487 ) {
488 self.recovery = recovery::Recovery::new_with_config(recovery_config)
489 }
490
491 pub fn stats(&self) -> PathStats {
492 PathStats {
493 local_addr: self.local_addr,
494 peer_addr: self.peer_addr,
495 validation_state: self.state,
496 active: self.active,
497 recv: self.recv_count,
498 sent: self.sent_count,
499 lost: self.recovery.lost_count(),
500 retrans: self.retrans_count,
501 dgram_recv: self.dgram_recv_count,
502 dgram_sent: self.dgram_sent_count,
503 rtt: self.recovery.rtt(),
504 min_rtt: self.recovery.min_rtt(),
505 rttvar: self.recovery.rttvar(),
506 cwnd: self.recovery.cwnd(),
507 sent_bytes: self.sent_bytes,
508 recv_bytes: self.recv_bytes,
509 lost_bytes: self.recovery.bytes_lost(),
510 stream_retrans_bytes: self.stream_retrans_bytes,
511 pmtu: self.recovery.max_datagram_size(),
512 delivery_rate: self.recovery.delivery_rate(),
513 }
514 }
515}
516
517#[derive(Default)]
519pub struct SocketAddrIter {
520 pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
521 pub(crate) index: usize,
522}
523
524impl Iterator for SocketAddrIter {
525 type Item = SocketAddr;
526
527 #[inline]
528 fn next(&mut self) -> Option<Self::Item> {
529 let v = self.sockaddrs.get(self.index)?;
530 self.index += 1;
531 Some(*v)
532 }
533}
534
535impl ExactSizeIterator for SocketAddrIter {
536 #[inline]
537 fn len(&self) -> usize {
538 self.sockaddrs.len() - self.index
539 }
540}
541
542pub struct PathMap {
544 paths: Slab<Path>,
547
548 max_concurrent_paths: usize,
550
551 addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
554
555 events: VecDeque<PathEvent>,
557
558 is_server: bool,
560}
561
562impl PathMap {
563 pub fn new(
566 mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
567 enable_pmtud: bool, max_send_udp_payload_size: usize,
568 ) -> Self {
569 let mut paths = Slab::with_capacity(1); let mut addrs_to_paths = BTreeMap::new();
571
572 let local_addr = initial_path.local_addr;
573 let peer_addr = initial_path.peer_addr;
574
575 initial_path.active = true;
577
578 if enable_pmtud {
581 initial_path.pmtud.should_probe(enable_pmtud);
582 initial_path.pmtud.set_probe_size(max_send_udp_payload_size);
583 initial_path.pmtud.enable(enable_pmtud);
584 }
585
586 let active_path_id = paths.insert(initial_path);
587 addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
588
589 Self {
590 paths,
591 max_concurrent_paths,
592 addrs_to_paths,
593 events: VecDeque::new(),
594 is_server,
595 }
596 }
597
598 #[inline]
604 pub fn get(&self, path_id: usize) -> Result<&Path> {
605 self.paths.get(path_id).ok_or(Error::InvalidState)
606 }
607
608 #[inline]
614 pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
615 self.paths.get_mut(path_id).ok_or(Error::InvalidState)
616 }
617
618 #[inline]
619 pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
622 self.paths.iter().find(|(_, p)| p.active())
623 }
624
625 #[inline]
630 pub fn get_active(&self) -> Result<&Path> {
631 self.get_active_with_pid()
632 .map(|(_, p)| p)
633 .ok_or(Error::InvalidState)
634 }
635
636 #[inline]
641 pub fn get_active_path_id(&self) -> Result<usize> {
642 self.get_active_with_pid()
643 .map(|(pid, _)| pid)
644 .ok_or(Error::InvalidState)
645 }
646
647 #[inline]
652 pub fn get_active_mut(&mut self) -> Result<&mut Path> {
653 self.paths
654 .iter_mut()
655 .map(|(_, p)| p)
656 .find(|p| p.active())
657 .ok_or(Error::InvalidState)
658 }
659
660 #[inline]
662 pub fn iter(&self) -> slab::Iter<Path> {
663 self.paths.iter()
664 }
665
666 #[inline]
668 pub fn iter_mut(&mut self) -> slab::IterMut<Path> {
669 self.paths.iter_mut()
670 }
671
672 #[inline]
674 pub fn len(&self) -> usize {
675 self.paths.len()
676 }
677
678 #[inline]
680 pub fn path_id_from_addrs(
681 &self, addrs: &(SocketAddr, SocketAddr),
682 ) -> Option<usize> {
683 self.addrs_to_paths.get(addrs).copied()
684 }
685
686 fn make_room_for_new_path(&mut self) -> Result<()> {
692 if self.paths.len() < self.max_concurrent_paths {
693 return Ok(());
694 }
695
696 let (pid_to_remove, _) = self
697 .paths
698 .iter()
699 .find(|(_, p)| p.unused())
700 .ok_or(Error::Done)?;
701
702 let path = self.paths.remove(pid_to_remove);
703 self.addrs_to_paths
704 .remove(&(path.local_addr, path.peer_addr));
705
706 self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
707
708 Ok(())
709 }
710
711 pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
722 self.make_room_for_new_path()?;
723
724 let local_addr = path.local_addr;
725 let peer_addr = path.peer_addr;
726
727 let pid = self.paths.insert(path);
728 self.addrs_to_paths.insert((local_addr, peer_addr), pid);
729
730 if is_server {
732 self.notify_event(PathEvent::New(local_addr, peer_addr));
733 }
734
735 Ok(pid)
736 }
737
738 pub fn notify_event(&mut self, ev: PathEvent) {
740 self.events.push_back(ev);
741 }
742
743 pub fn pop_event(&mut self) -> Option<PathEvent> {
745 self.events.pop_front()
746 }
747
748 pub fn notify_failed_validations(&mut self) {
750 let validation_failed = self
751 .paths
752 .iter_mut()
753 .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
754
755 for (_, p) in validation_failed {
756 self.events.push_back(PathEvent::FailedValidation(
757 p.local_addr,
758 p.peer_addr,
759 ));
760
761 p.failure_notified = true;
762 }
763 }
764
765 pub fn find_candidate_path(&self) -> Option<usize> {
767 self.paths
769 .iter()
770 .find(|(_, p)| p.usable())
771 .map(|(pid, _)| pid)
772 }
773
774 pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
776 let active_pid = self.get_active_path_id()?;
777
778 let challenge_pending =
779 self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
780
781 if let Some((pid, p)) = challenge_pending {
782 if p.on_response_received(data) {
783 let local_addr = p.local_addr;
784 let peer_addr = p.peer_addr;
785 let was_migrating = p.migrating;
786
787 p.migrating = false;
788
789 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
791
792 if pid == active_pid && was_migrating {
795 self.notify_event(PathEvent::PeerMigrated(
796 local_addr, peer_addr,
797 ));
798 }
799 }
800 }
801 Ok(())
802 }
803
804 pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
815 let is_server = self.is_server;
816
817 if let Ok(old_active_path) = self.get_active_mut() {
818 old_active_path.active = false;
819 }
820
821 let new_active_path = self.get_mut(path_id)?;
822 new_active_path.active = true;
823
824 if is_server {
825 if new_active_path.validated() {
826 let local_addr = new_active_path.local_addr();
827 let peer_addr = new_active_path.peer_addr();
828
829 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
830 } else {
831 new_active_path.migrating = true;
832
833 if !new_active_path.under_validation() {
835 new_active_path.request_validation();
836 }
837 }
838 }
839
840 Ok(())
841 }
842}
843
844#[derive(Clone)]
851pub struct PathStats {
852 pub local_addr: SocketAddr,
854
855 pub peer_addr: SocketAddr,
857
858 pub validation_state: PathState,
860
861 pub active: bool,
863
864 pub recv: usize,
866
867 pub sent: usize,
869
870 pub lost: usize,
872
873 pub retrans: usize,
875
876 pub dgram_recv: usize,
878
879 pub dgram_sent: usize,
881
882 pub rtt: time::Duration,
884
885 pub min_rtt: Option<time::Duration>,
887
888 pub rttvar: time::Duration,
891
892 pub cwnd: usize,
894
895 pub sent_bytes: u64,
897
898 pub recv_bytes: u64,
900
901 pub lost_bytes: u64,
903
904 pub stream_retrans_bytes: u64,
906
907 pub pmtu: usize,
909
910 pub delivery_rate: u64,
919}
920
921impl std::fmt::Debug for PathStats {
922 #[inline]
923 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
924 write!(
925 f,
926 "local_addr={:?} peer_addr={:?} ",
927 self.local_addr, self.peer_addr,
928 )?;
929 write!(
930 f,
931 "validation_state={:?} active={} ",
932 self.validation_state, self.active,
933 )?;
934 write!(
935 f,
936 "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
937 self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
938 )?;
939
940 write!(
941 f,
942 " sent_bytes={} recv_bytes={} lost_bytes={}",
943 self.sent_bytes, self.recv_bytes, self.lost_bytes,
944 )?;
945
946 write!(
947 f,
948 " stream_retrans_bytes={} pmtu={} delivery_rate={}",
949 self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
950 )
951 }
952}
953
954#[cfg(test)]
955mod tests {
956 use crate::rand;
957 use crate::MIN_CLIENT_INITIAL_LEN;
958
959 use crate::recovery::RecoveryConfig;
960 use crate::Config;
961
962 use super::*;
963
964 #[test]
965 fn path_validation_limited_mtu() {
966 let client_addr = "127.0.0.1:1234".parse().unwrap();
967 let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
968 let server_addr = "127.0.0.1:4321".parse().unwrap();
969
970 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
971 let recovery_config = RecoveryConfig::from_config(&config);
972
973 let path = Path::new(
974 client_addr,
975 server_addr,
976 &recovery_config,
977 config.path_challenge_recv_max_queue_len,
978 1200,
979 true,
980 );
981 let mut path_mgr = PathMap::new(path, 2, false, true, 1200);
982
983 let probed_path = Path::new(
984 client_addr_2,
985 server_addr,
986 &recovery_config,
987 config.path_challenge_recv_max_queue_len,
988 1200,
989 false,
990 );
991 path_mgr.insert_path(probed_path, false).unwrap();
992
993 let pid = path_mgr
994 .path_id_from_addrs(&(client_addr_2, server_addr))
995 .unwrap();
996 path_mgr.get_mut(pid).unwrap().request_validation();
997 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
998 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
999
1000 let data = rand::rand_u64().to_be_bytes();
1003 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1004 data,
1005 MIN_CLIENT_INITIAL_LEN - 1,
1006 time::Instant::now(),
1007 );
1008
1009 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1010 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1011 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1012 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1013 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1014 assert_eq!(path_mgr.pop_event(), None);
1015
1016 path_mgr.on_response_received(data).unwrap();
1019
1020 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1021 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1022 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1023 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1024 assert_eq!(
1025 path_mgr.get_mut(pid).unwrap().state,
1026 PathState::ValidatingMTU
1027 );
1028 assert_eq!(path_mgr.pop_event(), None);
1029
1030 let data = rand::rand_u64().to_be_bytes();
1033 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1034 data,
1035 MIN_CLIENT_INITIAL_LEN,
1036 time::Instant::now(),
1037 );
1038
1039 path_mgr.on_response_received(data).unwrap();
1040
1041 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1042 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1043 assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1044 assert!(path_mgr.get_mut(pid).unwrap().validated());
1045 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1046 assert_eq!(
1047 path_mgr.pop_event(),
1048 Some(PathEvent::Validated(client_addr_2, server_addr))
1049 );
1050 }
1051
1052 #[test]
1053 fn multiple_probes() {
1054 let client_addr = "127.0.0.1:1234".parse().unwrap();
1055 let server_addr = "127.0.0.1:4321".parse().unwrap();
1056
1057 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1058 let recovery_config = RecoveryConfig::from_config(&config);
1059
1060 let path = Path::new(
1061 client_addr,
1062 server_addr,
1063 &recovery_config,
1064 config.path_challenge_recv_max_queue_len,
1065 1200,
1066 true,
1067 );
1068 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1069 let mut server_path = Path::new(
1070 server_addr,
1071 client_addr,
1072 &recovery_config,
1073 config.path_challenge_recv_max_queue_len,
1074 1200,
1075 false,
1076 );
1077
1078 let client_pid = client_path_mgr
1079 .path_id_from_addrs(&(client_addr, server_addr))
1080 .unwrap();
1081
1082 let data = rand::rand_u64().to_be_bytes();
1084
1085 client_path_mgr
1086 .get_mut(client_pid)
1087 .unwrap()
1088 .add_challenge_sent(
1089 data,
1090 MIN_CLIENT_INITIAL_LEN,
1091 time::Instant::now(),
1092 );
1093
1094 let data_2 = rand::rand_u64().to_be_bytes();
1096
1097 client_path_mgr
1098 .get_mut(client_pid)
1099 .unwrap()
1100 .add_challenge_sent(
1101 data_2,
1102 MIN_CLIENT_INITIAL_LEN,
1103 time::Instant::now(),
1104 );
1105 assert_eq!(
1106 client_path_mgr
1107 .get(client_pid)
1108 .unwrap()
1109 .in_flight_challenges
1110 .len(),
1111 2
1112 );
1113
1114 server_path.on_challenge_received(data);
1116 assert_eq!(server_path.received_challenges.len(), 1);
1117 server_path.on_challenge_received(data_2);
1118 assert_eq!(server_path.received_challenges.len(), 2);
1119
1120 client_path_mgr.on_response_received(data).unwrap();
1122 assert_eq!(
1123 client_path_mgr
1124 .get(client_pid)
1125 .unwrap()
1126 .in_flight_challenges
1127 .len(),
1128 1
1129 );
1130
1131 client_path_mgr.on_response_received(data_2).unwrap();
1133 assert_eq!(
1134 client_path_mgr
1135 .get(client_pid)
1136 .unwrap()
1137 .in_flight_challenges
1138 .len(),
1139 0
1140 );
1141 }
1142
1143 #[test]
1144 fn too_many_probes() {
1145 let client_addr = "127.0.0.1:1234".parse().unwrap();
1146 let server_addr = "127.0.0.1:4321".parse().unwrap();
1147
1148 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1150 let recovery_config = RecoveryConfig::from_config(&config);
1151
1152 let path = Path::new(
1153 client_addr,
1154 server_addr,
1155 &recovery_config,
1156 config.path_challenge_recv_max_queue_len,
1157 1200,
1158 true,
1159 );
1160 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1161 let mut server_path = Path::new(
1162 server_addr,
1163 client_addr,
1164 &recovery_config,
1165 config.path_challenge_recv_max_queue_len,
1166 1200,
1167 false,
1168 );
1169
1170 let client_pid = client_path_mgr
1171 .path_id_from_addrs(&(client_addr, server_addr))
1172 .unwrap();
1173
1174 let data = rand::rand_u64().to_be_bytes();
1176
1177 client_path_mgr
1178 .get_mut(client_pid)
1179 .unwrap()
1180 .add_challenge_sent(
1181 data,
1182 MIN_CLIENT_INITIAL_LEN,
1183 time::Instant::now(),
1184 );
1185
1186 let data_2 = rand::rand_u64().to_be_bytes();
1188
1189 client_path_mgr
1190 .get_mut(client_pid)
1191 .unwrap()
1192 .add_challenge_sent(
1193 data_2,
1194 MIN_CLIENT_INITIAL_LEN,
1195 time::Instant::now(),
1196 );
1197 assert_eq!(
1198 client_path_mgr
1199 .get(client_pid)
1200 .unwrap()
1201 .in_flight_challenges
1202 .len(),
1203 2
1204 );
1205
1206 let data_3 = rand::rand_u64().to_be_bytes();
1208
1209 client_path_mgr
1210 .get_mut(client_pid)
1211 .unwrap()
1212 .add_challenge_sent(
1213 data_3,
1214 MIN_CLIENT_INITIAL_LEN,
1215 time::Instant::now(),
1216 );
1217 assert_eq!(
1218 client_path_mgr
1219 .get(client_pid)
1220 .unwrap()
1221 .in_flight_challenges
1222 .len(),
1223 3
1224 );
1225
1226 let data_4 = rand::rand_u64().to_be_bytes();
1228
1229 client_path_mgr
1230 .get_mut(client_pid)
1231 .unwrap()
1232 .add_challenge_sent(
1233 data_4,
1234 MIN_CLIENT_INITIAL_LEN,
1235 time::Instant::now(),
1236 );
1237 assert_eq!(
1238 client_path_mgr
1239 .get(client_pid)
1240 .unwrap()
1241 .in_flight_challenges
1242 .len(),
1243 4
1244 );
1245
1246 server_path.on_challenge_received(data);
1249 assert_eq!(server_path.received_challenges.len(), 1);
1250 server_path.on_challenge_received(data_2);
1251 assert_eq!(server_path.received_challenges.len(), 2);
1252 server_path.on_challenge_received(data_3);
1253 assert_eq!(server_path.received_challenges.len(), 3);
1254 server_path.on_challenge_received(data_4);
1255 assert_eq!(server_path.received_challenges.len(), 3);
1256
1257 client_path_mgr.on_response_received(data).unwrap();
1259 assert_eq!(
1260 client_path_mgr
1261 .get(client_pid)
1262 .unwrap()
1263 .in_flight_challenges
1264 .len(),
1265 3
1266 );
1267
1268 client_path_mgr.on_response_received(data_2).unwrap();
1270 assert_eq!(
1271 client_path_mgr
1272 .get(client_pid)
1273 .unwrap()
1274 .in_flight_challenges
1275 .len(),
1276 2
1277 );
1278
1279 client_path_mgr.on_response_received(data_3).unwrap();
1281 assert_eq!(
1282 client_path_mgr
1283 .get(client_pid)
1284 .unwrap()
1285 .in_flight_challenges
1286 .len(),
1287 1
1288 );
1289
1290 }
1292}