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 max_rtt: self.recovery.max_rtt(),
506 rttvar: self.recovery.rttvar(),
507 cwnd: self.recovery.cwnd(),
508 sent_bytes: self.sent_bytes,
509 recv_bytes: self.recv_bytes,
510 lost_bytes: self.recovery.bytes_lost(),
511 stream_retrans_bytes: self.stream_retrans_bytes,
512 pmtu: self.recovery.max_datagram_size(),
513 delivery_rate: self.recovery.delivery_rate().to_bytes_per_second(),
514 }
515 }
516}
517
518#[derive(Default)]
520pub struct SocketAddrIter {
521 pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
522 pub(crate) index: usize,
523}
524
525impl Iterator for SocketAddrIter {
526 type Item = SocketAddr;
527
528 #[inline]
529 fn next(&mut self) -> Option<Self::Item> {
530 let v = self.sockaddrs.get(self.index)?;
531 self.index += 1;
532 Some(*v)
533 }
534}
535
536impl ExactSizeIterator for SocketAddrIter {
537 #[inline]
538 fn len(&self) -> usize {
539 self.sockaddrs.len() - self.index
540 }
541}
542
543pub struct PathMap {
545 paths: Slab<Path>,
548
549 max_concurrent_paths: usize,
551
552 addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
555
556 events: VecDeque<PathEvent>,
558
559 is_server: bool,
561}
562
563impl PathMap {
564 pub fn new(
567 mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
568 enable_pmtud: bool, max_send_udp_payload_size: usize,
569 ) -> Self {
570 let mut paths = Slab::with_capacity(1); let mut addrs_to_paths = BTreeMap::new();
572
573 let local_addr = initial_path.local_addr;
574 let peer_addr = initial_path.peer_addr;
575
576 initial_path.active = true;
578
579 if enable_pmtud {
582 initial_path.pmtud.should_probe(enable_pmtud);
583 initial_path.pmtud.set_probe_size(max_send_udp_payload_size);
584 initial_path.pmtud.enable(enable_pmtud);
585 }
586
587 let active_path_id = paths.insert(initial_path);
588 addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
589
590 Self {
591 paths,
592 max_concurrent_paths,
593 addrs_to_paths,
594 events: VecDeque::new(),
595 is_server,
596 }
597 }
598
599 #[inline]
605 pub fn get(&self, path_id: usize) -> Result<&Path> {
606 self.paths.get(path_id).ok_or(Error::InvalidState)
607 }
608
609 #[inline]
615 pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
616 self.paths.get_mut(path_id).ok_or(Error::InvalidState)
617 }
618
619 #[inline]
620 pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
623 self.paths.iter().find(|(_, p)| p.active())
624 }
625
626 #[inline]
631 pub fn get_active(&self) -> Result<&Path> {
632 self.get_active_with_pid()
633 .map(|(_, p)| p)
634 .ok_or(Error::InvalidState)
635 }
636
637 #[inline]
642 pub fn get_active_path_id(&self) -> Result<usize> {
643 self.get_active_with_pid()
644 .map(|(pid, _)| pid)
645 .ok_or(Error::InvalidState)
646 }
647
648 #[inline]
653 pub fn get_active_mut(&mut self) -> Result<&mut Path> {
654 self.paths
655 .iter_mut()
656 .map(|(_, p)| p)
657 .find(|p| p.active())
658 .ok_or(Error::InvalidState)
659 }
660
661 #[inline]
663 pub fn iter(&self) -> slab::Iter<Path> {
664 self.paths.iter()
665 }
666
667 #[inline]
669 pub fn iter_mut(&mut self) -> slab::IterMut<Path> {
670 self.paths.iter_mut()
671 }
672
673 #[inline]
675 pub fn len(&self) -> usize {
676 self.paths.len()
677 }
678
679 #[inline]
681 pub fn path_id_from_addrs(
682 &self, addrs: &(SocketAddr, SocketAddr),
683 ) -> Option<usize> {
684 self.addrs_to_paths.get(addrs).copied()
685 }
686
687 fn make_room_for_new_path(&mut self) -> Result<()> {
693 if self.paths.len() < self.max_concurrent_paths {
694 return Ok(());
695 }
696
697 let (pid_to_remove, _) = self
698 .paths
699 .iter()
700 .find(|(_, p)| p.unused())
701 .ok_or(Error::Done)?;
702
703 let path = self.paths.remove(pid_to_remove);
704 self.addrs_to_paths
705 .remove(&(path.local_addr, path.peer_addr));
706
707 self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
708
709 Ok(())
710 }
711
712 pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
723 self.make_room_for_new_path()?;
724
725 let local_addr = path.local_addr;
726 let peer_addr = path.peer_addr;
727
728 let pid = self.paths.insert(path);
729 self.addrs_to_paths.insert((local_addr, peer_addr), pid);
730
731 if is_server {
733 self.notify_event(PathEvent::New(local_addr, peer_addr));
734 }
735
736 Ok(pid)
737 }
738
739 pub fn notify_event(&mut self, ev: PathEvent) {
741 self.events.push_back(ev);
742 }
743
744 pub fn pop_event(&mut self) -> Option<PathEvent> {
746 self.events.pop_front()
747 }
748
749 pub fn notify_failed_validations(&mut self) {
751 let validation_failed = self
752 .paths
753 .iter_mut()
754 .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
755
756 for (_, p) in validation_failed {
757 self.events.push_back(PathEvent::FailedValidation(
758 p.local_addr,
759 p.peer_addr,
760 ));
761
762 p.failure_notified = true;
763 }
764 }
765
766 pub fn find_candidate_path(&self) -> Option<usize> {
768 self.paths
770 .iter()
771 .find(|(_, p)| p.usable())
772 .map(|(pid, _)| pid)
773 }
774
775 pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
777 let active_pid = self.get_active_path_id()?;
778
779 let challenge_pending =
780 self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
781
782 if let Some((pid, p)) = challenge_pending {
783 if p.on_response_received(data) {
784 let local_addr = p.local_addr;
785 let peer_addr = p.peer_addr;
786 let was_migrating = p.migrating;
787
788 p.migrating = false;
789
790 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
792
793 if pid == active_pid && was_migrating {
796 self.notify_event(PathEvent::PeerMigrated(
797 local_addr, peer_addr,
798 ));
799 }
800 }
801 }
802 Ok(())
803 }
804
805 pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
816 let is_server = self.is_server;
817
818 if let Ok(old_active_path) = self.get_active_mut() {
819 old_active_path.active = false;
820 }
821
822 let new_active_path = self.get_mut(path_id)?;
823 new_active_path.active = true;
824
825 if is_server {
826 if new_active_path.validated() {
827 let local_addr = new_active_path.local_addr();
828 let peer_addr = new_active_path.peer_addr();
829
830 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
831 } else {
832 new_active_path.migrating = true;
833
834 if !new_active_path.under_validation() {
836 new_active_path.request_validation();
837 }
838 }
839 }
840
841 Ok(())
842 }
843}
844
845#[derive(Clone)]
852pub struct PathStats {
853 pub local_addr: SocketAddr,
855
856 pub peer_addr: SocketAddr,
858
859 pub validation_state: PathState,
861
862 pub active: bool,
864
865 pub recv: usize,
867
868 pub sent: usize,
870
871 pub lost: usize,
873
874 pub retrans: usize,
876
877 pub dgram_recv: usize,
879
880 pub dgram_sent: usize,
882
883 pub rtt: time::Duration,
885
886 pub min_rtt: Option<time::Duration>,
888
889 pub max_rtt: Option<time::Duration>,
891
892 pub rttvar: time::Duration,
895
896 pub cwnd: usize,
898
899 pub sent_bytes: u64,
901
902 pub recv_bytes: u64,
904
905 pub lost_bytes: u64,
907
908 pub stream_retrans_bytes: u64,
910
911 pub pmtu: usize,
913
914 pub delivery_rate: u64,
923}
924
925impl std::fmt::Debug for PathStats {
926 #[inline]
927 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
928 write!(
929 f,
930 "local_addr={:?} peer_addr={:?} ",
931 self.local_addr, self.peer_addr,
932 )?;
933 write!(
934 f,
935 "validation_state={:?} active={} ",
936 self.validation_state, self.active,
937 )?;
938 write!(
939 f,
940 "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
941 self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
942 )?;
943
944 write!(
945 f,
946 " sent_bytes={} recv_bytes={} lost_bytes={}",
947 self.sent_bytes, self.recv_bytes, self.lost_bytes,
948 )?;
949
950 write!(
951 f,
952 " stream_retrans_bytes={} pmtu={} delivery_rate={}",
953 self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
954 )
955 }
956}
957
958#[cfg(test)]
959mod tests {
960 use crate::rand;
961 use crate::MIN_CLIENT_INITIAL_LEN;
962
963 use crate::recovery::RecoveryConfig;
964 use crate::Config;
965
966 use super::*;
967
968 #[test]
969 fn path_validation_limited_mtu() {
970 let client_addr = "127.0.0.1:1234".parse().unwrap();
971 let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
972 let server_addr = "127.0.0.1:4321".parse().unwrap();
973
974 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
975 let recovery_config = RecoveryConfig::from_config(&config);
976
977 let path = Path::new(
978 client_addr,
979 server_addr,
980 &recovery_config,
981 config.path_challenge_recv_max_queue_len,
982 1200,
983 true,
984 );
985 let mut path_mgr = PathMap::new(path, 2, false, true, 1200);
986
987 let probed_path = Path::new(
988 client_addr_2,
989 server_addr,
990 &recovery_config,
991 config.path_challenge_recv_max_queue_len,
992 1200,
993 false,
994 );
995 path_mgr.insert_path(probed_path, false).unwrap();
996
997 let pid = path_mgr
998 .path_id_from_addrs(&(client_addr_2, server_addr))
999 .unwrap();
1000 path_mgr.get_mut(pid).unwrap().request_validation();
1001 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1002 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1003
1004 let data = rand::rand_u64().to_be_bytes();
1007 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1008 data,
1009 MIN_CLIENT_INITIAL_LEN - 1,
1010 time::Instant::now(),
1011 );
1012
1013 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1014 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1015 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1016 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1017 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1018 assert_eq!(path_mgr.pop_event(), None);
1019
1020 path_mgr.on_response_received(data).unwrap();
1023
1024 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1025 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1026 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1027 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1028 assert_eq!(
1029 path_mgr.get_mut(pid).unwrap().state,
1030 PathState::ValidatingMTU
1031 );
1032 assert_eq!(path_mgr.pop_event(), None);
1033
1034 let data = rand::rand_u64().to_be_bytes();
1037 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1038 data,
1039 MIN_CLIENT_INITIAL_LEN,
1040 time::Instant::now(),
1041 );
1042
1043 path_mgr.on_response_received(data).unwrap();
1044
1045 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1046 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1047 assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1048 assert!(path_mgr.get_mut(pid).unwrap().validated());
1049 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1050 assert_eq!(
1051 path_mgr.pop_event(),
1052 Some(PathEvent::Validated(client_addr_2, server_addr))
1053 );
1054 }
1055
1056 #[test]
1057 fn multiple_probes() {
1058 let client_addr = "127.0.0.1:1234".parse().unwrap();
1059 let server_addr = "127.0.0.1:4321".parse().unwrap();
1060
1061 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1062 let recovery_config = RecoveryConfig::from_config(&config);
1063
1064 let path = Path::new(
1065 client_addr,
1066 server_addr,
1067 &recovery_config,
1068 config.path_challenge_recv_max_queue_len,
1069 1200,
1070 true,
1071 );
1072 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1073 let mut server_path = Path::new(
1074 server_addr,
1075 client_addr,
1076 &recovery_config,
1077 config.path_challenge_recv_max_queue_len,
1078 1200,
1079 false,
1080 );
1081
1082 let client_pid = client_path_mgr
1083 .path_id_from_addrs(&(client_addr, server_addr))
1084 .unwrap();
1085
1086 let data = rand::rand_u64().to_be_bytes();
1088
1089 client_path_mgr
1090 .get_mut(client_pid)
1091 .unwrap()
1092 .add_challenge_sent(
1093 data,
1094 MIN_CLIENT_INITIAL_LEN,
1095 time::Instant::now(),
1096 );
1097
1098 let data_2 = rand::rand_u64().to_be_bytes();
1100
1101 client_path_mgr
1102 .get_mut(client_pid)
1103 .unwrap()
1104 .add_challenge_sent(
1105 data_2,
1106 MIN_CLIENT_INITIAL_LEN,
1107 time::Instant::now(),
1108 );
1109 assert_eq!(
1110 client_path_mgr
1111 .get(client_pid)
1112 .unwrap()
1113 .in_flight_challenges
1114 .len(),
1115 2
1116 );
1117
1118 server_path.on_challenge_received(data);
1120 assert_eq!(server_path.received_challenges.len(), 1);
1121 server_path.on_challenge_received(data_2);
1122 assert_eq!(server_path.received_challenges.len(), 2);
1123
1124 client_path_mgr.on_response_received(data).unwrap();
1126 assert_eq!(
1127 client_path_mgr
1128 .get(client_pid)
1129 .unwrap()
1130 .in_flight_challenges
1131 .len(),
1132 1
1133 );
1134
1135 client_path_mgr.on_response_received(data_2).unwrap();
1137 assert_eq!(
1138 client_path_mgr
1139 .get(client_pid)
1140 .unwrap()
1141 .in_flight_challenges
1142 .len(),
1143 0
1144 );
1145 }
1146
1147 #[test]
1148 fn too_many_probes() {
1149 let client_addr = "127.0.0.1:1234".parse().unwrap();
1150 let server_addr = "127.0.0.1:4321".parse().unwrap();
1151
1152 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1154 let recovery_config = RecoveryConfig::from_config(&config);
1155
1156 let path = Path::new(
1157 client_addr,
1158 server_addr,
1159 &recovery_config,
1160 config.path_challenge_recv_max_queue_len,
1161 1200,
1162 true,
1163 );
1164 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1165 let mut server_path = Path::new(
1166 server_addr,
1167 client_addr,
1168 &recovery_config,
1169 config.path_challenge_recv_max_queue_len,
1170 1200,
1171 false,
1172 );
1173
1174 let client_pid = client_path_mgr
1175 .path_id_from_addrs(&(client_addr, server_addr))
1176 .unwrap();
1177
1178 let data = rand::rand_u64().to_be_bytes();
1180
1181 client_path_mgr
1182 .get_mut(client_pid)
1183 .unwrap()
1184 .add_challenge_sent(
1185 data,
1186 MIN_CLIENT_INITIAL_LEN,
1187 time::Instant::now(),
1188 );
1189
1190 let data_2 = rand::rand_u64().to_be_bytes();
1192
1193 client_path_mgr
1194 .get_mut(client_pid)
1195 .unwrap()
1196 .add_challenge_sent(
1197 data_2,
1198 MIN_CLIENT_INITIAL_LEN,
1199 time::Instant::now(),
1200 );
1201 assert_eq!(
1202 client_path_mgr
1203 .get(client_pid)
1204 .unwrap()
1205 .in_flight_challenges
1206 .len(),
1207 2
1208 );
1209
1210 let data_3 = rand::rand_u64().to_be_bytes();
1212
1213 client_path_mgr
1214 .get_mut(client_pid)
1215 .unwrap()
1216 .add_challenge_sent(
1217 data_3,
1218 MIN_CLIENT_INITIAL_LEN,
1219 time::Instant::now(),
1220 );
1221 assert_eq!(
1222 client_path_mgr
1223 .get(client_pid)
1224 .unwrap()
1225 .in_flight_challenges
1226 .len(),
1227 3
1228 );
1229
1230 let data_4 = rand::rand_u64().to_be_bytes();
1232
1233 client_path_mgr
1234 .get_mut(client_pid)
1235 .unwrap()
1236 .add_challenge_sent(
1237 data_4,
1238 MIN_CLIENT_INITIAL_LEN,
1239 time::Instant::now(),
1240 );
1241 assert_eq!(
1242 client_path_mgr
1243 .get(client_pid)
1244 .unwrap()
1245 .in_flight_challenges
1246 .len(),
1247 4
1248 );
1249
1250 server_path.on_challenge_received(data);
1253 assert_eq!(server_path.received_challenges.len(), 1);
1254 server_path.on_challenge_received(data_2);
1255 assert_eq!(server_path.received_challenges.len(), 2);
1256 server_path.on_challenge_received(data_3);
1257 assert_eq!(server_path.received_challenges.len(), 3);
1258 server_path.on_challenge_received(data_4);
1259 assert_eq!(server_path.received_challenges.len(), 3);
1260
1261 client_path_mgr.on_response_received(data).unwrap();
1263 assert_eq!(
1264 client_path_mgr
1265 .get(client_pid)
1266 .unwrap()
1267 .in_flight_challenges
1268 .len(),
1269 3
1270 );
1271
1272 client_path_mgr.on_response_received(data_2).unwrap();
1274 assert_eq!(
1275 client_path_mgr
1276 .get(client_pid)
1277 .unwrap()
1278 .in_flight_challenges
1279 .len(),
1280 2
1281 );
1282
1283 client_path_mgr.on_response_received(data_3).unwrap();
1285 assert_eq!(
1286 client_path_mgr
1287 .get(client_pid)
1288 .unwrap()
1289 .in_flight_challenges
1290 .len(),
1291 1
1292 );
1293
1294 }
1296}