• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 use std::time;
28 
29 use std::collections::BTreeMap;
30 use std::collections::VecDeque;
31 use std::net::SocketAddr;
32 
33 use slab::Slab;
34 
35 use crate::Error;
36 use crate::Result;
37 
38 use crate::recovery;
39 use crate::recovery::HandshakeStatus;
40 
41 /// The different states of the path validation.
42 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
43 pub enum PathState {
44     /// The path failed its validation.
45     Failed,
46 
47     /// The path exists, but no path validation has been performed.
48     Unknown,
49 
50     /// The path is under validation.
51     Validating,
52 
53     /// The remote address has been validated, but not the path MTU.
54     ValidatingMTU,
55 
56     /// The path has been validated.
57     Validated,
58 }
59 
60 impl PathState {
61     #[cfg(feature = "ffi")]
to_c(self) -> libc::ssize_t62     pub fn to_c(self) -> libc::ssize_t {
63         match self {
64             PathState::Failed => -1,
65             PathState::Unknown => 0,
66             PathState::Validating => 1,
67             PathState::ValidatingMTU => 2,
68             PathState::Validated => 3,
69         }
70     }
71 }
72 
73 /// A path-specific event.
74 #[derive(Clone, Debug, PartialEq, Eq)]
75 pub enum PathEvent {
76     /// A new network path (local address, peer address) has been seen on a
77     /// received packet. Note that this event is only triggered for servers, as
78     /// the client is responsible from initiating new paths. The application may
79     /// then probe this new path, if desired.
80     New(SocketAddr, SocketAddr),
81 
82     /// The related network path between local `SocketAddr` and peer
83     /// `SocketAddr` has been validated.
84     Validated(SocketAddr, SocketAddr),
85 
86     /// The related network path between local `SocketAddr` and peer
87     /// `SocketAddr` failed to be validated. This network path will not be used
88     /// anymore, unless the application requests probing this path again.
89     FailedValidation(SocketAddr, SocketAddr),
90 
91     /// The related network path between local `SocketAddr` and peer
92     /// `SocketAddr` has been closed and is now unusable on this connection.
93     Closed(SocketAddr, SocketAddr),
94 
95     /// The stack observes that the Source Connection ID with the given sequence
96     /// number, initially used by the peer over the first pair of `SocketAddr`s,
97     /// is now reused over the second pair of `SocketAddr`s.
98     ReusedSourceConnectionId(
99         u64,
100         (SocketAddr, SocketAddr),
101         (SocketAddr, SocketAddr),
102     ),
103 
104     /// The connection observed that the peer migrated over the network path
105     /// denoted by the pair of `SocketAddr`, i.e., non-probing packets have been
106     /// received on this network path. This is a server side only event.
107     ///
108     /// Note that this event is only raised if the path has been validated.
109     PeerMigrated(SocketAddr, SocketAddr),
110 }
111 
112 /// A network path on which QUIC packets can be sent.
113 #[derive(Debug)]
114 pub struct Path {
115     /// The local address.
116     local_addr: SocketAddr,
117 
118     /// The remote address.
119     peer_addr: SocketAddr,
120 
121     /// Source CID sequence number used over that path.
122     pub active_scid_seq: Option<u64>,
123 
124     /// Destination CID sequence number used over that path.
125     pub active_dcid_seq: Option<u64>,
126 
127     /// The current validation state of the path.
128     state: PathState,
129 
130     /// Is this path used to send non-probing packets.
131     active: bool,
132 
133     /// Loss recovery and congestion control state.
134     pub recovery: recovery::Recovery,
135 
136     /// Pending challenge data with the size of the packet containing them and
137     /// when they were sent.
138     in_flight_challenges: VecDeque<([u8; 8], usize, time::Instant)>,
139 
140     /// The maximum challenge size that got acknowledged.
141     max_challenge_size: usize,
142 
143     /// Number of consecutive (spaced by at least 1 RTT) probing packets lost.
144     probing_lost: usize,
145 
146     /// Last instant when a probing packet got lost.
147     last_probe_lost_time: Option<time::Instant>,
148 
149     /// Received challenge data.
150     received_challenges: VecDeque<[u8; 8]>,
151 
152     /// Number of packets sent on this path.
153     pub sent_count: usize,
154 
155     /// Number of packets received on this path.
156     pub recv_count: usize,
157 
158     /// Total number of packets sent with data retransmitted from this path.
159     pub retrans_count: usize,
160 
161     /// Total number of sent bytes over this path.
162     pub sent_bytes: u64,
163 
164     /// Total number of bytes received over this path.
165     pub recv_bytes: u64,
166 
167     /// Total number of bytes retransmitted from this path.
168     /// This counts only STREAM and CRYPTO data.
169     pub stream_retrans_bytes: u64,
170 
171     /// Total number of bytes the server can send before the peer's address
172     /// is verified.
173     pub max_send_bytes: usize,
174 
175     /// Whether the peer's address has been verified.
176     pub verified_peer_address: bool,
177 
178     /// Whether the peer has verified our address.
179     pub peer_verified_local_address: bool,
180 
181     /// Does it requires sending PATH_CHALLENGE?
182     challenge_requested: bool,
183 
184     /// Whether the failure of this path was notified.
185     failure_notified: bool,
186 
187     /// Whether the connection tries to migrate to this path, but it still needs
188     /// to be validated.
189     migrating: bool,
190 
191     /// Whether or not we should force eliciting of an ACK (e.g. via PING frame)
192     pub needs_ack_eliciting: bool,
193 }
194 
195 impl Path {
196     /// Create a new Path instance with the provided addresses, the remaining of
197     /// the fields being set to their default value.
new( local_addr: SocketAddr, peer_addr: SocketAddr, recovery_config: &recovery::RecoveryConfig, is_initial: bool, ) -> Self198     pub fn new(
199         local_addr: SocketAddr, peer_addr: SocketAddr,
200         recovery_config: &recovery::RecoveryConfig, is_initial: bool,
201     ) -> Self {
202         let (state, active_scid_seq, active_dcid_seq) = if is_initial {
203             (PathState::Validated, Some(0), Some(0))
204         } else {
205             (PathState::Unknown, None, None)
206         };
207 
208         Self {
209             local_addr,
210             peer_addr,
211             active_scid_seq,
212             active_dcid_seq,
213             state,
214             active: false,
215             recovery: recovery::Recovery::new_with_config(recovery_config),
216             in_flight_challenges: VecDeque::new(),
217             max_challenge_size: 0,
218             probing_lost: 0,
219             last_probe_lost_time: None,
220             received_challenges: VecDeque::new(),
221             sent_count: 0,
222             recv_count: 0,
223             retrans_count: 0,
224             sent_bytes: 0,
225             recv_bytes: 0,
226             stream_retrans_bytes: 0,
227             max_send_bytes: 0,
228             verified_peer_address: false,
229             peer_verified_local_address: false,
230             challenge_requested: false,
231             failure_notified: false,
232             migrating: false,
233             needs_ack_eliciting: false,
234         }
235     }
236 
237     /// Returns the local address on which this path operates.
238     #[inline]
local_addr(&self) -> SocketAddr239     pub fn local_addr(&self) -> SocketAddr {
240         self.local_addr
241     }
242 
243     /// Returns the peer address on which this path operates.
244     #[inline]
peer_addr(&self) -> SocketAddr245     pub fn peer_addr(&self) -> SocketAddr {
246         self.peer_addr
247     }
248 
249     /// Returns whether the path is working (i.e., not failed).
250     #[inline]
working(&self) -> bool251     fn working(&self) -> bool {
252         self.state > PathState::Failed
253     }
254 
255     /// Returns whether the path is active.
256     #[inline]
active(&self) -> bool257     pub fn active(&self) -> bool {
258         self.active && self.working() && self.active_dcid_seq.is_some()
259     }
260 
261     /// Returns whether the path can be used to send non-probing packets.
262     #[inline]
usable(&self) -> bool263     pub fn usable(&self) -> bool {
264         self.active() ||
265             (self.state == PathState::Validated &&
266                 self.active_dcid_seq.is_some())
267     }
268 
269     /// Returns whether the path is unused.
270     #[inline]
unused(&self) -> bool271     fn unused(&self) -> bool {
272         // FIXME: we should check that there is nothing in the sent queue.
273         !self.active() && self.active_dcid_seq.is_none()
274     }
275 
276     /// Returns whether the path requires sending a probing packet.
277     #[inline]
probing_required(&self) -> bool278     pub fn probing_required(&self) -> bool {
279         !self.received_challenges.is_empty() || self.validation_requested()
280     }
281 
282     /// Promotes the path to the provided state only if the new state is greater
283     /// than the current one.
promote_to(&mut self, state: PathState)284     fn promote_to(&mut self, state: PathState) {
285         if self.state < state {
286             self.state = state;
287         }
288     }
289 
290     /// Returns whether the path is validated.
291     #[inline]
validated(&self) -> bool292     pub fn validated(&self) -> bool {
293         self.state == PathState::Validated
294     }
295 
296     /// Returns whether this path failed its validation.
297     #[inline]
validation_failed(&self) -> bool298     fn validation_failed(&self) -> bool {
299         self.state == PathState::Failed
300     }
301 
302     // Returns whether this path is under path validation process.
303     #[inline]
under_validation(&self) -> bool304     pub fn under_validation(&self) -> bool {
305         matches!(self.state, PathState::Validating | PathState::ValidatingMTU)
306     }
307 
308     /// Requests path validation.
309     #[inline]
request_validation(&mut self)310     pub fn request_validation(&mut self) {
311         self.challenge_requested = true;
312     }
313 
314     /// Returns whether a validation is requested.
315     #[inline]
validation_requested(&self) -> bool316     pub fn validation_requested(&self) -> bool {
317         self.challenge_requested
318     }
319 
on_challenge_sent(&mut self)320     pub fn on_challenge_sent(&mut self) {
321         self.promote_to(PathState::Validating);
322         self.challenge_requested = false;
323     }
324 
325     /// Handles the sending of PATH_CHALLENGE.
add_challenge_sent( &mut self, data: [u8; 8], pkt_size: usize, sent_time: time::Instant, )326     pub fn add_challenge_sent(
327         &mut self, data: [u8; 8], pkt_size: usize, sent_time: time::Instant,
328     ) {
329         self.on_challenge_sent();
330         self.in_flight_challenges
331             .push_back((data, pkt_size, sent_time));
332     }
333 
on_challenge_received(&mut self, data: [u8; 8])334     pub fn on_challenge_received(&mut self, data: [u8; 8]) {
335         self.received_challenges.push_back(data);
336         self.peer_verified_local_address = true;
337     }
338 
has_pending_challenge(&self, data: [u8; 8]) -> bool339     pub fn has_pending_challenge(&self, data: [u8; 8]) -> bool {
340         self.in_flight_challenges.iter().any(|(d, ..)| *d == data)
341     }
342 
343     /// Returns whether the path is now validated.
on_response_received(&mut self, data: [u8; 8]) -> bool344     pub fn on_response_received(&mut self, data: [u8; 8]) -> bool {
345         self.verified_peer_address = true;
346         self.probing_lost = 0;
347 
348         let mut challenge_size = 0;
349         self.in_flight_challenges.retain(|(d, s, _)| {
350             if *d == data {
351                 challenge_size = *s;
352                 false
353             } else {
354                 true
355             }
356         });
357 
358         // The 4-tuple is reachable, but we didn't check Path MTU yet.
359         self.promote_to(PathState::ValidatingMTU);
360 
361         self.max_challenge_size =
362             std::cmp::max(self.max_challenge_size, challenge_size);
363 
364         if self.state == PathState::ValidatingMTU {
365             if self.max_challenge_size >= crate::MIN_CLIENT_INITIAL_LEN {
366                 // Path MTU is sufficient for QUIC traffic.
367                 self.promote_to(PathState::Validated);
368                 return true;
369             }
370 
371             // If the MTU was not validated, probe again.
372             self.request_validation();
373         }
374 
375         false
376     }
377 
on_failed_validation(&mut self)378     fn on_failed_validation(&mut self) {
379         self.state = PathState::Failed;
380         self.active = false;
381     }
382 
383     #[inline]
pop_received_challenge(&mut self) -> Option<[u8; 8]>384     pub fn pop_received_challenge(&mut self) -> Option<[u8; 8]> {
385         self.received_challenges.pop_front()
386     }
387 
on_loss_detection_timeout( &mut self, handshake_status: HandshakeStatus, now: time::Instant, is_server: bool, trace_id: &str, ) -> (usize, usize)388     pub fn on_loss_detection_timeout(
389         &mut self, handshake_status: HandshakeStatus, now: time::Instant,
390         is_server: bool, trace_id: &str,
391     ) -> (usize, usize) {
392         let (lost_packets, lost_bytes) = self.recovery.on_loss_detection_timeout(
393             handshake_status,
394             now,
395             trace_id,
396         );
397 
398         let mut lost_probe_time = None;
399         self.in_flight_challenges.retain(|(_, _, sent_time)| {
400             if *sent_time <= now {
401                 if lost_probe_time.is_none() {
402                     lost_probe_time = Some(*sent_time);
403                 }
404                 false
405             } else {
406                 true
407             }
408         });
409 
410         // If we lost probing packets, check if the path failed
411         // validation.
412         if let Some(lost_probe_time) = lost_probe_time {
413             self.last_probe_lost_time = match self.last_probe_lost_time {
414                 Some(last) => {
415                     // Count a loss if at least 1-RTT happened.
416                     if lost_probe_time - last >= self.recovery.rtt() {
417                         self.probing_lost += 1;
418                         Some(lost_probe_time)
419                     } else {
420                         Some(last)
421                     }
422                 },
423                 None => {
424                     self.probing_lost += 1;
425                     Some(lost_probe_time)
426                 },
427             };
428             // As a server, if requesting a challenge is not
429             // possible due to the amplification attack, declare the
430             // validation as failed.
431             if self.probing_lost >= crate::MAX_PROBING_TIMEOUTS ||
432                 (is_server && self.max_send_bytes < crate::MIN_PROBING_SIZE)
433             {
434                 self.on_failed_validation();
435             } else {
436                 self.request_validation();
437             }
438         }
439 
440         (lost_packets, lost_bytes)
441     }
442 
stats(&self) -> PathStats443     pub fn stats(&self) -> PathStats {
444         PathStats {
445             local_addr: self.local_addr,
446             peer_addr: self.peer_addr,
447             validation_state: self.state,
448             active: self.active,
449             recv: self.recv_count,
450             sent: self.sent_count,
451             lost: self.recovery.lost_count,
452             retrans: self.retrans_count,
453             rtt: self.recovery.rtt(),
454             min_rtt: self.recovery.min_rtt(),
455             rttvar: self.recovery.rttvar(),
456             cwnd: self.recovery.cwnd(),
457             sent_bytes: self.sent_bytes,
458             recv_bytes: self.recv_bytes,
459             lost_bytes: self.recovery.bytes_lost,
460             stream_retrans_bytes: self.stream_retrans_bytes,
461             pmtu: self.recovery.max_datagram_size(),
462             delivery_rate: self.recovery.delivery_rate(),
463         }
464     }
465 }
466 
467 /// An iterator over SocketAddr.
468 #[derive(Default)]
469 pub struct SocketAddrIter {
470     pub(crate) sockaddrs: Vec<SocketAddr>,
471 }
472 
473 impl Iterator for SocketAddrIter {
474     type Item = SocketAddr;
475 
476     #[inline]
next(&mut self) -> Option<Self::Item>477     fn next(&mut self) -> Option<Self::Item> {
478         self.sockaddrs.pop()
479     }
480 }
481 
482 impl ExactSizeIterator for SocketAddrIter {
483     #[inline]
len(&self) -> usize484     fn len(&self) -> usize {
485         self.sockaddrs.len()
486     }
487 }
488 
489 /// All path-related information.
490 pub struct PathMap {
491     /// The paths of the connection. Each of them has an internal identifier
492     /// that is used by `addrs_to_paths` and `ConnectionEntry`.
493     paths: Slab<Path>,
494 
495     /// The maximum number of concurrent paths allowed.
496     max_concurrent_paths: usize,
497 
498     /// The mapping from the (local `SocketAddr`, peer `SocketAddr`) to the
499     /// `Path` structure identifier.
500     addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
501 
502     /// Path-specific events to be notified to the application.
503     events: VecDeque<PathEvent>,
504 
505     /// Whether this manager serves a connection as a server.
506     is_server: bool,
507 }
508 
509 impl PathMap {
510     /// Creates a new `PathMap` with the initial provided `path` and a
511     /// capacity limit.
new( mut initial_path: Path, max_concurrent_paths: usize, is_server: bool, ) -> Self512     pub fn new(
513         mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
514     ) -> Self {
515         let mut paths = Slab::with_capacity(1); // most connections only have one path
516         let mut addrs_to_paths = BTreeMap::new();
517 
518         let local_addr = initial_path.local_addr;
519         let peer_addr = initial_path.peer_addr;
520 
521         // As it is the first path, it is active by default.
522         initial_path.active = true;
523 
524         let active_path_id = paths.insert(initial_path);
525         addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
526 
527         Self {
528             paths,
529             max_concurrent_paths,
530             addrs_to_paths,
531             events: VecDeque::new(),
532             is_server,
533         }
534     }
535 
536     /// Gets an immutable reference to the path identified by `path_id`. If the
537     /// provided `path_id` does not identify any current `Path`, returns an
538     /// [`InvalidState`].
539     ///
540     /// [`InvalidState`]: enum.Error.html#variant.InvalidState
541     #[inline]
get(&self, path_id: usize) -> Result<&Path>542     pub fn get(&self, path_id: usize) -> Result<&Path> {
543         self.paths.get(path_id).ok_or(Error::InvalidState)
544     }
545 
546     /// Gets a mutable reference to the path identified by `path_id`. If the
547     /// provided `path_id` does not identify any current `Path`, returns an
548     /// [`InvalidState`].
549     ///
550     /// [`InvalidState`]: enum.Error.html#variant.InvalidState
551     #[inline]
get_mut(&mut self, path_id: usize) -> Result<&mut Path>552     pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
553         self.paths.get_mut(path_id).ok_or(Error::InvalidState)
554     }
555 
556     #[inline]
557     /// Gets an immutable reference to the active path with the value of the
558     /// lowest identifier. If there is no active path, returns `None`.
get_active_with_pid(&self) -> Option<(usize, &Path)>559     pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
560         self.paths.iter().find(|(_, p)| p.active())
561     }
562 
563     /// Gets an immutable reference to the active path with the lowest
564     /// identifier. If there is no active path, returns an [`InvalidState`].
565     ///
566     /// [`InvalidState`]: enum.Error.html#variant.InvalidState
567     #[inline]
get_active(&self) -> Result<&Path>568     pub fn get_active(&self) -> Result<&Path> {
569         self.get_active_with_pid()
570             .map(|(_, p)| p)
571             .ok_or(Error::InvalidState)
572     }
573 
574     /// Gets the lowest active path identifier. If there is no active path,
575     /// returns an [`InvalidState`].
576     ///
577     /// [`InvalidState`]: enum.Error.html#variant.InvalidState
578     #[inline]
get_active_path_id(&self) -> Result<usize>579     pub fn get_active_path_id(&self) -> Result<usize> {
580         self.get_active_with_pid()
581             .map(|(pid, _)| pid)
582             .ok_or(Error::InvalidState)
583     }
584 
585     /// Gets an mutable reference to the active path with the lowest identifier.
586     /// If there is no active path, returns an [`InvalidState`].
587     ///
588     /// [`InvalidState`]: enum.Error.html#variant.InvalidState
589     #[inline]
get_active_mut(&mut self) -> Result<&mut Path>590     pub fn get_active_mut(&mut self) -> Result<&mut Path> {
591         self.paths
592             .iter_mut()
593             .map(|(_, p)| p)
594             .find(|p| p.active())
595             .ok_or(Error::InvalidState)
596     }
597 
598     /// Returns an iterator over all existing paths.
599     #[inline]
iter(&self) -> slab::Iter<Path>600     pub fn iter(&self) -> slab::Iter<Path> {
601         self.paths.iter()
602     }
603 
604     /// Returns a mutable iterator over all existing paths.
605     #[inline]
iter_mut(&mut self) -> slab::IterMut<Path>606     pub fn iter_mut(&mut self) -> slab::IterMut<Path> {
607         self.paths.iter_mut()
608     }
609 
610     /// Returns the number of existing paths.
611     #[inline]
len(&self) -> usize612     pub fn len(&self) -> usize {
613         self.paths.len()
614     }
615 
616     /// Returns the `Path` identifier related to the provided `addrs`.
617     #[inline]
path_id_from_addrs( &self, addrs: &(SocketAddr, SocketAddr), ) -> Option<usize>618     pub fn path_id_from_addrs(
619         &self, addrs: &(SocketAddr, SocketAddr),
620     ) -> Option<usize> {
621         self.addrs_to_paths.get(addrs).copied()
622     }
623 
624     /// Checks if creating a new path will not exceed the current `self.paths`
625     /// capacity. If yes, this method tries to remove one unused path. If it
626     /// fails to do so, returns [`Done`].
627     ///
628     /// [`Done`]: enum.Error.html#variant.Done
make_room_for_new_path(&mut self) -> Result<()>629     fn make_room_for_new_path(&mut self) -> Result<()> {
630         if self.paths.len() < self.max_concurrent_paths {
631             return Ok(());
632         }
633 
634         let (pid_to_remove, _) = self
635             .paths
636             .iter()
637             .find(|(_, p)| p.unused())
638             .ok_or(Error::Done)?;
639 
640         let path = self.paths.remove(pid_to_remove);
641         self.addrs_to_paths
642             .remove(&(path.local_addr, path.peer_addr));
643 
644         self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
645 
646         Ok(())
647     }
648 
649     /// Records the provided `Path` and returns its assigned identifier.
650     ///
651     /// On success, this method takes care of creating a notification to the
652     /// serving application, if it serves a server-side connection.
653     ///
654     /// If there are already `max_concurrent_paths` currently recorded, this
655     /// method tries to remove an unused `Path` first. If it fails to do so,
656     /// it returns [`Done`].
657     ///
658     /// [`Done`]: enum.Error.html#variant.Done
insert_path(&mut self, path: Path, is_server: bool) -> Result<usize>659     pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
660         self.make_room_for_new_path()?;
661 
662         let local_addr = path.local_addr;
663         let peer_addr = path.peer_addr;
664 
665         let pid = self.paths.insert(path);
666         self.addrs_to_paths.insert((local_addr, peer_addr), pid);
667 
668         // Notifies the application if we are in server mode.
669         if is_server {
670             self.notify_event(PathEvent::New(local_addr, peer_addr));
671         }
672 
673         Ok(pid)
674     }
675 
676     /// Notifies a path event to the application served by the connection.
notify_event(&mut self, ev: PathEvent)677     pub fn notify_event(&mut self, ev: PathEvent) {
678         self.events.push_back(ev);
679     }
680 
681     /// Gets the first path event to be notified to the application.
pop_event(&mut self) -> Option<PathEvent>682     pub fn pop_event(&mut self) -> Option<PathEvent> {
683         self.events.pop_front()
684     }
685 
686     /// Notifies all failed validations to the application.
notify_failed_validations(&mut self)687     pub fn notify_failed_validations(&mut self) {
688         let validation_failed = self
689             .paths
690             .iter_mut()
691             .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
692 
693         for (_, p) in validation_failed {
694             self.events.push_back(PathEvent::FailedValidation(
695                 p.local_addr,
696                 p.peer_addr,
697             ));
698 
699             p.failure_notified = true;
700         }
701     }
702 
703     /// Finds a path candidate to be active and returns its identifier.
find_candidate_path(&self) -> Option<usize>704     pub fn find_candidate_path(&self) -> Option<usize> {
705         // TODO: also consider unvalidated paths if there are no more validated.
706         self.paths
707             .iter()
708             .find(|(_, p)| p.usable())
709             .map(|(pid, _)| pid)
710     }
711 
712     /// Handles incoming PATH_RESPONSE data.
on_response_received(&mut self, data: [u8; 8]) -> Result<()>713     pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
714         let active_pid = self.get_active_path_id()?;
715 
716         let challenge_pending =
717             self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
718 
719         if let Some((pid, p)) = challenge_pending {
720             if p.on_response_received(data) {
721                 let local_addr = p.local_addr;
722                 let peer_addr = p.peer_addr;
723                 let was_migrating = p.migrating;
724 
725                 p.migrating = false;
726 
727                 // Notifies the application.
728                 self.notify_event(PathEvent::Validated(local_addr, peer_addr));
729 
730                 // If this path was the candidate for migration, notifies the
731                 // application.
732                 if pid == active_pid && was_migrating {
733                     self.notify_event(PathEvent::PeerMigrated(
734                         local_addr, peer_addr,
735                     ));
736                 }
737             }
738         }
739         Ok(())
740     }
741 
742     /// Sets the path with identifier 'path_id' to be active.
743     ///
744     /// There can be exactly one active path on which non-probing packets can be
745     /// sent. If another path is marked as active, it will be superseded by the
746     /// one having `path_id` as identifier.
747     ///
748     /// A server should always ensure that the active path is validated. If it
749     /// is already the case, it notifies the application that the connection
750     /// migrated. Otherwise, it triggers a path validation and defers the
751     /// notification once it is actually validated.
set_active_path(&mut self, path_id: usize) -> Result<()>752     pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
753         let is_server = self.is_server;
754 
755         if let Ok(old_active_path) = self.get_active_mut() {
756             old_active_path.active = false;
757         }
758 
759         let new_active_path = self.get_mut(path_id)?;
760         new_active_path.active = true;
761 
762         if is_server {
763             if new_active_path.validated() {
764                 let local_addr = new_active_path.local_addr();
765                 let peer_addr = new_active_path.peer_addr();
766 
767                 self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
768             } else {
769                 new_active_path.migrating = true;
770 
771                 // Requests path validation if needed.
772                 if !new_active_path.under_validation() {
773                     new_active_path.request_validation();
774                 }
775             }
776         }
777 
778         Ok(())
779     }
780 
781     /// Handles potential connection migration.
on_peer_migrated( &mut self, new_pid: usize, disable_dcid_reuse: bool, ) -> Result<()>782     pub fn on_peer_migrated(
783         &mut self, new_pid: usize, disable_dcid_reuse: bool,
784     ) -> Result<()> {
785         let active_path_id = self.get_active_path_id()?;
786 
787         if active_path_id == new_pid {
788             return Ok(());
789         }
790 
791         self.set_active_path(new_pid)?;
792 
793         let no_spare_dcid = self.get_mut(new_pid)?.active_dcid_seq.is_none();
794 
795         if no_spare_dcid && !disable_dcid_reuse {
796             self.get_mut(new_pid)?.active_dcid_seq =
797                 self.get_mut(active_path_id)?.active_dcid_seq;
798         }
799 
800         Ok(())
801     }
802 }
803 
804 /// Statistics about the path of a connection.
805 ///
806 /// It is part of the `Stats` structure returned by the [`stats()`] method.
807 ///
808 /// [`stats()`]: struct.Connection.html#method.stats
809 #[derive(Clone)]
810 pub struct PathStats {
811     /// The local address of the path.
812     pub local_addr: SocketAddr,
813 
814     /// The peer address of the path.
815     pub peer_addr: SocketAddr,
816 
817     /// The path validation state.
818     pub validation_state: PathState,
819 
820     /// Whether the path is marked as active.
821     pub active: bool,
822 
823     /// The number of QUIC packets received.
824     pub recv: usize,
825 
826     /// The number of QUIC packets sent.
827     pub sent: usize,
828 
829     /// The number of QUIC packets that were lost.
830     pub lost: usize,
831 
832     /// The number of sent QUIC packets with retransmitted data.
833     pub retrans: usize,
834 
835     /// The estimated round-trip time of the connection.
836     pub rtt: time::Duration,
837 
838     /// The minimum round-trip time observed.
839     pub min_rtt: Option<time::Duration>,
840 
841     /// The estimated round-trip time variation in samples using a mean
842     /// variation.
843     pub rttvar: time::Duration,
844 
845     /// The size of the connection's congestion window in bytes.
846     pub cwnd: usize,
847 
848     /// The number of sent bytes.
849     pub sent_bytes: u64,
850 
851     /// The number of received bytes.
852     pub recv_bytes: u64,
853 
854     /// The number of bytes lost.
855     pub lost_bytes: u64,
856 
857     /// The number of stream bytes retransmitted.
858     pub stream_retrans_bytes: u64,
859 
860     /// The current PMTU for the connection.
861     pub pmtu: usize,
862 
863     /// The most recent data delivery rate estimate in bytes/s.
864     ///
865     /// Note that this value could be inaccurate if the application does not
866     /// respect pacing hints (see [`SendInfo.at`] and [Pacing] for more
867     /// details).
868     ///
869     /// [`SendInfo.at`]: struct.SendInfo.html#structfield.at
870     /// [Pacing]: index.html#pacing
871     pub delivery_rate: u64,
872 }
873 
874 impl std::fmt::Debug for PathStats {
875     #[inline]
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result876     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
877         write!(
878             f,
879             "local_addr={:?} peer_addr={:?} ",
880             self.local_addr, self.peer_addr,
881         )?;
882         write!(
883             f,
884             "validation_state={:?} active={} ",
885             self.validation_state, self.active,
886         )?;
887         write!(
888             f,
889             "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
890             self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
891         )?;
892 
893         write!(
894             f,
895             " sent_bytes={} recv_bytes={} lost_bytes={}",
896             self.sent_bytes, self.recv_bytes, self.lost_bytes,
897         )?;
898 
899         write!(
900             f,
901             " stream_retrans_bytes={} pmtu={} delivery_rate={}",
902             self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
903         )
904     }
905 }
906 
907 #[cfg(test)]
908 mod tests {
909     use crate::rand;
910     use crate::MIN_CLIENT_INITIAL_LEN;
911 
912     use crate::recovery::RecoveryConfig;
913     use crate::Config;
914 
915     use super::*;
916 
917     #[test]
path_validation_limited_mtu()918     fn path_validation_limited_mtu() {
919         let client_addr = "127.0.0.1:1234".parse().unwrap();
920         let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
921         let server_addr = "127.0.0.1:4321".parse().unwrap();
922 
923         let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
924         let recovery_config = RecoveryConfig::from_config(&config);
925 
926         let path = Path::new(client_addr, server_addr, &recovery_config, true);
927         let mut path_mgr = PathMap::new(path, 2, false);
928 
929         let probed_path =
930             Path::new(client_addr_2, server_addr, &recovery_config, false);
931         path_mgr.insert_path(probed_path, false).unwrap();
932 
933         let pid = path_mgr
934             .path_id_from_addrs(&(client_addr_2, server_addr))
935             .unwrap();
936         path_mgr.get_mut(pid).unwrap().request_validation();
937         assert_eq!(path_mgr.get_mut(pid).unwrap().validation_requested(), true);
938         assert_eq!(path_mgr.get_mut(pid).unwrap().probing_required(), true);
939 
940         // Fake sending of PathChallenge in a packet of MIN_CLIENT_INITIAL_LEN - 1
941         // bytes.
942         let data = rand::rand_u64().to_be_bytes();
943         path_mgr.get_mut(pid).unwrap().add_challenge_sent(
944             data,
945             MIN_CLIENT_INITIAL_LEN - 1,
946             time::Instant::now(),
947         );
948 
949         assert_eq!(path_mgr.get_mut(pid).unwrap().validation_requested(), false);
950         assert_eq!(path_mgr.get_mut(pid).unwrap().probing_required(), false);
951         assert_eq!(path_mgr.get_mut(pid).unwrap().under_validation(), true);
952         assert_eq!(path_mgr.get_mut(pid).unwrap().validated(), false);
953         assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
954         assert_eq!(path_mgr.pop_event(), None);
955 
956         // Receives the response. The path is reachable, but the MTU is not
957         // validated yet.
958         path_mgr.on_response_received(data).unwrap();
959 
960         assert_eq!(path_mgr.get_mut(pid).unwrap().validation_requested(), true);
961         assert_eq!(path_mgr.get_mut(pid).unwrap().probing_required(), true);
962         assert_eq!(path_mgr.get_mut(pid).unwrap().under_validation(), true);
963         assert_eq!(path_mgr.get_mut(pid).unwrap().validated(), false);
964         assert_eq!(
965             path_mgr.get_mut(pid).unwrap().state,
966             PathState::ValidatingMTU
967         );
968         assert_eq!(path_mgr.pop_event(), None);
969 
970         // Fake sending of PathChallenge in a packet of MIN_CLIENT_INITIAL_LEN
971         // bytes.
972         let data = rand::rand_u64().to_be_bytes();
973         path_mgr.get_mut(pid).unwrap().add_challenge_sent(
974             data,
975             MIN_CLIENT_INITIAL_LEN,
976             time::Instant::now(),
977         );
978 
979         path_mgr.on_response_received(data).unwrap();
980 
981         assert_eq!(path_mgr.get_mut(pid).unwrap().validation_requested(), false);
982         assert_eq!(path_mgr.get_mut(pid).unwrap().probing_required(), false);
983         assert_eq!(path_mgr.get_mut(pid).unwrap().under_validation(), false);
984         assert_eq!(path_mgr.get_mut(pid).unwrap().validated(), true);
985         assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
986         assert_eq!(
987             path_mgr.pop_event(),
988             Some(PathEvent::Validated(client_addr_2, server_addr))
989         );
990     }
991 
992     #[test]
multiple_probes()993     fn multiple_probes() {
994         let client_addr = "127.0.0.1:1234".parse().unwrap();
995         let server_addr = "127.0.0.1:4321".parse().unwrap();
996 
997         let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
998         let recovery_config = RecoveryConfig::from_config(&config);
999 
1000         let path = Path::new(client_addr, server_addr, &recovery_config, true);
1001         let mut client_path_mgr = PathMap::new(path, 2, false);
1002         let mut server_path =
1003             Path::new(server_addr, client_addr, &recovery_config, false);
1004 
1005         let client_pid = client_path_mgr
1006             .path_id_from_addrs(&(client_addr, server_addr))
1007             .unwrap();
1008 
1009         // First probe.
1010         let data = rand::rand_u64().to_be_bytes();
1011 
1012         client_path_mgr
1013             .get_mut(client_pid)
1014             .unwrap()
1015             .add_challenge_sent(
1016                 data,
1017                 MIN_CLIENT_INITIAL_LEN,
1018                 time::Instant::now(),
1019             );
1020 
1021         // Second probe.
1022         let data_2 = rand::rand_u64().to_be_bytes();
1023 
1024         client_path_mgr
1025             .get_mut(client_pid)
1026             .unwrap()
1027             .add_challenge_sent(
1028                 data_2,
1029                 MIN_CLIENT_INITIAL_LEN,
1030                 time::Instant::now(),
1031             );
1032         assert_eq!(
1033             client_path_mgr
1034                 .get(client_pid)
1035                 .unwrap()
1036                 .in_flight_challenges
1037                 .len(),
1038             2
1039         );
1040 
1041         // If we receive multiple challenges, we can store them.
1042         server_path.on_challenge_received(data);
1043         assert_eq!(server_path.received_challenges.len(), 1);
1044         server_path.on_challenge_received(data_2);
1045         assert_eq!(server_path.received_challenges.len(), 2);
1046 
1047         // Response for first probe.
1048         client_path_mgr.on_response_received(data).unwrap();
1049         assert_eq!(
1050             client_path_mgr
1051                 .get(client_pid)
1052                 .unwrap()
1053                 .in_flight_challenges
1054                 .len(),
1055             1
1056         );
1057 
1058         // Response for second probe.
1059         client_path_mgr.on_response_received(data_2).unwrap();
1060         assert_eq!(
1061             client_path_mgr
1062                 .get(client_pid)
1063                 .unwrap()
1064                 .in_flight_challenges
1065                 .len(),
1066             0
1067         );
1068     }
1069 }
1070