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;
39use crate::StartupExit;
40
41use crate::pmtud;
42use crate::recovery;
43use crate::recovery::HandshakeStatus;
44use crate::recovery::OnLossDetectionTimeoutOutcome;
45use crate::recovery::RecoveryOps;
46
47#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
49pub enum PathState {
50 Failed,
52
53 Unknown,
55
56 Validating,
58
59 ValidatingMTU,
61
62 Validated,
64}
65
66impl PathState {
67 #[cfg(feature = "ffi")]
68 pub fn to_c(self) -> libc::ssize_t {
69 match self {
70 PathState::Failed => -1,
71 PathState::Unknown => 0,
72 PathState::Validating => 1,
73 PathState::ValidatingMTU => 2,
74 PathState::Validated => 3,
75 }
76 }
77}
78
79#[derive(Clone, Debug, PartialEq, Eq)]
81pub enum PathEvent {
82 New(SocketAddr, SocketAddr),
87
88 Validated(SocketAddr, SocketAddr),
91
92 FailedValidation(SocketAddr, SocketAddr),
96
97 Closed(SocketAddr, SocketAddr),
100
101 ReusedSourceConnectionId(
105 u64,
106 (SocketAddr, SocketAddr),
107 (SocketAddr, SocketAddr),
108 ),
109
110 PeerMigrated(SocketAddr, SocketAddr),
116}
117
118#[derive(Debug)]
120pub struct Path {
121 local_addr: SocketAddr,
123
124 peer_addr: SocketAddr,
126
127 pub active_scid_seq: Option<u64>,
129
130 pub active_dcid_seq: Option<u64>,
132
133 state: PathState,
135
136 active: bool,
138
139 pub recovery: recovery::Recovery,
141
142 pub pmtud: pmtud::Pmtud,
144
145 in_flight_challenges: VecDeque<([u8; 8], usize, time::Instant)>,
148
149 max_challenge_size: usize,
151
152 probing_lost: usize,
154
155 last_probe_lost_time: Option<time::Instant>,
157
158 received_challenges: VecDeque<[u8; 8]>,
160
161 received_challenges_max_len: usize,
163
164 pub sent_count: usize,
166
167 pub recv_count: usize,
169
170 pub retrans_count: usize,
172
173 pub total_pto_count: usize,
180
181 pub dgram_sent_count: usize,
183
184 pub dgram_recv_count: usize,
186
187 pub sent_bytes: u64,
189
190 pub recv_bytes: u64,
192
193 pub stream_retrans_bytes: u64,
196
197 pub max_send_bytes: usize,
200
201 pub verified_peer_address: bool,
203
204 pub peer_verified_local_address: bool,
206
207 challenge_requested: bool,
209
210 failure_notified: bool,
212
213 migrating: bool,
216
217 pub needs_ack_eliciting: bool,
219}
220
221impl Path {
222 pub fn new(
225 local_addr: SocketAddr, peer_addr: SocketAddr,
226 recovery_config: &recovery::RecoveryConfig,
227 path_challenge_recv_max_queue_len: usize, pmtud_init: usize,
228 is_initial: bool,
229 ) -> Self {
230 let (state, active_scid_seq, active_dcid_seq) = if is_initial {
231 (PathState::Validated, Some(0), Some(0))
232 } else {
233 (PathState::Unknown, None, None)
234 };
235
236 Self {
237 local_addr,
238 peer_addr,
239 active_scid_seq,
240 active_dcid_seq,
241 state,
242 active: false,
243 recovery: recovery::Recovery::new_with_config(recovery_config),
244 pmtud: pmtud::Pmtud::new(pmtud_init),
245 in_flight_challenges: VecDeque::new(),
246 max_challenge_size: 0,
247 probing_lost: 0,
248 last_probe_lost_time: None,
249 received_challenges: VecDeque::with_capacity(
250 path_challenge_recv_max_queue_len,
251 ),
252 received_challenges_max_len: path_challenge_recv_max_queue_len,
253 sent_count: 0,
254 recv_count: 0,
255 retrans_count: 0,
256 total_pto_count: 0,
257 dgram_sent_count: 0,
258 dgram_recv_count: 0,
259 sent_bytes: 0,
260 recv_bytes: 0,
261 stream_retrans_bytes: 0,
262 max_send_bytes: 0,
263 verified_peer_address: false,
264 peer_verified_local_address: false,
265 challenge_requested: false,
266 failure_notified: false,
267 migrating: false,
268 needs_ack_eliciting: false,
269 }
270 }
271
272 #[inline]
274 pub fn local_addr(&self) -> SocketAddr {
275 self.local_addr
276 }
277
278 #[inline]
280 pub fn peer_addr(&self) -> SocketAddr {
281 self.peer_addr
282 }
283
284 #[inline]
286 fn working(&self) -> bool {
287 self.state > PathState::Failed
288 }
289
290 #[inline]
292 pub fn active(&self) -> bool {
293 self.active && self.working() && self.active_dcid_seq.is_some()
294 }
295
296 #[inline]
298 pub fn usable(&self) -> bool {
299 self.active() ||
300 (self.state == PathState::Validated &&
301 self.active_dcid_seq.is_some())
302 }
303
304 #[inline]
306 fn unused(&self) -> bool {
307 !self.active() && self.active_dcid_seq.is_none()
309 }
310
311 #[inline]
313 pub fn probing_required(&self) -> bool {
314 !self.received_challenges.is_empty() || self.validation_requested()
315 }
316
317 fn promote_to(&mut self, state: PathState) {
320 if self.state < state {
321 self.state = state;
322 }
323 }
324
325 #[inline]
327 pub fn validated(&self) -> bool {
328 self.state == PathState::Validated
329 }
330
331 #[inline]
333 fn validation_failed(&self) -> bool {
334 self.state == PathState::Failed
335 }
336
337 #[inline]
339 pub fn under_validation(&self) -> bool {
340 matches!(self.state, PathState::Validating | PathState::ValidatingMTU)
341 }
342
343 #[inline]
345 pub fn request_validation(&mut self) {
346 self.challenge_requested = true;
347 }
348
349 #[inline]
351 pub fn validation_requested(&self) -> bool {
352 self.challenge_requested
353 }
354
355 pub fn should_send_pmtu_probe(
356 &mut self, hs_confirmed: bool, hs_done: bool, out_len: usize,
357 is_closing: bool, frames_empty: bool,
358 ) -> bool {
359 (hs_confirmed && hs_done) &&
360 self.pmtud.get_probe_size() > self.pmtud.get_current_mtu() &&
361 self.recovery.cwnd_available() > self.pmtud.get_probe_size() &&
362 out_len >= self.pmtud.get_probe_size() &&
363 self.pmtud.get_should_probe() &&
364 !is_closing &&
365 frames_empty
366 }
367
368 pub fn on_challenge_sent(&mut self) {
369 self.promote_to(PathState::Validating);
370 self.challenge_requested = false;
371 }
372
373 pub fn add_challenge_sent(
375 &mut self, data: [u8; 8], pkt_size: usize, sent_time: time::Instant,
376 ) {
377 self.on_challenge_sent();
378 self.in_flight_challenges
379 .push_back((data, pkt_size, sent_time));
380 }
381
382 pub fn on_challenge_received(&mut self, data: [u8; 8]) {
383 if self.received_challenges.len() == self.received_challenges_max_len {
385 return;
386 }
387
388 self.received_challenges.push_back(data);
389 self.peer_verified_local_address = true;
390 }
391
392 pub fn has_pending_challenge(&self, data: [u8; 8]) -> bool {
393 self.in_flight_challenges.iter().any(|(d, ..)| *d == data)
394 }
395
396 pub fn on_response_received(&mut self, data: [u8; 8]) -> bool {
398 self.verified_peer_address = true;
399 self.probing_lost = 0;
400
401 let mut challenge_size = 0;
402 self.in_flight_challenges.retain(|(d, s, _)| {
403 if *d == data {
404 challenge_size = *s;
405 false
406 } else {
407 true
408 }
409 });
410
411 self.promote_to(PathState::ValidatingMTU);
413
414 self.max_challenge_size =
415 std::cmp::max(self.max_challenge_size, challenge_size);
416
417 if self.state == PathState::ValidatingMTU {
418 if self.max_challenge_size >= crate::MIN_CLIENT_INITIAL_LEN {
419 self.promote_to(PathState::Validated);
421 return true;
422 }
423
424 self.request_validation();
426 }
427
428 false
429 }
430
431 fn on_failed_validation(&mut self) {
432 self.state = PathState::Failed;
433 self.active = false;
434 }
435
436 #[inline]
437 pub fn pop_received_challenge(&mut self) -> Option<[u8; 8]> {
438 self.received_challenges.pop_front()
439 }
440
441 pub fn on_loss_detection_timeout(
442 &mut self, handshake_status: HandshakeStatus, now: time::Instant,
443 is_server: bool, trace_id: &str,
444 ) -> OnLossDetectionTimeoutOutcome {
445 let outcome = self.recovery.on_loss_detection_timeout(
446 handshake_status,
447 now,
448 trace_id,
449 );
450
451 let mut lost_probe_time = None;
452 self.in_flight_challenges.retain(|(_, _, sent_time)| {
453 if *sent_time <= now {
454 if lost_probe_time.is_none() {
455 lost_probe_time = Some(*sent_time);
456 }
457 false
458 } else {
459 true
460 }
461 });
462
463 if let Some(lost_probe_time) = lost_probe_time {
466 self.last_probe_lost_time = match self.last_probe_lost_time {
467 Some(last) => {
468 if lost_probe_time - last >= self.recovery.rtt() {
470 self.probing_lost += 1;
471 Some(lost_probe_time)
472 } else {
473 Some(last)
474 }
475 },
476 None => {
477 self.probing_lost += 1;
478 Some(lost_probe_time)
479 },
480 };
481 if self.probing_lost >= crate::MAX_PROBING_TIMEOUTS ||
485 (is_server && self.max_send_bytes < crate::MIN_PROBING_SIZE)
486 {
487 self.on_failed_validation();
488 } else {
489 self.request_validation();
490 }
491 }
492
493 self.total_pto_count += 1;
495
496 outcome
497 }
498
499 pub fn reinit_recovery(
500 &mut self, recovery_config: &recovery::RecoveryConfig,
501 ) {
502 self.recovery = recovery::Recovery::new_with_config(recovery_config)
503 }
504
505 pub fn stats(&self) -> PathStats {
506 PathStats {
507 local_addr: self.local_addr,
508 peer_addr: self.peer_addr,
509 validation_state: self.state,
510 active: self.active,
511 recv: self.recv_count,
512 sent: self.sent_count,
513 lost: self.recovery.lost_count(),
514 retrans: self.retrans_count,
515 total_pto_count: self.total_pto_count,
516 dgram_recv: self.dgram_recv_count,
517 dgram_sent: self.dgram_sent_count,
518 rtt: self.recovery.rtt(),
519 min_rtt: self.recovery.min_rtt(),
520 max_rtt: self.recovery.max_rtt(),
521 rttvar: self.recovery.rttvar(),
522 cwnd: self.recovery.cwnd(),
523 sent_bytes: self.sent_bytes,
524 recv_bytes: self.recv_bytes,
525 lost_bytes: self.recovery.bytes_lost(),
526 stream_retrans_bytes: self.stream_retrans_bytes,
527 pmtu: self.recovery.max_datagram_size(),
528 delivery_rate: self.recovery.delivery_rate().to_bytes_per_second(),
529 startup_exit: self.recovery.startup_exit(),
530 }
531 }
532
533 pub fn bytes_in_flight_duration(&self) -> time::Duration {
534 self.recovery.bytes_in_flight_duration()
535 }
536}
537
538#[derive(Default)]
540pub struct SocketAddrIter {
541 pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
542 pub(crate) index: usize,
543}
544
545impl Iterator for SocketAddrIter {
546 type Item = SocketAddr;
547
548 #[inline]
549 fn next(&mut self) -> Option<Self::Item> {
550 let v = self.sockaddrs.get(self.index)?;
551 self.index += 1;
552 Some(*v)
553 }
554}
555
556impl ExactSizeIterator for SocketAddrIter {
557 #[inline]
558 fn len(&self) -> usize {
559 self.sockaddrs.len() - self.index
560 }
561}
562
563pub struct PathMap {
565 paths: Slab<Path>,
568
569 max_concurrent_paths: usize,
571
572 addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
575
576 events: VecDeque<PathEvent>,
578
579 is_server: bool,
581}
582
583impl PathMap {
584 pub fn new(
587 mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
588 enable_pmtud: bool, max_send_udp_payload_size: usize,
589 ) -> Self {
590 let mut paths = Slab::with_capacity(1); let mut addrs_to_paths = BTreeMap::new();
592
593 let local_addr = initial_path.local_addr;
594 let peer_addr = initial_path.peer_addr;
595
596 initial_path.active = true;
598
599 if enable_pmtud {
602 initial_path.pmtud.set_should_probe(enable_pmtud);
603 initial_path.pmtud.set_probe_size(max_send_udp_payload_size);
604 initial_path.pmtud.enable(enable_pmtud);
605 }
606
607 let active_path_id = paths.insert(initial_path);
608 addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
609
610 Self {
611 paths,
612 max_concurrent_paths,
613 addrs_to_paths,
614 events: VecDeque::new(),
615 is_server,
616 }
617 }
618
619 #[inline]
625 pub fn get(&self, path_id: usize) -> Result<&Path> {
626 self.paths.get(path_id).ok_or(Error::InvalidState)
627 }
628
629 #[inline]
635 pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
636 self.paths.get_mut(path_id).ok_or(Error::InvalidState)
637 }
638
639 #[inline]
640 pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
643 self.paths.iter().find(|(_, p)| p.active())
644 }
645
646 #[inline]
651 pub fn get_active(&self) -> Result<&Path> {
652 self.get_active_with_pid()
653 .map(|(_, p)| p)
654 .ok_or(Error::InvalidState)
655 }
656
657 #[inline]
662 pub fn get_active_path_id(&self) -> Result<usize> {
663 self.get_active_with_pid()
664 .map(|(pid, _)| pid)
665 .ok_or(Error::InvalidState)
666 }
667
668 #[inline]
673 pub fn get_active_mut(&mut self) -> Result<&mut Path> {
674 self.paths
675 .iter_mut()
676 .map(|(_, p)| p)
677 .find(|p| p.active())
678 .ok_or(Error::InvalidState)
679 }
680
681 #[inline]
683 pub fn iter(&self) -> slab::Iter<'_, Path> {
684 self.paths.iter()
685 }
686
687 #[inline]
689 pub fn iter_mut(&mut self) -> slab::IterMut<'_, Path> {
690 self.paths.iter_mut()
691 }
692
693 #[inline]
695 pub fn len(&self) -> usize {
696 self.paths.len()
697 }
698
699 #[inline]
701 pub fn path_id_from_addrs(
702 &self, addrs: &(SocketAddr, SocketAddr),
703 ) -> Option<usize> {
704 self.addrs_to_paths.get(addrs).copied()
705 }
706
707 fn make_room_for_new_path(&mut self) -> Result<()> {
713 if self.paths.len() < self.max_concurrent_paths {
714 return Ok(());
715 }
716
717 let (pid_to_remove, _) = self
718 .paths
719 .iter()
720 .find(|(_, p)| p.unused())
721 .ok_or(Error::Done)?;
722
723 let path = self.paths.remove(pid_to_remove);
724 self.addrs_to_paths
725 .remove(&(path.local_addr, path.peer_addr));
726
727 self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
728
729 Ok(())
730 }
731
732 pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
743 self.make_room_for_new_path()?;
744
745 let local_addr = path.local_addr;
746 let peer_addr = path.peer_addr;
747
748 let pid = self.paths.insert(path);
749 self.addrs_to_paths.insert((local_addr, peer_addr), pid);
750
751 if is_server {
753 self.notify_event(PathEvent::New(local_addr, peer_addr));
754 }
755
756 Ok(pid)
757 }
758
759 pub fn notify_event(&mut self, ev: PathEvent) {
761 self.events.push_back(ev);
762 }
763
764 pub fn pop_event(&mut self) -> Option<PathEvent> {
766 self.events.pop_front()
767 }
768
769 pub fn notify_failed_validations(&mut self) {
771 let validation_failed = self
772 .paths
773 .iter_mut()
774 .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
775
776 for (_, p) in validation_failed {
777 self.events.push_back(PathEvent::FailedValidation(
778 p.local_addr,
779 p.peer_addr,
780 ));
781
782 p.failure_notified = true;
783 }
784 }
785
786 pub fn find_candidate_path(&self) -> Option<usize> {
788 self.paths
790 .iter()
791 .find(|(_, p)| p.usable())
792 .map(|(pid, _)| pid)
793 }
794
795 pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
797 let active_pid = self.get_active_path_id()?;
798
799 let challenge_pending =
800 self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
801
802 if let Some((pid, p)) = challenge_pending {
803 if p.on_response_received(data) {
804 let local_addr = p.local_addr;
805 let peer_addr = p.peer_addr;
806 let was_migrating = p.migrating;
807
808 p.migrating = false;
809
810 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
812
813 if pid == active_pid && was_migrating {
816 self.notify_event(PathEvent::PeerMigrated(
817 local_addr, peer_addr,
818 ));
819 }
820 }
821 }
822 Ok(())
823 }
824
825 pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
836 let is_server = self.is_server;
837
838 if let Ok(old_active_path) = self.get_active_mut() {
839 old_active_path.active = false;
840 }
841
842 let new_active_path = self.get_mut(path_id)?;
843 new_active_path.active = true;
844
845 if is_server {
846 if new_active_path.validated() {
847 let local_addr = new_active_path.local_addr();
848 let peer_addr = new_active_path.peer_addr();
849
850 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
851 } else {
852 new_active_path.migrating = true;
853
854 if !new_active_path.under_validation() {
856 new_active_path.request_validation();
857 }
858 }
859 }
860
861 Ok(())
862 }
863
864 pub fn set_discover_pmtu_on_existing_paths(
866 &mut self, discover: bool, max_send_udp_payload_size: usize,
867 ) {
868 for (_, path) in self.paths.iter_mut() {
869 path.pmtud.enable(discover);
870 path.pmtud.set_probe_size(max_send_udp_payload_size);
873 path.pmtud.set_should_probe(discover);
874 }
875 }
876}
877
878#[derive(Clone)]
885pub struct PathStats {
886 pub local_addr: SocketAddr,
888
889 pub peer_addr: SocketAddr,
891
892 pub validation_state: PathState,
894
895 pub active: bool,
897
898 pub recv: usize,
900
901 pub sent: usize,
903
904 pub lost: usize,
906
907 pub retrans: usize,
909
910 pub total_pto_count: usize,
917
918 pub dgram_recv: usize,
920
921 pub dgram_sent: usize,
923
924 pub rtt: time::Duration,
926
927 pub min_rtt: Option<time::Duration>,
929
930 pub max_rtt: Option<time::Duration>,
932
933 pub rttvar: time::Duration,
936
937 pub cwnd: usize,
939
940 pub sent_bytes: u64,
942
943 pub recv_bytes: u64,
945
946 pub lost_bytes: u64,
948
949 pub stream_retrans_bytes: u64,
951
952 pub pmtu: usize,
954
955 pub delivery_rate: u64,
964
965 pub startup_exit: Option<StartupExit>,
967}
968
969impl std::fmt::Debug for PathStats {
970 #[inline]
971 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
972 write!(
973 f,
974 "local_addr={:?} peer_addr={:?} ",
975 self.local_addr, self.peer_addr,
976 )?;
977 write!(
978 f,
979 "validation_state={:?} active={} ",
980 self.validation_state, self.active,
981 )?;
982 write!(
983 f,
984 "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
985 self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
986 )?;
987
988 write!(
989 f,
990 " sent_bytes={} recv_bytes={} lost_bytes={}",
991 self.sent_bytes, self.recv_bytes, self.lost_bytes,
992 )?;
993
994 write!(
995 f,
996 " stream_retrans_bytes={} pmtu={} delivery_rate={}",
997 self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
998 )
999 }
1000}
1001
1002#[cfg(test)]
1003mod tests {
1004 use crate::rand;
1005 use crate::MIN_CLIENT_INITIAL_LEN;
1006
1007 use crate::recovery::RecoveryConfig;
1008 use crate::Config;
1009
1010 use super::*;
1011
1012 #[test]
1013 fn path_validation_limited_mtu() {
1014 let client_addr = "127.0.0.1:1234".parse().unwrap();
1015 let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
1016 let server_addr = "127.0.0.1:4321".parse().unwrap();
1017
1018 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1019 let recovery_config = RecoveryConfig::from_config(&config);
1020
1021 let path = Path::new(
1022 client_addr,
1023 server_addr,
1024 &recovery_config,
1025 config.path_challenge_recv_max_queue_len,
1026 1200,
1027 true,
1028 );
1029 let mut path_mgr = PathMap::new(path, 2, false, true, 1200);
1030
1031 let probed_path = Path::new(
1032 client_addr_2,
1033 server_addr,
1034 &recovery_config,
1035 config.path_challenge_recv_max_queue_len,
1036 1200,
1037 false,
1038 );
1039 path_mgr.insert_path(probed_path, false).unwrap();
1040
1041 let pid = path_mgr
1042 .path_id_from_addrs(&(client_addr_2, server_addr))
1043 .unwrap();
1044 path_mgr.get_mut(pid).unwrap().request_validation();
1045 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1046 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1047
1048 let data = rand::rand_u64().to_be_bytes();
1051 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1052 data,
1053 MIN_CLIENT_INITIAL_LEN - 1,
1054 time::Instant::now(),
1055 );
1056
1057 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1058 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1059 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1060 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1061 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1062 assert_eq!(path_mgr.pop_event(), None);
1063
1064 path_mgr.on_response_received(data).unwrap();
1067
1068 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1069 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1070 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1071 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1072 assert_eq!(
1073 path_mgr.get_mut(pid).unwrap().state,
1074 PathState::ValidatingMTU
1075 );
1076 assert_eq!(path_mgr.pop_event(), None);
1077
1078 let data = rand::rand_u64().to_be_bytes();
1081 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1082 data,
1083 MIN_CLIENT_INITIAL_LEN,
1084 time::Instant::now(),
1085 );
1086
1087 path_mgr.on_response_received(data).unwrap();
1088
1089 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1090 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1091 assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1092 assert!(path_mgr.get_mut(pid).unwrap().validated());
1093 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1094 assert_eq!(
1095 path_mgr.pop_event(),
1096 Some(PathEvent::Validated(client_addr_2, server_addr))
1097 );
1098 }
1099
1100 #[test]
1101 fn multiple_probes() {
1102 let client_addr = "127.0.0.1:1234".parse().unwrap();
1103 let server_addr = "127.0.0.1:4321".parse().unwrap();
1104
1105 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1106 let recovery_config = RecoveryConfig::from_config(&config);
1107
1108 let path = Path::new(
1109 client_addr,
1110 server_addr,
1111 &recovery_config,
1112 config.path_challenge_recv_max_queue_len,
1113 1200,
1114 true,
1115 );
1116 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1117 let mut server_path = Path::new(
1118 server_addr,
1119 client_addr,
1120 &recovery_config,
1121 config.path_challenge_recv_max_queue_len,
1122 1200,
1123 false,
1124 );
1125
1126 let client_pid = client_path_mgr
1127 .path_id_from_addrs(&(client_addr, server_addr))
1128 .unwrap();
1129
1130 let data = rand::rand_u64().to_be_bytes();
1132
1133 client_path_mgr
1134 .get_mut(client_pid)
1135 .unwrap()
1136 .add_challenge_sent(
1137 data,
1138 MIN_CLIENT_INITIAL_LEN,
1139 time::Instant::now(),
1140 );
1141
1142 let data_2 = rand::rand_u64().to_be_bytes();
1144
1145 client_path_mgr
1146 .get_mut(client_pid)
1147 .unwrap()
1148 .add_challenge_sent(
1149 data_2,
1150 MIN_CLIENT_INITIAL_LEN,
1151 time::Instant::now(),
1152 );
1153 assert_eq!(
1154 client_path_mgr
1155 .get(client_pid)
1156 .unwrap()
1157 .in_flight_challenges
1158 .len(),
1159 2
1160 );
1161
1162 server_path.on_challenge_received(data);
1164 assert_eq!(server_path.received_challenges.len(), 1);
1165 server_path.on_challenge_received(data_2);
1166 assert_eq!(server_path.received_challenges.len(), 2);
1167
1168 client_path_mgr.on_response_received(data).unwrap();
1170 assert_eq!(
1171 client_path_mgr
1172 .get(client_pid)
1173 .unwrap()
1174 .in_flight_challenges
1175 .len(),
1176 1
1177 );
1178
1179 client_path_mgr.on_response_received(data_2).unwrap();
1181 assert_eq!(
1182 client_path_mgr
1183 .get(client_pid)
1184 .unwrap()
1185 .in_flight_challenges
1186 .len(),
1187 0
1188 );
1189 }
1190
1191 #[test]
1192 fn too_many_probes() {
1193 let client_addr = "127.0.0.1:1234".parse().unwrap();
1194 let server_addr = "127.0.0.1:4321".parse().unwrap();
1195
1196 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1198 let recovery_config = RecoveryConfig::from_config(&config);
1199
1200 let path = Path::new(
1201 client_addr,
1202 server_addr,
1203 &recovery_config,
1204 config.path_challenge_recv_max_queue_len,
1205 1200,
1206 true,
1207 );
1208 let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1209 let mut server_path = Path::new(
1210 server_addr,
1211 client_addr,
1212 &recovery_config,
1213 config.path_challenge_recv_max_queue_len,
1214 1200,
1215 false,
1216 );
1217
1218 let client_pid = client_path_mgr
1219 .path_id_from_addrs(&(client_addr, server_addr))
1220 .unwrap();
1221
1222 let data = rand::rand_u64().to_be_bytes();
1224
1225 client_path_mgr
1226 .get_mut(client_pid)
1227 .unwrap()
1228 .add_challenge_sent(
1229 data,
1230 MIN_CLIENT_INITIAL_LEN,
1231 time::Instant::now(),
1232 );
1233
1234 let data_2 = rand::rand_u64().to_be_bytes();
1236
1237 client_path_mgr
1238 .get_mut(client_pid)
1239 .unwrap()
1240 .add_challenge_sent(
1241 data_2,
1242 MIN_CLIENT_INITIAL_LEN,
1243 time::Instant::now(),
1244 );
1245 assert_eq!(
1246 client_path_mgr
1247 .get(client_pid)
1248 .unwrap()
1249 .in_flight_challenges
1250 .len(),
1251 2
1252 );
1253
1254 let data_3 = rand::rand_u64().to_be_bytes();
1256
1257 client_path_mgr
1258 .get_mut(client_pid)
1259 .unwrap()
1260 .add_challenge_sent(
1261 data_3,
1262 MIN_CLIENT_INITIAL_LEN,
1263 time::Instant::now(),
1264 );
1265 assert_eq!(
1266 client_path_mgr
1267 .get(client_pid)
1268 .unwrap()
1269 .in_flight_challenges
1270 .len(),
1271 3
1272 );
1273
1274 let data_4 = rand::rand_u64().to_be_bytes();
1276
1277 client_path_mgr
1278 .get_mut(client_pid)
1279 .unwrap()
1280 .add_challenge_sent(
1281 data_4,
1282 MIN_CLIENT_INITIAL_LEN,
1283 time::Instant::now(),
1284 );
1285 assert_eq!(
1286 client_path_mgr
1287 .get(client_pid)
1288 .unwrap()
1289 .in_flight_challenges
1290 .len(),
1291 4
1292 );
1293
1294 server_path.on_challenge_received(data);
1297 assert_eq!(server_path.received_challenges.len(), 1);
1298 server_path.on_challenge_received(data_2);
1299 assert_eq!(server_path.received_challenges.len(), 2);
1300 server_path.on_challenge_received(data_3);
1301 assert_eq!(server_path.received_challenges.len(), 3);
1302 server_path.on_challenge_received(data_4);
1303 assert_eq!(server_path.received_challenges.len(), 3);
1304
1305 client_path_mgr.on_response_received(data).unwrap();
1307 assert_eq!(
1308 client_path_mgr
1309 .get(client_pid)
1310 .unwrap()
1311 .in_flight_challenges
1312 .len(),
1313 3
1314 );
1315
1316 client_path_mgr.on_response_received(data_2).unwrap();
1318 assert_eq!(
1319 client_path_mgr
1320 .get(client_pid)
1321 .unwrap()
1322 .in_flight_challenges
1323 .len(),
1324 2
1325 );
1326
1327 client_path_mgr.on_response_received(data_3).unwrap();
1329 assert_eq!(
1330 client_path_mgr
1331 .get(client_pid)
1332 .unwrap()
1333 .in_flight_challenges
1334 .len(),
1335 1
1336 );
1337
1338 }
1340}