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 stats(&self) -> PathStats {
485 PathStats {
486 local_addr: self.local_addr,
487 peer_addr: self.peer_addr,
488 validation_state: self.state,
489 active: self.active,
490 recv: self.recv_count,
491 sent: self.sent_count,
492 lost: self.recovery.lost_count(),
493 retrans: self.retrans_count,
494 dgram_recv: self.dgram_recv_count,
495 dgram_sent: self.dgram_sent_count,
496 rtt: self.recovery.rtt(),
497 min_rtt: self.recovery.min_rtt(),
498 rttvar: self.recovery.rttvar(),
499 cwnd: self.recovery.cwnd(),
500 sent_bytes: self.sent_bytes,
501 recv_bytes: self.recv_bytes,
502 lost_bytes: self.recovery.bytes_lost,
503 stream_retrans_bytes: self.stream_retrans_bytes,
504 pmtu: self.recovery.max_datagram_size(),
505 delivery_rate: self.recovery.delivery_rate(),
506 }
507 }
508}
509
510#[derive(Default)]
512pub struct SocketAddrIter {
513 pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
514 pub(crate) index: usize,
515}
516
517impl Iterator for SocketAddrIter {
518 type Item = SocketAddr;
519
520 #[inline]
521 fn next(&mut self) -> Option<Self::Item> {
522 let v = self.sockaddrs.get(self.index)?;
523 self.index += 1;
524 Some(*v)
525 }
526}
527
528impl ExactSizeIterator for SocketAddrIter {
529 #[inline]
530 fn len(&self) -> usize {
531 self.sockaddrs.len() - self.index
532 }
533}
534
535pub struct PathMap {
537 paths: Slab<Path>,
540
541 max_concurrent_paths: usize,
543
544 addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
547
548 events: VecDeque<PathEvent>,
550
551 is_server: bool,
553}
554
555impl PathMap {
556 pub fn new(
559 mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
560 enable_pmtud: bool, max_send_udp_payload_size: usize,
561 ) -> Self {
562 let mut paths = Slab::with_capacity(1); let mut addrs_to_paths = BTreeMap::new();
564
565 let local_addr = initial_path.local_addr;
566 let peer_addr = initial_path.peer_addr;
567
568 initial_path.active = true;
570
571 if enable_pmtud {
574 initial_path.pmtud.should_probe(enable_pmtud);
575 initial_path.pmtud.set_probe_size(max_send_udp_payload_size);
576 initial_path.pmtud.enable(enable_pmtud);
577 }
578
579 let active_path_id = paths.insert(initial_path);
580 addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
581
582 Self {
583 paths,
584 max_concurrent_paths,
585 addrs_to_paths,
586 events: VecDeque::new(),
587 is_server,
588 }
589 }
590
591 #[inline]
597 pub fn get(&self, path_id: usize) -> Result<&Path> {
598 self.paths.get(path_id).ok_or(Error::InvalidState)
599 }
600
601 #[inline]
607 pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
608 self.paths.get_mut(path_id).ok_or(Error::InvalidState)
609 }
610
611 #[inline]
612 pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
615 self.paths.iter().find(|(_, p)| p.active())
616 }
617
618 #[inline]
623 pub fn get_active(&self) -> Result<&Path> {
624 self.get_active_with_pid()
625 .map(|(_, p)| p)
626 .ok_or(Error::InvalidState)
627 }
628
629 #[inline]
634 pub fn get_active_path_id(&self) -> Result<usize> {
635 self.get_active_with_pid()
636 .map(|(pid, _)| pid)
637 .ok_or(Error::InvalidState)
638 }
639
640 #[inline]
645 pub fn get_active_mut(&mut self) -> Result<&mut Path> {
646 self.paths
647 .iter_mut()
648 .map(|(_, p)| p)
649 .find(|p| p.active())
650 .ok_or(Error::InvalidState)
651 }
652
653 #[inline]
655 pub fn iter(&self) -> slab::Iter<Path> {
656 self.paths.iter()
657 }
658
659 #[inline]
661 pub fn iter_mut(&mut self) -> slab::IterMut<Path> {
662 self.paths.iter_mut()
663 }
664
665 #[inline]
667 pub fn len(&self) -> usize {
668 self.paths.len()
669 }
670
671 #[inline]
673 pub fn path_id_from_addrs(
674 &self, addrs: &(SocketAddr, SocketAddr),
675 ) -> Option<usize> {
676 self.addrs_to_paths.get(addrs).copied()
677 }
678
679 fn make_room_for_new_path(&mut self) -> Result<()> {
685 if self.paths.len() < self.max_concurrent_paths {
686 return Ok(());
687 }
688
689 let (pid_to_remove, _) = self
690 .paths
691 .iter()
692 .find(|(_, p)| p.unused())
693 .ok_or(Error::Done)?;
694
695 let path = self.paths.remove(pid_to_remove);
696 self.addrs_to_paths
697 .remove(&(path.local_addr, path.peer_addr));
698
699 self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
700
701 Ok(())
702 }
703
704 pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
715 self.make_room_for_new_path()?;
716
717 let local_addr = path.local_addr;
718 let peer_addr = path.peer_addr;
719
720 let pid = self.paths.insert(path);
721 self.addrs_to_paths.insert((local_addr, peer_addr), pid);
722
723 if is_server {
725 self.notify_event(PathEvent::New(local_addr, peer_addr));
726 }
727
728 Ok(pid)
729 }
730
731 pub fn notify_event(&mut self, ev: PathEvent) {
733 self.events.push_back(ev);
734 }
735
736 pub fn pop_event(&mut self) -> Option<PathEvent> {
738 self.events.pop_front()
739 }
740
741 pub fn notify_failed_validations(&mut self) {
743 let validation_failed = self
744 .paths
745 .iter_mut()
746 .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
747
748 for (_, p) in validation_failed {
749 self.events.push_back(PathEvent::FailedValidation(
750 p.local_addr,
751 p.peer_addr,
752 ));
753
754 p.failure_notified = true;
755 }
756 }
757
758 pub fn find_candidate_path(&self) -> Option<usize> {
760 self.paths
762 .iter()
763 .find(|(_, p)| p.usable())
764 .map(|(pid, _)| pid)
765 }
766
767 pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
769 let active_pid = self.get_active_path_id()?;
770
771 let challenge_pending =
772 self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
773
774 if let Some((pid, p)) = challenge_pending {
775 if p.on_response_received(data) {
776 let local_addr = p.local_addr;
777 let peer_addr = p.peer_addr;
778 let was_migrating = p.migrating;
779
780 p.migrating = false;
781
782 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
784
785 if pid == active_pid && was_migrating {
788 self.notify_event(PathEvent::PeerMigrated(
789 local_addr, peer_addr,
790 ));
791 }
792 }
793 }
794 Ok(())
795 }
796
797 pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
808 let is_server = self.is_server;
809
810 if let Ok(old_active_path) = self.get_active_mut() {
811 old_active_path.active = false;
812 }
813
814 let new_active_path = self.get_mut(path_id)?;
815 new_active_path.active = true;
816
817 if is_server {
818 if new_active_path.validated() {
819 let local_addr = new_active_path.local_addr();
820 let peer_addr = new_active_path.peer_addr();
821
822 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
823 } else {
824 new_active_path.migrating = true;
825
826 if !new_active_path.under_validation() {
828 new_active_path.request_validation();
829 }
830 }
831 }
832
833 Ok(())
834 }
835}
836
837#[derive(Clone)]
844pub struct PathStats {
845 pub local_addr: SocketAddr,
847
848 pub peer_addr: SocketAddr,
850
851 pub validation_state: PathState,
853
854 pub active: bool,
856
857 pub recv: usize,
859
860 pub sent: usize,
862
863 pub lost: usize,
865
866 pub retrans: usize,
868
869 pub dgram_recv: usize,
871
872 pub dgram_sent: usize,
874
875 pub rtt: time::Duration,
877
878 pub min_rtt: Option<time::Duration>,
880
881 pub rttvar: time::Duration,
884
885 pub cwnd: usize,
887
888 pub sent_bytes: u64,
890
891 pub recv_bytes: u64,
893
894 pub lost_bytes: u64,
896
897 pub stream_retrans_bytes: u64,
899
900 pub pmtu: usize,
902
903 pub delivery_rate: u64,
912}
913
914impl std::fmt::Debug for PathStats {
915 #[inline]
916 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
917 write!(
918 f,
919 "local_addr={:?} peer_addr={:?} ",
920 self.local_addr, self.peer_addr,
921 )?;
922 write!(
923 f,
924 "validation_state={:?} active={} ",
925 self.validation_state, self.active,
926 )?;
927 write!(
928 f,
929 "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
930 self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
931 )?;
932
933 write!(
934 f,
935 " sent_bytes={} recv_bytes={} lost_bytes={}",
936 self.sent_bytes, self.recv_bytes, self.lost_bytes,
937 )?;
938
939 write!(
940 f,
941 " stream_retrans_bytes={} pmtu={} delivery_rate={}",
942 self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
943 )
944 }
945}
946
947#[cfg(test)]
948mod tests {
949 use crate::rand;
950 use crate::MIN_CLIENT_INITIAL_LEN;
951
952 use crate::recovery::RecoveryConfig;
953 use crate::Config;
954
955 use super::*;
956
957 #[test]
958 fn path_validation_limited_mtu() {
959 let client_addr = "127.0.0.1:1234".parse().unwrap();
960 let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
961 let server_addr = "127.0.0.1:4321".parse().unwrap();
962
963 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
964 let recovery_config = RecoveryConfig::from_config(&config);
965
966 let path = Path::new(
967 client_addr,
968 server_addr,
969 &recovery_config,
970 config.path_challenge_recv_max_queue_len,
971 1200,
972 true,
973 );
974 let mut path_mgr = PathMap::new(path, 2, false, true, 1200);
975
976 let probed_path = Path::new(
977 client_addr_2,
978 server_addr,
979 &recovery_config,
980 config.path_challenge_recv_max_queue_len,
981 1200,
982 false,
983 );
984 path_mgr.insert_path(probed_path, false).unwrap();
985
986 let pid = path_mgr
987 .path_id_from_addrs(&(client_addr_2, server_addr))
988 .unwrap();
989 path_mgr.get_mut(pid).unwrap().request_validation();
990 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
991 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
992
993 let data = rand::rand_u64().to_be_bytes();
996 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
997 data,
998 MIN_CLIENT_INITIAL_LEN - 1,
999 time::Instant::now(),
1000 );
1001
1002 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1003 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1004 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1005 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1006 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1007 assert_eq!(path_mgr.pop_event(), None);
1008
1009 path_mgr.on_response_received(data).unwrap();
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!(
1018 path_mgr.get_mut(pid).unwrap().state,
1019 PathState::ValidatingMTU
1020 );
1021 assert_eq!(path_mgr.pop_event(), None);
1022
1023 let data = rand::rand_u64().to_be_bytes();
1026 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1027 data,
1028 MIN_CLIENT_INITIAL_LEN,
1029 time::Instant::now(),
1030 );
1031
1032 path_mgr.on_response_received(data).unwrap();
1033
1034 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1035 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1036 assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1037 assert!(path_mgr.get_mut(pid).unwrap().validated());
1038 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1039 assert_eq!(
1040 path_mgr.pop_event(),
1041 Some(PathEvent::Validated(client_addr_2, server_addr))
1042 );
1043 }
1044
1045 #[test]
1046 fn multiple_probes() {
1047 let client_addr = "127.0.0.1:1234".parse().unwrap();
1048 let server_addr = "127.0.0.1:4321".parse().unwrap();
1049
1050 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1051 let recovery_config = RecoveryConfig::from_config(&config);
1052
1053 let path = Path::new(
1054 client_addr,
1055 server_addr,
1056 &recovery_config,
1057 config.path_challenge_recv_max_queue_len,
1058 1200,
1059 true,
1060 );
1061 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1062 let mut server_path = Path::new(
1063 server_addr,
1064 client_addr,
1065 &recovery_config,
1066 config.path_challenge_recv_max_queue_len,
1067 1200,
1068 false,
1069 );
1070
1071 let client_pid = client_path_mgr
1072 .path_id_from_addrs(&(client_addr, server_addr))
1073 .unwrap();
1074
1075 let data = rand::rand_u64().to_be_bytes();
1077
1078 client_path_mgr
1079 .get_mut(client_pid)
1080 .unwrap()
1081 .add_challenge_sent(
1082 data,
1083 MIN_CLIENT_INITIAL_LEN,
1084 time::Instant::now(),
1085 );
1086
1087 let data_2 = rand::rand_u64().to_be_bytes();
1089
1090 client_path_mgr
1091 .get_mut(client_pid)
1092 .unwrap()
1093 .add_challenge_sent(
1094 data_2,
1095 MIN_CLIENT_INITIAL_LEN,
1096 time::Instant::now(),
1097 );
1098 assert_eq!(
1099 client_path_mgr
1100 .get(client_pid)
1101 .unwrap()
1102 .in_flight_challenges
1103 .len(),
1104 2
1105 );
1106
1107 server_path.on_challenge_received(data);
1109 assert_eq!(server_path.received_challenges.len(), 1);
1110 server_path.on_challenge_received(data_2);
1111 assert_eq!(server_path.received_challenges.len(), 2);
1112
1113 client_path_mgr.on_response_received(data).unwrap();
1115 assert_eq!(
1116 client_path_mgr
1117 .get(client_pid)
1118 .unwrap()
1119 .in_flight_challenges
1120 .len(),
1121 1
1122 );
1123
1124 client_path_mgr.on_response_received(data_2).unwrap();
1126 assert_eq!(
1127 client_path_mgr
1128 .get(client_pid)
1129 .unwrap()
1130 .in_flight_challenges
1131 .len(),
1132 0
1133 );
1134 }
1135
1136 #[test]
1137 fn too_many_probes() {
1138 let client_addr = "127.0.0.1:1234".parse().unwrap();
1139 let server_addr = "127.0.0.1:4321".parse().unwrap();
1140
1141 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1143 let recovery_config = RecoveryConfig::from_config(&config);
1144
1145 let path = Path::new(
1146 client_addr,
1147 server_addr,
1148 &recovery_config,
1149 config.path_challenge_recv_max_queue_len,
1150 1200,
1151 true,
1152 );
1153 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1154 let mut server_path = Path::new(
1155 server_addr,
1156 client_addr,
1157 &recovery_config,
1158 config.path_challenge_recv_max_queue_len,
1159 1200,
1160 false,
1161 );
1162
1163 let client_pid = client_path_mgr
1164 .path_id_from_addrs(&(client_addr, server_addr))
1165 .unwrap();
1166
1167 let data = rand::rand_u64().to_be_bytes();
1169
1170 client_path_mgr
1171 .get_mut(client_pid)
1172 .unwrap()
1173 .add_challenge_sent(
1174 data,
1175 MIN_CLIENT_INITIAL_LEN,
1176 time::Instant::now(),
1177 );
1178
1179 let data_2 = rand::rand_u64().to_be_bytes();
1181
1182 client_path_mgr
1183 .get_mut(client_pid)
1184 .unwrap()
1185 .add_challenge_sent(
1186 data_2,
1187 MIN_CLIENT_INITIAL_LEN,
1188 time::Instant::now(),
1189 );
1190 assert_eq!(
1191 client_path_mgr
1192 .get(client_pid)
1193 .unwrap()
1194 .in_flight_challenges
1195 .len(),
1196 2
1197 );
1198
1199 let data_3 = rand::rand_u64().to_be_bytes();
1201
1202 client_path_mgr
1203 .get_mut(client_pid)
1204 .unwrap()
1205 .add_challenge_sent(
1206 data_3,
1207 MIN_CLIENT_INITIAL_LEN,
1208 time::Instant::now(),
1209 );
1210 assert_eq!(
1211 client_path_mgr
1212 .get(client_pid)
1213 .unwrap()
1214 .in_flight_challenges
1215 .len(),
1216 3
1217 );
1218
1219 let data_4 = rand::rand_u64().to_be_bytes();
1221
1222 client_path_mgr
1223 .get_mut(client_pid)
1224 .unwrap()
1225 .add_challenge_sent(
1226 data_4,
1227 MIN_CLIENT_INITIAL_LEN,
1228 time::Instant::now(),
1229 );
1230 assert_eq!(
1231 client_path_mgr
1232 .get(client_pid)
1233 .unwrap()
1234 .in_flight_challenges
1235 .len(),
1236 4
1237 );
1238
1239 server_path.on_challenge_received(data);
1242 assert_eq!(server_path.received_challenges.len(), 1);
1243 server_path.on_challenge_received(data_2);
1244 assert_eq!(server_path.received_challenges.len(), 2);
1245 server_path.on_challenge_received(data_3);
1246 assert_eq!(server_path.received_challenges.len(), 3);
1247 server_path.on_challenge_received(data_4);
1248 assert_eq!(server_path.received_challenges.len(), 3);
1249
1250 client_path_mgr.on_response_received(data).unwrap();
1252 assert_eq!(
1253 client_path_mgr
1254 .get(client_pid)
1255 .unwrap()
1256 .in_flight_challenges
1257 .len(),
1258 3
1259 );
1260
1261 client_path_mgr.on_response_received(data_2).unwrap();
1263 assert_eq!(
1264 client_path_mgr
1265 .get(client_pid)
1266 .unwrap()
1267 .in_flight_challenges
1268 .len(),
1269 2
1270 );
1271
1272 client_path_mgr.on_response_received(data_3).unwrap();
1274 assert_eq!(
1275 client_path_mgr
1276 .get(client_pid)
1277 .unwrap()
1278 .in_flight_challenges
1279 .len(),
1280 1
1281 );
1282
1283 }
1285}