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;
43
44#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
46pub enum PathState {
47 Failed,
49
50 Unknown,
52
53 Validating,
55
56 ValidatingMTU,
58
59 Validated,
61}
62
63impl PathState {
64 #[cfg(feature = "ffi")]
65 pub fn to_c(self) -> libc::ssize_t {
66 match self {
67 PathState::Failed => -1,
68 PathState::Unknown => 0,
69 PathState::Validating => 1,
70 PathState::ValidatingMTU => 2,
71 PathState::Validated => 3,
72 }
73 }
74}
75
76#[derive(Clone, Debug, PartialEq, Eq)]
78pub enum PathEvent {
79 New(SocketAddr, SocketAddr),
84
85 Validated(SocketAddr, SocketAddr),
88
89 FailedValidation(SocketAddr, SocketAddr),
93
94 Closed(SocketAddr, SocketAddr),
97
98 ReusedSourceConnectionId(
102 u64,
103 (SocketAddr, SocketAddr),
104 (SocketAddr, SocketAddr),
105 ),
106
107 PeerMigrated(SocketAddr, SocketAddr),
113}
114
115#[derive(Debug)]
117pub struct Path {
118 local_addr: SocketAddr,
120
121 peer_addr: SocketAddr,
123
124 pub active_scid_seq: Option<u64>,
126
127 pub active_dcid_seq: Option<u64>,
129
130 state: PathState,
132
133 active: bool,
135
136 pub recovery: recovery::Recovery,
138
139 pub pmtud: pmtud::Pmtud,
141
142 in_flight_challenges: VecDeque<([u8; 8], usize, time::Instant)>,
145
146 max_challenge_size: usize,
148
149 probing_lost: usize,
151
152 last_probe_lost_time: Option<time::Instant>,
154
155 received_challenges: VecDeque<[u8; 8]>,
157
158 received_challenges_max_len: usize,
160
161 pub sent_count: usize,
163
164 pub recv_count: usize,
166
167 pub retrans_count: usize,
169
170 pub dgram_sent_count: usize,
172
173 pub dgram_recv_count: usize,
175
176 pub sent_bytes: u64,
178
179 pub recv_bytes: u64,
181
182 pub stream_retrans_bytes: u64,
185
186 pub max_send_bytes: usize,
189
190 pub verified_peer_address: bool,
192
193 pub peer_verified_local_address: bool,
195
196 challenge_requested: bool,
198
199 failure_notified: bool,
201
202 migrating: bool,
205
206 pub needs_ack_eliciting: bool,
208}
209
210impl Path {
211 pub fn new(
214 local_addr: SocketAddr, peer_addr: SocketAddr,
215 recovery_config: &recovery::RecoveryConfig,
216 path_challenge_recv_max_queue_len: usize, pmtud_init: usize,
217 is_initial: bool,
218 ) -> Self {
219 let (state, active_scid_seq, active_dcid_seq) = if is_initial {
220 (PathState::Validated, Some(0), Some(0))
221 } else {
222 (PathState::Unknown, None, None)
223 };
224
225 Self {
226 local_addr,
227 peer_addr,
228 active_scid_seq,
229 active_dcid_seq,
230 state,
231 active: false,
232 recovery: recovery::Recovery::new_with_config(recovery_config),
233 pmtud: pmtud::Pmtud::new(pmtud_init),
234 in_flight_challenges: VecDeque::new(),
235 max_challenge_size: 0,
236 probing_lost: 0,
237 last_probe_lost_time: None,
238 received_challenges: VecDeque::with_capacity(
239 path_challenge_recv_max_queue_len,
240 ),
241 received_challenges_max_len: path_challenge_recv_max_queue_len,
242 sent_count: 0,
243 recv_count: 0,
244 retrans_count: 0,
245 dgram_sent_count: 0,
246 dgram_recv_count: 0,
247 sent_bytes: 0,
248 recv_bytes: 0,
249 stream_retrans_bytes: 0,
250 max_send_bytes: 0,
251 verified_peer_address: false,
252 peer_verified_local_address: false,
253 challenge_requested: false,
254 failure_notified: false,
255 migrating: false,
256 needs_ack_eliciting: false,
257 }
258 }
259
260 #[inline]
262 pub fn local_addr(&self) -> SocketAddr {
263 self.local_addr
264 }
265
266 #[inline]
268 pub fn peer_addr(&self) -> SocketAddr {
269 self.peer_addr
270 }
271
272 #[inline]
274 fn working(&self) -> bool {
275 self.state > PathState::Failed
276 }
277
278 #[inline]
280 pub fn active(&self) -> bool {
281 self.active && self.working() && self.active_dcid_seq.is_some()
282 }
283
284 #[inline]
286 pub fn usable(&self) -> bool {
287 self.active() ||
288 (self.state == PathState::Validated &&
289 self.active_dcid_seq.is_some())
290 }
291
292 #[inline]
294 fn unused(&self) -> bool {
295 !self.active() && self.active_dcid_seq.is_none()
297 }
298
299 #[inline]
301 pub fn probing_required(&self) -> bool {
302 !self.received_challenges.is_empty() || self.validation_requested()
303 }
304
305 fn promote_to(&mut self, state: PathState) {
308 if self.state < state {
309 self.state = state;
310 }
311 }
312
313 #[inline]
315 pub fn validated(&self) -> bool {
316 self.state == PathState::Validated
317 }
318
319 #[inline]
321 fn validation_failed(&self) -> bool {
322 self.state == PathState::Failed
323 }
324
325 #[inline]
327 pub fn under_validation(&self) -> bool {
328 matches!(self.state, PathState::Validating | PathState::ValidatingMTU)
329 }
330
331 #[inline]
333 pub fn request_validation(&mut self) {
334 self.challenge_requested = true;
335 }
336
337 #[inline]
339 pub fn validation_requested(&self) -> bool {
340 self.challenge_requested
341 }
342
343 pub fn should_send_pmtu_probe(
344 &mut self, hs_confirmed: bool, hs_done: bool, out_len: usize,
345 is_closing: bool, frames_empty: bool,
346 ) -> bool {
347 (hs_confirmed && hs_done) &&
348 self.pmtud.get_probe_size() > self.pmtud.get_current() &&
349 self.recovery.cwnd_available() > self.pmtud.get_probe_size() &&
350 out_len >= self.pmtud.get_probe_size() &&
351 self.pmtud.get_probe_status() &&
352 !is_closing &&
353 frames_empty
354 }
355
356 pub fn on_challenge_sent(&mut self) {
357 self.promote_to(PathState::Validating);
358 self.challenge_requested = false;
359 }
360
361 pub fn add_challenge_sent(
363 &mut self, data: [u8; 8], pkt_size: usize, sent_time: time::Instant,
364 ) {
365 self.on_challenge_sent();
366 self.in_flight_challenges
367 .push_back((data, pkt_size, sent_time));
368 }
369
370 pub fn on_challenge_received(&mut self, data: [u8; 8]) {
371 if self.received_challenges.len() == self.received_challenges_max_len {
373 return;
374 }
375
376 self.received_challenges.push_back(data);
377 self.peer_verified_local_address = true;
378 }
379
380 pub fn has_pending_challenge(&self, data: [u8; 8]) -> bool {
381 self.in_flight_challenges.iter().any(|(d, ..)| *d == data)
382 }
383
384 pub fn on_response_received(&mut self, data: [u8; 8]) -> bool {
386 self.verified_peer_address = true;
387 self.probing_lost = 0;
388
389 let mut challenge_size = 0;
390 self.in_flight_challenges.retain(|(d, s, _)| {
391 if *d == data {
392 challenge_size = *s;
393 false
394 } else {
395 true
396 }
397 });
398
399 self.promote_to(PathState::ValidatingMTU);
401
402 self.max_challenge_size =
403 std::cmp::max(self.max_challenge_size, challenge_size);
404
405 if self.state == PathState::ValidatingMTU {
406 if self.max_challenge_size >= crate::MIN_CLIENT_INITIAL_LEN {
407 self.promote_to(PathState::Validated);
409 return true;
410 }
411
412 self.request_validation();
414 }
415
416 false
417 }
418
419 fn on_failed_validation(&mut self) {
420 self.state = PathState::Failed;
421 self.active = false;
422 }
423
424 #[inline]
425 pub fn pop_received_challenge(&mut self) -> Option<[u8; 8]> {
426 self.received_challenges.pop_front()
427 }
428
429 pub fn on_loss_detection_timeout(
430 &mut self, handshake_status: HandshakeStatus, now: time::Instant,
431 is_server: bool, trace_id: &str,
432 ) -> (usize, usize) {
433 let (lost_packets, lost_bytes) = self.recovery.on_loss_detection_timeout(
434 handshake_status,
435 now,
436 trace_id,
437 );
438
439 let mut lost_probe_time = None;
440 self.in_flight_challenges.retain(|(_, _, sent_time)| {
441 if *sent_time <= now {
442 if lost_probe_time.is_none() {
443 lost_probe_time = Some(*sent_time);
444 }
445 false
446 } else {
447 true
448 }
449 });
450
451 if let Some(lost_probe_time) = lost_probe_time {
454 self.last_probe_lost_time = match self.last_probe_lost_time {
455 Some(last) => {
456 if lost_probe_time - last >= self.recovery.rtt() {
458 self.probing_lost += 1;
459 Some(lost_probe_time)
460 } else {
461 Some(last)
462 }
463 },
464 None => {
465 self.probing_lost += 1;
466 Some(lost_probe_time)
467 },
468 };
469 if self.probing_lost >= crate::MAX_PROBING_TIMEOUTS ||
473 (is_server && self.max_send_bytes < crate::MIN_PROBING_SIZE)
474 {
475 self.on_failed_validation();
476 } else {
477 self.request_validation();
478 }
479 }
480
481 (lost_packets, lost_bytes)
482 }
483
484 pub fn reinit_recovery(
485 &mut self, recovery_config: &recovery::RecoveryConfig,
486 ) {
487 self.recovery = recovery::Recovery::new_with_config(recovery_config)
488 }
489
490 pub fn stats(&self) -> PathStats {
491 PathStats {
492 local_addr: self.local_addr,
493 peer_addr: self.peer_addr,
494 validation_state: self.state,
495 active: self.active,
496 recv: self.recv_count,
497 sent: self.sent_count,
498 lost: self.recovery.lost_count(),
499 retrans: self.retrans_count,
500 dgram_recv: self.dgram_recv_count,
501 dgram_sent: self.dgram_sent_count,
502 rtt: self.recovery.rtt(),
503 min_rtt: self.recovery.min_rtt(),
504 rttvar: self.recovery.rttvar(),
505 cwnd: self.recovery.cwnd(),
506 sent_bytes: self.sent_bytes,
507 recv_bytes: self.recv_bytes,
508 lost_bytes: self.recovery.bytes_lost,
509 stream_retrans_bytes: self.stream_retrans_bytes,
510 pmtu: self.recovery.max_datagram_size(),
511 delivery_rate: self.recovery.delivery_rate(),
512 }
513 }
514}
515
516#[derive(Default)]
518pub struct SocketAddrIter {
519 pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
520 pub(crate) index: usize,
521}
522
523impl Iterator for SocketAddrIter {
524 type Item = SocketAddr;
525
526 #[inline]
527 fn next(&mut self) -> Option<Self::Item> {
528 let v = self.sockaddrs.get(self.index)?;
529 self.index += 1;
530 Some(*v)
531 }
532}
533
534impl ExactSizeIterator for SocketAddrIter {
535 #[inline]
536 fn len(&self) -> usize {
537 self.sockaddrs.len() - self.index
538 }
539}
540
541pub struct PathMap {
543 paths: Slab<Path>,
546
547 max_concurrent_paths: usize,
549
550 addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
553
554 events: VecDeque<PathEvent>,
556
557 is_server: bool,
559}
560
561impl PathMap {
562 pub fn new(
565 mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
566 enable_pmtud: bool, max_send_udp_payload_size: usize,
567 ) -> Self {
568 let mut paths = Slab::with_capacity(1); let mut addrs_to_paths = BTreeMap::new();
570
571 let local_addr = initial_path.local_addr;
572 let peer_addr = initial_path.peer_addr;
573
574 initial_path.active = true;
576
577 if enable_pmtud {
580 initial_path.pmtud.should_probe(enable_pmtud);
581 initial_path.pmtud.set_probe_size(max_send_udp_payload_size);
582 initial_path.pmtud.enable(enable_pmtud);
583 }
584
585 let active_path_id = paths.insert(initial_path);
586 addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
587
588 Self {
589 paths,
590 max_concurrent_paths,
591 addrs_to_paths,
592 events: VecDeque::new(),
593 is_server,
594 }
595 }
596
597 #[inline]
603 pub fn get(&self, path_id: usize) -> Result<&Path> {
604 self.paths.get(path_id).ok_or(Error::InvalidState)
605 }
606
607 #[inline]
613 pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
614 self.paths.get_mut(path_id).ok_or(Error::InvalidState)
615 }
616
617 #[inline]
618 pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
621 self.paths.iter().find(|(_, p)| p.active())
622 }
623
624 #[inline]
629 pub fn get_active(&self) -> Result<&Path> {
630 self.get_active_with_pid()
631 .map(|(_, p)| p)
632 .ok_or(Error::InvalidState)
633 }
634
635 #[inline]
640 pub fn get_active_path_id(&self) -> Result<usize> {
641 self.get_active_with_pid()
642 .map(|(pid, _)| pid)
643 .ok_or(Error::InvalidState)
644 }
645
646 #[inline]
651 pub fn get_active_mut(&mut self) -> Result<&mut Path> {
652 self.paths
653 .iter_mut()
654 .map(|(_, p)| p)
655 .find(|p| p.active())
656 .ok_or(Error::InvalidState)
657 }
658
659 #[inline]
661 pub fn iter(&self) -> slab::Iter<Path> {
662 self.paths.iter()
663 }
664
665 #[inline]
667 pub fn iter_mut(&mut self) -> slab::IterMut<Path> {
668 self.paths.iter_mut()
669 }
670
671 #[inline]
673 pub fn len(&self) -> usize {
674 self.paths.len()
675 }
676
677 #[inline]
679 pub fn path_id_from_addrs(
680 &self, addrs: &(SocketAddr, SocketAddr),
681 ) -> Option<usize> {
682 self.addrs_to_paths.get(addrs).copied()
683 }
684
685 fn make_room_for_new_path(&mut self) -> Result<()> {
691 if self.paths.len() < self.max_concurrent_paths {
692 return Ok(());
693 }
694
695 let (pid_to_remove, _) = self
696 .paths
697 .iter()
698 .find(|(_, p)| p.unused())
699 .ok_or(Error::Done)?;
700
701 let path = self.paths.remove(pid_to_remove);
702 self.addrs_to_paths
703 .remove(&(path.local_addr, path.peer_addr));
704
705 self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
706
707 Ok(())
708 }
709
710 pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
721 self.make_room_for_new_path()?;
722
723 let local_addr = path.local_addr;
724 let peer_addr = path.peer_addr;
725
726 let pid = self.paths.insert(path);
727 self.addrs_to_paths.insert((local_addr, peer_addr), pid);
728
729 if is_server {
731 self.notify_event(PathEvent::New(local_addr, peer_addr));
732 }
733
734 Ok(pid)
735 }
736
737 pub fn notify_event(&mut self, ev: PathEvent) {
739 self.events.push_back(ev);
740 }
741
742 pub fn pop_event(&mut self) -> Option<PathEvent> {
744 self.events.pop_front()
745 }
746
747 pub fn notify_failed_validations(&mut self) {
749 let validation_failed = self
750 .paths
751 .iter_mut()
752 .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
753
754 for (_, p) in validation_failed {
755 self.events.push_back(PathEvent::FailedValidation(
756 p.local_addr,
757 p.peer_addr,
758 ));
759
760 p.failure_notified = true;
761 }
762 }
763
764 pub fn find_candidate_path(&self) -> Option<usize> {
766 self.paths
768 .iter()
769 .find(|(_, p)| p.usable())
770 .map(|(pid, _)| pid)
771 }
772
773 pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
775 let active_pid = self.get_active_path_id()?;
776
777 let challenge_pending =
778 self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
779
780 if let Some((pid, p)) = challenge_pending {
781 if p.on_response_received(data) {
782 let local_addr = p.local_addr;
783 let peer_addr = p.peer_addr;
784 let was_migrating = p.migrating;
785
786 p.migrating = false;
787
788 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
790
791 if pid == active_pid && was_migrating {
794 self.notify_event(PathEvent::PeerMigrated(
795 local_addr, peer_addr,
796 ));
797 }
798 }
799 }
800 Ok(())
801 }
802
803 pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
814 let is_server = self.is_server;
815
816 if let Ok(old_active_path) = self.get_active_mut() {
817 old_active_path.active = false;
818 }
819
820 let new_active_path = self.get_mut(path_id)?;
821 new_active_path.active = true;
822
823 if is_server {
824 if new_active_path.validated() {
825 let local_addr = new_active_path.local_addr();
826 let peer_addr = new_active_path.peer_addr();
827
828 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
829 } else {
830 new_active_path.migrating = true;
831
832 if !new_active_path.under_validation() {
834 new_active_path.request_validation();
835 }
836 }
837 }
838
839 Ok(())
840 }
841}
842
843#[derive(Clone)]
850pub struct PathStats {
851 pub local_addr: SocketAddr,
853
854 pub peer_addr: SocketAddr,
856
857 pub validation_state: PathState,
859
860 pub active: bool,
862
863 pub recv: usize,
865
866 pub sent: usize,
868
869 pub lost: usize,
871
872 pub retrans: usize,
874
875 pub dgram_recv: usize,
877
878 pub dgram_sent: usize,
880
881 pub rtt: time::Duration,
883
884 pub min_rtt: Option<time::Duration>,
886
887 pub rttvar: time::Duration,
890
891 pub cwnd: usize,
893
894 pub sent_bytes: u64,
896
897 pub recv_bytes: u64,
899
900 pub lost_bytes: u64,
902
903 pub stream_retrans_bytes: u64,
905
906 pub pmtu: usize,
908
909 pub delivery_rate: u64,
918}
919
920impl std::fmt::Debug for PathStats {
921 #[inline]
922 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
923 write!(
924 f,
925 "local_addr={:?} peer_addr={:?} ",
926 self.local_addr, self.peer_addr,
927 )?;
928 write!(
929 f,
930 "validation_state={:?} active={} ",
931 self.validation_state, self.active,
932 )?;
933 write!(
934 f,
935 "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
936 self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
937 )?;
938
939 write!(
940 f,
941 " sent_bytes={} recv_bytes={} lost_bytes={}",
942 self.sent_bytes, self.recv_bytes, self.lost_bytes,
943 )?;
944
945 write!(
946 f,
947 " stream_retrans_bytes={} pmtu={} delivery_rate={}",
948 self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
949 )
950 }
951}
952
953#[cfg(test)]
954mod tests {
955 use crate::rand;
956 use crate::MIN_CLIENT_INITIAL_LEN;
957
958 use crate::recovery::RecoveryConfig;
959 use crate::Config;
960
961 use super::*;
962
963 #[test]
964 fn path_validation_limited_mtu() {
965 let client_addr = "127.0.0.1:1234".parse().unwrap();
966 let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
967 let server_addr = "127.0.0.1:4321".parse().unwrap();
968
969 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
970 let recovery_config = RecoveryConfig::from_config(&config);
971
972 let path = Path::new(
973 client_addr,
974 server_addr,
975 &recovery_config,
976 config.path_challenge_recv_max_queue_len,
977 1200,
978 true,
979 );
980 let mut path_mgr = PathMap::new(path, 2, false, true, 1200);
981
982 let probed_path = Path::new(
983 client_addr_2,
984 server_addr,
985 &recovery_config,
986 config.path_challenge_recv_max_queue_len,
987 1200,
988 false,
989 );
990 path_mgr.insert_path(probed_path, false).unwrap();
991
992 let pid = path_mgr
993 .path_id_from_addrs(&(client_addr_2, server_addr))
994 .unwrap();
995 path_mgr.get_mut(pid).unwrap().request_validation();
996 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
997 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
998
999 let data = rand::rand_u64().to_be_bytes();
1002 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1003 data,
1004 MIN_CLIENT_INITIAL_LEN - 1,
1005 time::Instant::now(),
1006 );
1007
1008 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1009 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1010 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1011 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1012 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1013 assert_eq!(path_mgr.pop_event(), None);
1014
1015 path_mgr.on_response_received(data).unwrap();
1018
1019 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1020 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1021 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1022 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1023 assert_eq!(
1024 path_mgr.get_mut(pid).unwrap().state,
1025 PathState::ValidatingMTU
1026 );
1027 assert_eq!(path_mgr.pop_event(), None);
1028
1029 let data = rand::rand_u64().to_be_bytes();
1032 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1033 data,
1034 MIN_CLIENT_INITIAL_LEN,
1035 time::Instant::now(),
1036 );
1037
1038 path_mgr.on_response_received(data).unwrap();
1039
1040 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1041 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1042 assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1043 assert!(path_mgr.get_mut(pid).unwrap().validated());
1044 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1045 assert_eq!(
1046 path_mgr.pop_event(),
1047 Some(PathEvent::Validated(client_addr_2, server_addr))
1048 );
1049 }
1050
1051 #[test]
1052 fn multiple_probes() {
1053 let client_addr = "127.0.0.1:1234".parse().unwrap();
1054 let server_addr = "127.0.0.1:4321".parse().unwrap();
1055
1056 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1057 let recovery_config = RecoveryConfig::from_config(&config);
1058
1059 let path = Path::new(
1060 client_addr,
1061 server_addr,
1062 &recovery_config,
1063 config.path_challenge_recv_max_queue_len,
1064 1200,
1065 true,
1066 );
1067 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1068 let mut server_path = Path::new(
1069 server_addr,
1070 client_addr,
1071 &recovery_config,
1072 config.path_challenge_recv_max_queue_len,
1073 1200,
1074 false,
1075 );
1076
1077 let client_pid = client_path_mgr
1078 .path_id_from_addrs(&(client_addr, server_addr))
1079 .unwrap();
1080
1081 let data = rand::rand_u64().to_be_bytes();
1083
1084 client_path_mgr
1085 .get_mut(client_pid)
1086 .unwrap()
1087 .add_challenge_sent(
1088 data,
1089 MIN_CLIENT_INITIAL_LEN,
1090 time::Instant::now(),
1091 );
1092
1093 let data_2 = rand::rand_u64().to_be_bytes();
1095
1096 client_path_mgr
1097 .get_mut(client_pid)
1098 .unwrap()
1099 .add_challenge_sent(
1100 data_2,
1101 MIN_CLIENT_INITIAL_LEN,
1102 time::Instant::now(),
1103 );
1104 assert_eq!(
1105 client_path_mgr
1106 .get(client_pid)
1107 .unwrap()
1108 .in_flight_challenges
1109 .len(),
1110 2
1111 );
1112
1113 server_path.on_challenge_received(data);
1115 assert_eq!(server_path.received_challenges.len(), 1);
1116 server_path.on_challenge_received(data_2);
1117 assert_eq!(server_path.received_challenges.len(), 2);
1118
1119 client_path_mgr.on_response_received(data).unwrap();
1121 assert_eq!(
1122 client_path_mgr
1123 .get(client_pid)
1124 .unwrap()
1125 .in_flight_challenges
1126 .len(),
1127 1
1128 );
1129
1130 client_path_mgr.on_response_received(data_2).unwrap();
1132 assert_eq!(
1133 client_path_mgr
1134 .get(client_pid)
1135 .unwrap()
1136 .in_flight_challenges
1137 .len(),
1138 0
1139 );
1140 }
1141
1142 #[test]
1143 fn too_many_probes() {
1144 let client_addr = "127.0.0.1:1234".parse().unwrap();
1145 let server_addr = "127.0.0.1:4321".parse().unwrap();
1146
1147 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1149 let recovery_config = RecoveryConfig::from_config(&config);
1150
1151 let path = Path::new(
1152 client_addr,
1153 server_addr,
1154 &recovery_config,
1155 config.path_challenge_recv_max_queue_len,
1156 1200,
1157 true,
1158 );
1159 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1160 let mut server_path = Path::new(
1161 server_addr,
1162 client_addr,
1163 &recovery_config,
1164 config.path_challenge_recv_max_queue_len,
1165 1200,
1166 false,
1167 );
1168
1169 let client_pid = client_path_mgr
1170 .path_id_from_addrs(&(client_addr, server_addr))
1171 .unwrap();
1172
1173 let data = rand::rand_u64().to_be_bytes();
1175
1176 client_path_mgr
1177 .get_mut(client_pid)
1178 .unwrap()
1179 .add_challenge_sent(
1180 data,
1181 MIN_CLIENT_INITIAL_LEN,
1182 time::Instant::now(),
1183 );
1184
1185 let data_2 = rand::rand_u64().to_be_bytes();
1187
1188 client_path_mgr
1189 .get_mut(client_pid)
1190 .unwrap()
1191 .add_challenge_sent(
1192 data_2,
1193 MIN_CLIENT_INITIAL_LEN,
1194 time::Instant::now(),
1195 );
1196 assert_eq!(
1197 client_path_mgr
1198 .get(client_pid)
1199 .unwrap()
1200 .in_flight_challenges
1201 .len(),
1202 2
1203 );
1204
1205 let data_3 = rand::rand_u64().to_be_bytes();
1207
1208 client_path_mgr
1209 .get_mut(client_pid)
1210 .unwrap()
1211 .add_challenge_sent(
1212 data_3,
1213 MIN_CLIENT_INITIAL_LEN,
1214 time::Instant::now(),
1215 );
1216 assert_eq!(
1217 client_path_mgr
1218 .get(client_pid)
1219 .unwrap()
1220 .in_flight_challenges
1221 .len(),
1222 3
1223 );
1224
1225 let data_4 = rand::rand_u64().to_be_bytes();
1227
1228 client_path_mgr
1229 .get_mut(client_pid)
1230 .unwrap()
1231 .add_challenge_sent(
1232 data_4,
1233 MIN_CLIENT_INITIAL_LEN,
1234 time::Instant::now(),
1235 );
1236 assert_eq!(
1237 client_path_mgr
1238 .get(client_pid)
1239 .unwrap()
1240 .in_flight_challenges
1241 .len(),
1242 4
1243 );
1244
1245 server_path.on_challenge_received(data);
1248 assert_eq!(server_path.received_challenges.len(), 1);
1249 server_path.on_challenge_received(data_2);
1250 assert_eq!(server_path.received_challenges.len(), 2);
1251 server_path.on_challenge_received(data_3);
1252 assert_eq!(server_path.received_challenges.len(), 3);
1253 server_path.on_challenge_received(data_4);
1254 assert_eq!(server_path.received_challenges.len(), 3);
1255
1256 client_path_mgr.on_response_received(data).unwrap();
1258 assert_eq!(
1259 client_path_mgr
1260 .get(client_pid)
1261 .unwrap()
1262 .in_flight_challenges
1263 .len(),
1264 3
1265 );
1266
1267 client_path_mgr.on_response_received(data_2).unwrap();
1269 assert_eq!(
1270 client_path_mgr
1271 .get(client_pid)
1272 .unwrap()
1273 .in_flight_challenges
1274 .len(),
1275 2
1276 );
1277
1278 client_path_mgr.on_response_received(data_3).unwrap();
1280 assert_eq!(
1281 client_path_mgr
1282 .get(client_pid)
1283 .unwrap()
1284 .in_flight_challenges
1285 .len(),
1286 1
1287 );
1288
1289 }
1291}