1use std::collections::BTreeMap;
28use std::collections::VecDeque;
29
30use std::net::SocketAddr;
31
32use std::time::Duration;
33use std::time::Instant;
34
35use smallvec::SmallVec;
36
37use slab::Slab;
38
39use crate::Config;
40use crate::Error;
41use crate::Result;
42use crate::StartupExit;
43
44use crate::pmtud;
45use crate::recovery;
46use crate::recovery::HandshakeStatus;
47use crate::recovery::OnLossDetectionTimeoutOutcome;
48use crate::recovery::RecoveryOps;
49
50#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
52pub enum PathState {
53 Failed,
55
56 Unknown,
58
59 Validating,
61
62 ValidatingMTU,
64
65 Validated,
67}
68
69impl PathState {
70 #[cfg(feature = "ffi")]
71 pub fn to_c(self) -> libc::ssize_t {
72 match self {
73 PathState::Failed => -1,
74 PathState::Unknown => 0,
75 PathState::Validating => 1,
76 PathState::ValidatingMTU => 2,
77 PathState::Validated => 3,
78 }
79 }
80}
81
82#[derive(Clone, Debug, PartialEq, Eq)]
84pub enum PathEvent {
85 New(SocketAddr, SocketAddr),
90
91 Validated(SocketAddr, SocketAddr),
94
95 FailedValidation(SocketAddr, SocketAddr),
99
100 Closed(SocketAddr, SocketAddr),
103
104 ReusedSourceConnectionId(
108 u64,
109 (SocketAddr, SocketAddr),
110 (SocketAddr, SocketAddr),
111 ),
112
113 PeerMigrated(SocketAddr, SocketAddr),
119}
120
121#[derive(Debug)]
123pub struct Path {
124 local_addr: SocketAddr,
126
127 peer_addr: SocketAddr,
129
130 pub active_scid_seq: Option<u64>,
132
133 pub active_dcid_seq: Option<u64>,
135
136 state: PathState,
138
139 active: bool,
141
142 pub recovery: recovery::Recovery,
144
145 pub pmtud: Option<pmtud::Pmtud>,
147
148 in_flight_challenges: VecDeque<([u8; 8], usize, Instant)>,
151
152 max_challenge_size: usize,
154
155 probing_lost: usize,
157
158 last_probe_lost_time: Option<Instant>,
160
161 received_challenges: VecDeque<[u8; 8]>,
163
164 received_challenges_max_len: usize,
166
167 pub sent_count: usize,
169
170 pub recv_count: usize,
172
173 pub retrans_count: usize,
175
176 pub total_pto_count: usize,
183
184 pub dgram_sent_count: usize,
186
187 pub dgram_recv_count: usize,
189
190 pub sent_bytes: u64,
192
193 pub recv_bytes: u64,
195
196 pub stream_retrans_bytes: u64,
199
200 pub max_send_bytes: usize,
203
204 pub verified_peer_address: bool,
206
207 pub peer_verified_local_address: bool,
209
210 challenge_requested: bool,
212
213 failure_notified: bool,
215
216 migrating: bool,
219
220 pub needs_ack_eliciting: bool,
222}
223
224impl Path {
225 pub fn new(
228 local_addr: SocketAddr, peer_addr: SocketAddr,
229 recovery_config: &recovery::RecoveryConfig,
230 path_challenge_recv_max_queue_len: usize, is_initial: bool,
231 config: Option<&Config>,
232 ) -> Self {
233 let (state, active_scid_seq, active_dcid_seq) = if is_initial {
234 (PathState::Validated, Some(0), Some(0))
235 } else {
236 (PathState::Unknown, None, None)
237 };
238
239 let pmtud = config.and_then(|c| {
240 if c.pmtud {
241 let maximum_supported_mtu: usize = std::cmp::min(
242 c.local_transport_params
245 .max_udp_payload_size
246 .try_into()
247 .unwrap_or(c.max_send_udp_payload_size),
248 c.max_send_udp_payload_size,
249 );
250 Some(pmtud::Pmtud::new(maximum_supported_mtu))
251 } else {
252 None
253 }
254 });
255
256 Self {
257 local_addr,
258 peer_addr,
259 active_scid_seq,
260 active_dcid_seq,
261 state,
262 active: false,
263 recovery: recovery::Recovery::new_with_config(recovery_config),
264 pmtud,
265 in_flight_challenges: VecDeque::new(),
266 max_challenge_size: 0,
267 probing_lost: 0,
268 last_probe_lost_time: None,
269 received_challenges: VecDeque::with_capacity(
270 path_challenge_recv_max_queue_len,
271 ),
272 received_challenges_max_len: path_challenge_recv_max_queue_len,
273 sent_count: 0,
274 recv_count: 0,
275 retrans_count: 0,
276 total_pto_count: 0,
277 dgram_sent_count: 0,
278 dgram_recv_count: 0,
279 sent_bytes: 0,
280 recv_bytes: 0,
281 stream_retrans_bytes: 0,
282 max_send_bytes: 0,
283 verified_peer_address: false,
284 peer_verified_local_address: false,
285 challenge_requested: false,
286 failure_notified: false,
287 migrating: false,
288 needs_ack_eliciting: false,
289 }
290 }
291
292 #[inline]
294 pub fn local_addr(&self) -> SocketAddr {
295 self.local_addr
296 }
297
298 #[inline]
300 pub fn peer_addr(&self) -> SocketAddr {
301 self.peer_addr
302 }
303
304 #[inline]
306 fn working(&self) -> bool {
307 self.state > PathState::Failed
308 }
309
310 #[inline]
312 pub fn active(&self) -> bool {
313 self.active && self.working() && self.active_dcid_seq.is_some()
314 }
315
316 #[inline]
318 pub fn usable(&self) -> bool {
319 self.active() ||
320 (self.state == PathState::Validated &&
321 self.active_dcid_seq.is_some())
322 }
323
324 #[inline]
326 fn unused(&self) -> bool {
327 !self.active() && self.active_dcid_seq.is_none()
329 }
330
331 #[inline]
333 pub fn probing_required(&self) -> bool {
334 !self.received_challenges.is_empty() || self.validation_requested()
335 }
336
337 fn promote_to(&mut self, state: PathState) {
340 if self.state < state {
341 self.state = state;
342 }
343 }
344
345 #[inline]
347 pub fn validated(&self) -> bool {
348 self.state == PathState::Validated
349 }
350
351 #[inline]
353 fn validation_failed(&self) -> bool {
354 self.state == PathState::Failed
355 }
356
357 #[inline]
359 pub fn under_validation(&self) -> bool {
360 matches!(self.state, PathState::Validating | PathState::ValidatingMTU)
361 }
362
363 #[inline]
365 pub fn request_validation(&mut self) {
366 self.challenge_requested = true;
367 }
368
369 #[inline]
371 pub fn validation_requested(&self) -> bool {
372 self.challenge_requested
373 }
374
375 pub fn should_send_pmtu_probe(
376 &mut self, hs_confirmed: bool, hs_done: bool, out_len: usize,
377 is_closing: bool, frames_empty: bool,
378 ) -> bool {
379 let Some(pmtud) = self.pmtud.as_mut() else {
380 return false;
381 };
382
383 (hs_confirmed && hs_done) &&
384 pmtud.get_probe_size() > pmtud.get_current_mtu() &&
385 self.recovery.cwnd_available() > pmtud.get_probe_size() &&
386 out_len >= pmtud.get_probe_size() &&
387 pmtud.should_probe() &&
388 !is_closing &&
389 frames_empty
390 }
391
392 pub fn on_challenge_sent(&mut self) {
393 self.promote_to(PathState::Validating);
394 self.challenge_requested = false;
395 }
396
397 pub fn add_challenge_sent(
399 &mut self, data: [u8; 8], pkt_size: usize, sent_time: Instant,
400 ) {
401 self.on_challenge_sent();
402 self.in_flight_challenges
403 .push_back((data, pkt_size, sent_time));
404 }
405
406 pub fn on_challenge_received(&mut self, data: [u8; 8]) {
407 if self.received_challenges.len() == self.received_challenges_max_len {
409 return;
410 }
411
412 self.received_challenges.push_back(data);
413 self.peer_verified_local_address = true;
414 }
415
416 pub fn has_pending_challenge(&self, data: [u8; 8]) -> bool {
417 self.in_flight_challenges.iter().any(|(d, ..)| *d == data)
418 }
419
420 pub fn on_response_received(&mut self, data: [u8; 8]) -> bool {
422 self.verified_peer_address = true;
423 self.probing_lost = 0;
424
425 let mut challenge_size = 0;
426 self.in_flight_challenges.retain(|(d, s, _)| {
427 if *d == data {
428 challenge_size = *s;
429 false
430 } else {
431 true
432 }
433 });
434
435 self.promote_to(PathState::ValidatingMTU);
437
438 self.max_challenge_size =
439 std::cmp::max(self.max_challenge_size, challenge_size);
440
441 if self.state == PathState::ValidatingMTU {
442 if self.max_challenge_size >= crate::MIN_CLIENT_INITIAL_LEN {
443 self.promote_to(PathState::Validated);
445 return true;
446 }
447
448 self.request_validation();
450 }
451
452 false
453 }
454
455 fn on_failed_validation(&mut self) {
456 self.state = PathState::Failed;
457 self.active = false;
458 }
459
460 #[inline]
461 pub fn pop_received_challenge(&mut self) -> Option<[u8; 8]> {
462 self.received_challenges.pop_front()
463 }
464
465 pub fn on_loss_detection_timeout(
466 &mut self, handshake_status: HandshakeStatus, now: Instant,
467 is_server: bool, trace_id: &str,
468 ) -> OnLossDetectionTimeoutOutcome {
469 let outcome = self.recovery.on_loss_detection_timeout(
470 handshake_status,
471 now,
472 trace_id,
473 );
474
475 let mut lost_probe_time = None;
476 self.in_flight_challenges.retain(|(_, _, sent_time)| {
477 if *sent_time <= now {
478 if lost_probe_time.is_none() {
479 lost_probe_time = Some(*sent_time);
480 }
481 false
482 } else {
483 true
484 }
485 });
486
487 if let Some(lost_probe_time) = lost_probe_time {
490 self.last_probe_lost_time = match self.last_probe_lost_time {
491 Some(last) => {
492 if lost_probe_time - last >= self.recovery.rtt() {
494 self.probing_lost += 1;
495 Some(lost_probe_time)
496 } else {
497 Some(last)
498 }
499 },
500 None => {
501 self.probing_lost += 1;
502 Some(lost_probe_time)
503 },
504 };
505 if self.probing_lost >= crate::MAX_PROBING_TIMEOUTS ||
509 (is_server && self.max_send_bytes < crate::MIN_PROBING_SIZE)
510 {
511 self.on_failed_validation();
512 } else {
513 self.request_validation();
514 }
515 }
516
517 self.total_pto_count += 1;
519
520 outcome
521 }
522
523 pub fn reinit_recovery(
524 &mut self, recovery_config: &recovery::RecoveryConfig,
525 ) {
526 self.recovery = recovery::Recovery::new_with_config(recovery_config)
527 }
528
529 pub fn stats(&self) -> PathStats {
530 PathStats {
531 local_addr: self.local_addr,
532 peer_addr: self.peer_addr,
533 validation_state: self.state,
534 active: self.active,
535 recv: self.recv_count,
536 sent: self.sent_count,
537 lost: self.recovery.lost_count(),
538 retrans: self.retrans_count,
539 total_pto_count: self.total_pto_count,
540 dgram_recv: self.dgram_recv_count,
541 dgram_sent: self.dgram_sent_count,
542 rtt: self.recovery.rtt(),
543 min_rtt: self.recovery.min_rtt(),
544 max_rtt: self.recovery.max_rtt(),
545 rttvar: self.recovery.rttvar(),
546 cwnd: self.recovery.cwnd(),
547 sent_bytes: self.sent_bytes,
548 recv_bytes: self.recv_bytes,
549 lost_bytes: self.recovery.bytes_lost(),
550 stream_retrans_bytes: self.stream_retrans_bytes,
551 pmtu: self.recovery.max_datagram_size(),
552 delivery_rate: self.recovery.delivery_rate().to_bytes_per_second(),
553 startup_exit: self.recovery.startup_exit(),
554 }
555 }
556
557 pub fn bytes_in_flight_duration(&self) -> Duration {
558 self.recovery.bytes_in_flight_duration()
559 }
560}
561
562#[derive(Default)]
564pub struct SocketAddrIter {
565 pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
566 pub(crate) index: usize,
567}
568
569impl Iterator for SocketAddrIter {
570 type Item = SocketAddr;
571
572 #[inline]
573 fn next(&mut self) -> Option<Self::Item> {
574 let v = self.sockaddrs.get(self.index)?;
575 self.index += 1;
576 Some(*v)
577 }
578}
579
580impl ExactSizeIterator for SocketAddrIter {
581 #[inline]
582 fn len(&self) -> usize {
583 self.sockaddrs.len() - self.index
584 }
585}
586
587pub struct PathMap {
589 paths: Slab<Path>,
592
593 max_concurrent_paths: usize,
595
596 addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
599
600 events: VecDeque<PathEvent>,
602
603 is_server: bool,
605}
606
607impl PathMap {
608 pub fn new(
611 mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
612 ) -> Self {
613 let mut paths = Slab::with_capacity(1); let mut addrs_to_paths = BTreeMap::new();
615
616 let local_addr = initial_path.local_addr;
617 let peer_addr = initial_path.peer_addr;
618
619 initial_path.active = true;
621
622 let active_path_id = paths.insert(initial_path);
623 addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
624
625 Self {
626 paths,
627 max_concurrent_paths,
628 addrs_to_paths,
629 events: VecDeque::new(),
630 is_server,
631 }
632 }
633
634 #[inline]
640 pub fn get(&self, path_id: usize) -> Result<&Path> {
641 self.paths.get(path_id).ok_or(Error::InvalidState)
642 }
643
644 #[inline]
650 pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
651 self.paths.get_mut(path_id).ok_or(Error::InvalidState)
652 }
653
654 #[inline]
655 pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
658 self.paths.iter().find(|(_, p)| p.active())
659 }
660
661 #[inline]
666 pub fn get_active(&self) -> Result<&Path> {
667 self.get_active_with_pid()
668 .map(|(_, p)| p)
669 .ok_or(Error::InvalidState)
670 }
671
672 #[inline]
677 pub fn get_active_path_id(&self) -> Result<usize> {
678 self.get_active_with_pid()
679 .map(|(pid, _)| pid)
680 .ok_or(Error::InvalidState)
681 }
682
683 #[inline]
688 pub fn get_active_mut(&mut self) -> Result<&mut Path> {
689 self.paths
690 .iter_mut()
691 .map(|(_, p)| p)
692 .find(|p| p.active())
693 .ok_or(Error::InvalidState)
694 }
695
696 #[inline]
698 pub fn iter(&self) -> slab::Iter<'_, Path> {
699 self.paths.iter()
700 }
701
702 #[inline]
704 pub fn iter_mut(&mut self) -> slab::IterMut<'_, Path> {
705 self.paths.iter_mut()
706 }
707
708 #[inline]
710 pub fn len(&self) -> usize {
711 self.paths.len()
712 }
713
714 #[inline]
716 pub fn path_id_from_addrs(
717 &self, addrs: &(SocketAddr, SocketAddr),
718 ) -> Option<usize> {
719 self.addrs_to_paths.get(addrs).copied()
720 }
721
722 fn make_room_for_new_path(&mut self) -> Result<()> {
728 if self.paths.len() < self.max_concurrent_paths {
729 return Ok(());
730 }
731
732 let (pid_to_remove, _) = self
733 .paths
734 .iter()
735 .find(|(_, p)| p.unused())
736 .ok_or(Error::Done)?;
737
738 let path = self.paths.remove(pid_to_remove);
739 self.addrs_to_paths
740 .remove(&(path.local_addr, path.peer_addr));
741
742 self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
743
744 Ok(())
745 }
746
747 pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
758 self.make_room_for_new_path()?;
759
760 let local_addr = path.local_addr;
761 let peer_addr = path.peer_addr;
762
763 let pid = self.paths.insert(path);
764 self.addrs_to_paths.insert((local_addr, peer_addr), pid);
765
766 if is_server {
768 self.notify_event(PathEvent::New(local_addr, peer_addr));
769 }
770
771 Ok(pid)
772 }
773
774 pub fn notify_event(&mut self, ev: PathEvent) {
776 self.events.push_back(ev);
777 }
778
779 pub fn pop_event(&mut self) -> Option<PathEvent> {
781 self.events.pop_front()
782 }
783
784 pub fn notify_failed_validations(&mut self) {
786 let validation_failed = self
787 .paths
788 .iter_mut()
789 .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
790
791 for (_, p) in validation_failed {
792 self.events.push_back(PathEvent::FailedValidation(
793 p.local_addr,
794 p.peer_addr,
795 ));
796
797 p.failure_notified = true;
798 }
799 }
800
801 pub fn find_candidate_path(&self) -> Option<usize> {
803 self.paths
805 .iter()
806 .find(|(_, p)| p.usable())
807 .map(|(pid, _)| pid)
808 }
809
810 pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
812 let active_pid = self.get_active_path_id()?;
813
814 let challenge_pending =
815 self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
816
817 if let Some((pid, p)) = challenge_pending {
818 if p.on_response_received(data) {
819 let local_addr = p.local_addr;
820 let peer_addr = p.peer_addr;
821 let was_migrating = p.migrating;
822
823 p.migrating = false;
824
825 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
827
828 if pid == active_pid && was_migrating {
831 self.notify_event(PathEvent::PeerMigrated(
832 local_addr, peer_addr,
833 ));
834 }
835 }
836 }
837 Ok(())
838 }
839
840 pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
851 let is_server = self.is_server;
852
853 if let Ok(old_active_path) = self.get_active_mut() {
854 old_active_path.active = false;
855 }
856
857 let new_active_path = self.get_mut(path_id)?;
858 new_active_path.active = true;
859
860 if is_server {
861 if new_active_path.validated() {
862 let local_addr = new_active_path.local_addr();
863 let peer_addr = new_active_path.peer_addr();
864
865 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
866 } else {
867 new_active_path.migrating = true;
868
869 if !new_active_path.under_validation() {
871 new_active_path.request_validation();
872 }
873 }
874 }
875
876 Ok(())
877 }
878
879 pub fn set_discover_pmtu_on_existing_paths(
881 &mut self, discover: bool, max_send_udp_payload_size: usize,
882 ) {
883 for (_, path) in self.paths.iter_mut() {
884 path.pmtud = if discover {
885 Some(pmtud::Pmtud::new(max_send_udp_payload_size))
886 } else {
887 None
888 };
889 }
890 }
891}
892
893#[derive(Clone)]
900pub struct PathStats {
901 pub local_addr: SocketAddr,
903
904 pub peer_addr: SocketAddr,
906
907 pub validation_state: PathState,
909
910 pub active: bool,
912
913 pub recv: usize,
915
916 pub sent: usize,
918
919 pub lost: usize,
921
922 pub retrans: usize,
924
925 pub total_pto_count: usize,
932
933 pub dgram_recv: usize,
935
936 pub dgram_sent: usize,
938
939 pub rtt: Duration,
941
942 pub min_rtt: Option<Duration>,
944
945 pub max_rtt: Option<Duration>,
947
948 pub rttvar: Duration,
951
952 pub cwnd: usize,
954
955 pub sent_bytes: u64,
957
958 pub recv_bytes: u64,
960
961 pub lost_bytes: u64,
963
964 pub stream_retrans_bytes: u64,
966
967 pub pmtu: usize,
969
970 pub delivery_rate: u64,
979
980 pub startup_exit: Option<StartupExit>,
982}
983
984impl std::fmt::Debug for PathStats {
985 #[inline]
986 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
987 write!(
988 f,
989 "local_addr={:?} peer_addr={:?} ",
990 self.local_addr, self.peer_addr,
991 )?;
992 write!(
993 f,
994 "validation_state={:?} active={} ",
995 self.validation_state, self.active,
996 )?;
997 write!(
998 f,
999 "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
1000 self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
1001 )?;
1002
1003 write!(
1004 f,
1005 " sent_bytes={} recv_bytes={} lost_bytes={}",
1006 self.sent_bytes, self.recv_bytes, self.lost_bytes,
1007 )?;
1008
1009 write!(
1010 f,
1011 " stream_retrans_bytes={} pmtu={} delivery_rate={}",
1012 self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
1013 )
1014 }
1015}
1016
1017#[cfg(test)]
1018mod tests {
1019 use crate::rand;
1020 use crate::MIN_CLIENT_INITIAL_LEN;
1021
1022 use crate::recovery::RecoveryConfig;
1023 use crate::Config;
1024
1025 use super::*;
1026
1027 #[test]
1028 fn path_validation_limited_mtu() {
1029 let client_addr = "127.0.0.1:1234".parse().unwrap();
1030 let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
1031 let server_addr = "127.0.0.1:4321".parse().unwrap();
1032
1033 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1034 let recovery_config = RecoveryConfig::from_config(&config);
1035
1036 let path = Path::new(
1037 client_addr,
1038 server_addr,
1039 &recovery_config,
1040 config.path_challenge_recv_max_queue_len,
1041 true,
1042 None,
1043 );
1044 let mut path_mgr = PathMap::new(path, 2, false);
1045
1046 let probed_path = Path::new(
1047 client_addr_2,
1048 server_addr,
1049 &recovery_config,
1050 config.path_challenge_recv_max_queue_len,
1051 false,
1052 None,
1053 );
1054 path_mgr.insert_path(probed_path, false).unwrap();
1055
1056 let pid = path_mgr
1057 .path_id_from_addrs(&(client_addr_2, server_addr))
1058 .unwrap();
1059 path_mgr.get_mut(pid).unwrap().request_validation();
1060 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1061 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1062
1063 let data = rand::rand_u64().to_be_bytes();
1066 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1067 data,
1068 MIN_CLIENT_INITIAL_LEN - 1,
1069 Instant::now(),
1070 );
1071
1072 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1073 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1074 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1075 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1076 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1077 assert_eq!(path_mgr.pop_event(), None);
1078
1079 path_mgr.on_response_received(data).unwrap();
1082
1083 assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1084 assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1085 assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1086 assert!(!path_mgr.get_mut(pid).unwrap().validated());
1087 assert_eq!(
1088 path_mgr.get_mut(pid).unwrap().state,
1089 PathState::ValidatingMTU
1090 );
1091 assert_eq!(path_mgr.pop_event(), None);
1092
1093 let data = rand::rand_u64().to_be_bytes();
1096 path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1097 data,
1098 MIN_CLIENT_INITIAL_LEN,
1099 Instant::now(),
1100 );
1101
1102 path_mgr.on_response_received(data).unwrap();
1103
1104 assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1105 assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1106 assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1107 assert!(path_mgr.get_mut(pid).unwrap().validated());
1108 assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1109 assert_eq!(
1110 path_mgr.pop_event(),
1111 Some(PathEvent::Validated(client_addr_2, server_addr))
1112 );
1113 }
1114
1115 #[test]
1116 fn multiple_probes() {
1117 let client_addr = "127.0.0.1:1234".parse().unwrap();
1118 let server_addr = "127.0.0.1:4321".parse().unwrap();
1119
1120 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1121 let recovery_config = RecoveryConfig::from_config(&config);
1122
1123 let path = Path::new(
1124 client_addr,
1125 server_addr,
1126 &recovery_config,
1127 config.path_challenge_recv_max_queue_len,
1128 true,
1129 None,
1130 );
1131 let mut client_path_mgr = PathMap::new(path, 2, false);
1132 let mut server_path = Path::new(
1133 server_addr,
1134 client_addr,
1135 &recovery_config,
1136 config.path_challenge_recv_max_queue_len,
1137 false,
1138 None,
1139 );
1140
1141 let client_pid = client_path_mgr
1142 .path_id_from_addrs(&(client_addr, server_addr))
1143 .unwrap();
1144
1145 let data = rand::rand_u64().to_be_bytes();
1147
1148 client_path_mgr
1149 .get_mut(client_pid)
1150 .unwrap()
1151 .add_challenge_sent(data, MIN_CLIENT_INITIAL_LEN, Instant::now());
1152
1153 let data_2 = rand::rand_u64().to_be_bytes();
1155
1156 client_path_mgr
1157 .get_mut(client_pid)
1158 .unwrap()
1159 .add_challenge_sent(data_2, MIN_CLIENT_INITIAL_LEN, Instant::now());
1160 assert_eq!(
1161 client_path_mgr
1162 .get(client_pid)
1163 .unwrap()
1164 .in_flight_challenges
1165 .len(),
1166 2
1167 );
1168
1169 server_path.on_challenge_received(data);
1171 assert_eq!(server_path.received_challenges.len(), 1);
1172 server_path.on_challenge_received(data_2);
1173 assert_eq!(server_path.received_challenges.len(), 2);
1174
1175 client_path_mgr.on_response_received(data).unwrap();
1177 assert_eq!(
1178 client_path_mgr
1179 .get(client_pid)
1180 .unwrap()
1181 .in_flight_challenges
1182 .len(),
1183 1
1184 );
1185
1186 client_path_mgr.on_response_received(data_2).unwrap();
1188 assert_eq!(
1189 client_path_mgr
1190 .get(client_pid)
1191 .unwrap()
1192 .in_flight_challenges
1193 .len(),
1194 0
1195 );
1196 }
1197
1198 #[test]
1199 fn too_many_probes() {
1200 let client_addr = "127.0.0.1:1234".parse().unwrap();
1201 let server_addr = "127.0.0.1:4321".parse().unwrap();
1202
1203 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1205 let recovery_config = RecoveryConfig::from_config(&config);
1206
1207 let path = Path::new(
1208 client_addr,
1209 server_addr,
1210 &recovery_config,
1211 config.path_challenge_recv_max_queue_len,
1212 true,
1213 None,
1214 );
1215 let mut client_path_mgr = PathMap::new(path, 2, false);
1216 let mut server_path = Path::new(
1217 server_addr,
1218 client_addr,
1219 &recovery_config,
1220 config.path_challenge_recv_max_queue_len,
1221 false,
1222 None,
1223 );
1224
1225 let client_pid = client_path_mgr
1226 .path_id_from_addrs(&(client_addr, server_addr))
1227 .unwrap();
1228
1229 let data = rand::rand_u64().to_be_bytes();
1231
1232 client_path_mgr
1233 .get_mut(client_pid)
1234 .unwrap()
1235 .add_challenge_sent(data, MIN_CLIENT_INITIAL_LEN, Instant::now());
1236
1237 let data_2 = rand::rand_u64().to_be_bytes();
1239
1240 client_path_mgr
1241 .get_mut(client_pid)
1242 .unwrap()
1243 .add_challenge_sent(data_2, MIN_CLIENT_INITIAL_LEN, Instant::now());
1244 assert_eq!(
1245 client_path_mgr
1246 .get(client_pid)
1247 .unwrap()
1248 .in_flight_challenges
1249 .len(),
1250 2
1251 );
1252
1253 let data_3 = rand::rand_u64().to_be_bytes();
1255
1256 client_path_mgr
1257 .get_mut(client_pid)
1258 .unwrap()
1259 .add_challenge_sent(data_3, MIN_CLIENT_INITIAL_LEN, Instant::now());
1260 assert_eq!(
1261 client_path_mgr
1262 .get(client_pid)
1263 .unwrap()
1264 .in_flight_challenges
1265 .len(),
1266 3
1267 );
1268
1269 let data_4 = rand::rand_u64().to_be_bytes();
1271
1272 client_path_mgr
1273 .get_mut(client_pid)
1274 .unwrap()
1275 .add_challenge_sent(data_4, MIN_CLIENT_INITIAL_LEN, Instant::now());
1276 assert_eq!(
1277 client_path_mgr
1278 .get(client_pid)
1279 .unwrap()
1280 .in_flight_challenges
1281 .len(),
1282 4
1283 );
1284
1285 server_path.on_challenge_received(data);
1288 assert_eq!(server_path.received_challenges.len(), 1);
1289 server_path.on_challenge_received(data_2);
1290 assert_eq!(server_path.received_challenges.len(), 2);
1291 server_path.on_challenge_received(data_3);
1292 assert_eq!(server_path.received_challenges.len(), 3);
1293 server_path.on_challenge_received(data_4);
1294 assert_eq!(server_path.received_challenges.len(), 3);
1295
1296 client_path_mgr.on_response_received(data).unwrap();
1298 assert_eq!(
1299 client_path_mgr
1300 .get(client_pid)
1301 .unwrap()
1302 .in_flight_challenges
1303 .len(),
1304 3
1305 );
1306
1307 client_path_mgr.on_response_received(data_2).unwrap();
1309 assert_eq!(
1310 client_path_mgr
1311 .get(client_pid)
1312 .unwrap()
1313 .in_flight_challenges
1314 .len(),
1315 2
1316 );
1317
1318 client_path_mgr.on_response_received(data_3).unwrap();
1320 assert_eq!(
1321 client_path_mgr
1322 .get(client_pid)
1323 .unwrap()
1324 .in_flight_challenges
1325 .len(),
1326 1
1327 );
1328
1329 }
1331}