quiche/
path.rs

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
27use std::time;
28
29use std::collections::BTreeMap;
30use std::collections::VecDeque;
31use std::net::SocketAddr;
32
33use smallvec::SmallVec;
34
35use slab::Slab;
36
37use crate::Error;
38use crate::Result;
39
40use crate::pmtud;
41use crate::recovery;
42use crate::recovery::HandshakeStatus;
43
44/// The different states of the path validation.
45#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
46pub enum PathState {
47    /// The path failed its validation.
48    Failed,
49
50    /// The path exists, but no path validation has been performed.
51    Unknown,
52
53    /// The path is under validation.
54    Validating,
55
56    /// The remote address has been validated, but not the path MTU.
57    ValidatingMTU,
58
59    /// The path has been validated.
60    Validated,
61}
62
63impl PathState {
64    #[cfg(feature = "ffi")]
65    pub fn to_c(self) -> libc::ssize_t {
66        match self {
67            PathState::Failed => -1,
68            PathState::Unknown => 0,
69            PathState::Validating => 1,
70            PathState::ValidatingMTU => 2,
71            PathState::Validated => 3,
72        }
73    }
74}
75
76/// A path-specific event.
77#[derive(Clone, Debug, PartialEq, Eq)]
78pub enum PathEvent {
79    /// A new network path (local address, peer address) has been seen on a
80    /// received packet. Note that this event is only triggered for servers, as
81    /// the client is responsible from initiating new paths. The application may
82    /// then probe this new path, if desired.
83    New(SocketAddr, SocketAddr),
84
85    /// The related network path between local `SocketAddr` and peer
86    /// `SocketAddr` has been validated.
87    Validated(SocketAddr, SocketAddr),
88
89    /// The related network path between local `SocketAddr` and peer
90    /// `SocketAddr` failed to be validated. This network path will not be used
91    /// anymore, unless the application requests probing this path again.
92    FailedValidation(SocketAddr, SocketAddr),
93
94    /// The related network path between local `SocketAddr` and peer
95    /// `SocketAddr` has been closed and is now unusable on this connection.
96    Closed(SocketAddr, SocketAddr),
97
98    /// The stack observes that the Source Connection ID with the given sequence
99    /// number, initially used by the peer over the first pair of `SocketAddr`s,
100    /// is now reused over the second pair of `SocketAddr`s.
101    ReusedSourceConnectionId(
102        u64,
103        (SocketAddr, SocketAddr),
104        (SocketAddr, SocketAddr),
105    ),
106
107    /// The connection observed that the peer migrated over the network path
108    /// denoted by the pair of `SocketAddr`, i.e., non-probing packets have been
109    /// received on this network path. This is a server side only event.
110    ///
111    /// Note that this event is only raised if the path has been validated.
112    PeerMigrated(SocketAddr, SocketAddr),
113}
114
115/// A network path on which QUIC packets can be sent.
116#[derive(Debug)]
117pub struct Path {
118    /// The local address.
119    local_addr: SocketAddr,
120
121    /// The remote address.
122    peer_addr: SocketAddr,
123
124    /// Source CID sequence number used over that path.
125    pub active_scid_seq: Option<u64>,
126
127    /// Destination CID sequence number used over that path.
128    pub active_dcid_seq: Option<u64>,
129
130    /// The current validation state of the path.
131    state: PathState,
132
133    /// Is this path used to send non-probing packets.
134    active: bool,
135
136    /// Loss recovery and congestion control state.
137    pub recovery: recovery::Recovery,
138
139    /// Path MTU discovery state.
140    pub pmtud: pmtud::Pmtud,
141
142    /// Pending challenge data with the size of the packet containing them and
143    /// when they were sent.
144    in_flight_challenges: VecDeque<([u8; 8], usize, time::Instant)>,
145
146    /// The maximum challenge size that got acknowledged.
147    max_challenge_size: usize,
148
149    /// Number of consecutive (spaced by at least 1 RTT) probing packets lost.
150    probing_lost: usize,
151
152    /// Last instant when a probing packet got lost.
153    last_probe_lost_time: Option<time::Instant>,
154
155    /// Received challenge data.
156    received_challenges: VecDeque<[u8; 8]>,
157
158    /// Max length of received challenges queue.
159    received_challenges_max_len: usize,
160
161    /// Number of packets sent on this path.
162    pub sent_count: usize,
163
164    /// Number of packets received on this path.
165    pub recv_count: usize,
166
167    /// Total number of packets sent with data retransmitted from this path.
168    pub retrans_count: usize,
169
170    /// Number of DATAGRAM frames sent on this path.
171    pub dgram_sent_count: usize,
172
173    /// Number of DATAGRAM frames received on this path.
174    pub dgram_recv_count: usize,
175
176    /// Total number of sent bytes over this path.
177    pub sent_bytes: u64,
178
179    /// Total number of bytes received over this path.
180    pub recv_bytes: u64,
181
182    /// Total number of bytes retransmitted from this path.
183    /// This counts only STREAM and CRYPTO data.
184    pub stream_retrans_bytes: u64,
185
186    /// Total number of bytes the server can send before the peer's address
187    /// is verified.
188    pub max_send_bytes: usize,
189
190    /// Whether the peer's address has been verified.
191    pub verified_peer_address: bool,
192
193    /// Whether the peer has verified our address.
194    pub peer_verified_local_address: bool,
195
196    /// Does it requires sending PATH_CHALLENGE?
197    challenge_requested: bool,
198
199    /// Whether the failure of this path was notified.
200    failure_notified: bool,
201
202    /// Whether the connection tries to migrate to this path, but it still needs
203    /// to be validated.
204    migrating: bool,
205
206    /// Whether or not we should force eliciting of an ACK (e.g. via PING frame)
207    pub needs_ack_eliciting: bool,
208}
209
210impl Path {
211    /// Create a new Path instance with the provided addresses, the remaining of
212    /// the fields being set to their default value.
213    pub fn new(
214        local_addr: SocketAddr, peer_addr: SocketAddr,
215        recovery_config: &recovery::RecoveryConfig,
216        path_challenge_recv_max_queue_len: usize, pmtud_init: usize,
217        is_initial: bool,
218    ) -> Self {
219        let (state, active_scid_seq, active_dcid_seq) = if is_initial {
220            (PathState::Validated, Some(0), Some(0))
221        } else {
222            (PathState::Unknown, None, None)
223        };
224
225        Self {
226            local_addr,
227            peer_addr,
228            active_scid_seq,
229            active_dcid_seq,
230            state,
231            active: false,
232            recovery: recovery::Recovery::new_with_config(recovery_config),
233            pmtud: pmtud::Pmtud::new(pmtud_init),
234            in_flight_challenges: VecDeque::new(),
235            max_challenge_size: 0,
236            probing_lost: 0,
237            last_probe_lost_time: None,
238            received_challenges: VecDeque::with_capacity(
239                path_challenge_recv_max_queue_len,
240            ),
241            received_challenges_max_len: path_challenge_recv_max_queue_len,
242            sent_count: 0,
243            recv_count: 0,
244            retrans_count: 0,
245            dgram_sent_count: 0,
246            dgram_recv_count: 0,
247            sent_bytes: 0,
248            recv_bytes: 0,
249            stream_retrans_bytes: 0,
250            max_send_bytes: 0,
251            verified_peer_address: false,
252            peer_verified_local_address: false,
253            challenge_requested: false,
254            failure_notified: false,
255            migrating: false,
256            needs_ack_eliciting: false,
257        }
258    }
259
260    /// Returns the local address on which this path operates.
261    #[inline]
262    pub fn local_addr(&self) -> SocketAddr {
263        self.local_addr
264    }
265
266    /// Returns the peer address on which this path operates.
267    #[inline]
268    pub fn peer_addr(&self) -> SocketAddr {
269        self.peer_addr
270    }
271
272    /// Returns whether the path is working (i.e., not failed).
273    #[inline]
274    fn working(&self) -> bool {
275        self.state > PathState::Failed
276    }
277
278    /// Returns whether the path is active.
279    #[inline]
280    pub fn active(&self) -> bool {
281        self.active && self.working() && self.active_dcid_seq.is_some()
282    }
283
284    /// Returns whether the path can be used to send non-probing packets.
285    #[inline]
286    pub fn usable(&self) -> bool {
287        self.active() ||
288            (self.state == PathState::Validated &&
289                self.active_dcid_seq.is_some())
290    }
291
292    /// Returns whether the path is unused.
293    #[inline]
294    fn unused(&self) -> bool {
295        // FIXME: we should check that there is nothing in the sent queue.
296        !self.active() && self.active_dcid_seq.is_none()
297    }
298
299    /// Returns whether the path requires sending a probing packet.
300    #[inline]
301    pub fn probing_required(&self) -> bool {
302        !self.received_challenges.is_empty() || self.validation_requested()
303    }
304
305    /// Promotes the path to the provided state only if the new state is greater
306    /// than the current one.
307    fn promote_to(&mut self, state: PathState) {
308        if self.state < state {
309            self.state = state;
310        }
311    }
312
313    /// Returns whether the path is validated.
314    #[inline]
315    pub fn validated(&self) -> bool {
316        self.state == PathState::Validated
317    }
318
319    /// Returns whether this path failed its validation.
320    #[inline]
321    fn validation_failed(&self) -> bool {
322        self.state == PathState::Failed
323    }
324
325    // Returns whether this path is under path validation process.
326    #[inline]
327    pub fn under_validation(&self) -> bool {
328        matches!(self.state, PathState::Validating | PathState::ValidatingMTU)
329    }
330
331    /// Requests path validation.
332    #[inline]
333    pub fn request_validation(&mut self) {
334        self.challenge_requested = true;
335    }
336
337    /// Returns whether a validation is requested.
338    #[inline]
339    pub fn validation_requested(&self) -> bool {
340        self.challenge_requested
341    }
342
343    pub fn should_send_pmtu_probe(
344        &mut self, hs_confirmed: bool, hs_done: bool, out_len: usize,
345        is_closing: bool, frames_empty: bool,
346    ) -> bool {
347        (hs_confirmed && hs_done) &&
348            self.pmtud.get_probe_size() > self.pmtud.get_current() &&
349            self.recovery.cwnd_available() > self.pmtud.get_probe_size() &&
350            out_len >= self.pmtud.get_probe_size() &&
351            self.pmtud.get_probe_status() &&
352            !is_closing &&
353            frames_empty
354    }
355
356    pub fn on_challenge_sent(&mut self) {
357        self.promote_to(PathState::Validating);
358        self.challenge_requested = false;
359    }
360
361    /// Handles the sending of PATH_CHALLENGE.
362    pub fn add_challenge_sent(
363        &mut self, data: [u8; 8], pkt_size: usize, sent_time: time::Instant,
364    ) {
365        self.on_challenge_sent();
366        self.in_flight_challenges
367            .push_back((data, pkt_size, sent_time));
368    }
369
370    pub fn on_challenge_received(&mut self, data: [u8; 8]) {
371        // Discard challenges that would cause us to queue more than we want.
372        if self.received_challenges.len() == self.received_challenges_max_len {
373            return;
374        }
375
376        self.received_challenges.push_back(data);
377        self.peer_verified_local_address = true;
378    }
379
380    pub fn has_pending_challenge(&self, data: [u8; 8]) -> bool {
381        self.in_flight_challenges.iter().any(|(d, ..)| *d == data)
382    }
383
384    /// Returns whether the path is now validated.
385    pub fn on_response_received(&mut self, data: [u8; 8]) -> bool {
386        self.verified_peer_address = true;
387        self.probing_lost = 0;
388
389        let mut challenge_size = 0;
390        self.in_flight_challenges.retain(|(d, s, _)| {
391            if *d == data {
392                challenge_size = *s;
393                false
394            } else {
395                true
396            }
397        });
398
399        // The 4-tuple is reachable, but we didn't check Path MTU yet.
400        self.promote_to(PathState::ValidatingMTU);
401
402        self.max_challenge_size =
403            std::cmp::max(self.max_challenge_size, challenge_size);
404
405        if self.state == PathState::ValidatingMTU {
406            if self.max_challenge_size >= crate::MIN_CLIENT_INITIAL_LEN {
407                // Path MTU is sufficient for QUIC traffic.
408                self.promote_to(PathState::Validated);
409                return true;
410            }
411
412            // If the MTU was not validated, probe again.
413            self.request_validation();
414        }
415
416        false
417    }
418
419    fn on_failed_validation(&mut self) {
420        self.state = PathState::Failed;
421        self.active = false;
422    }
423
424    #[inline]
425    pub fn pop_received_challenge(&mut self) -> Option<[u8; 8]> {
426        self.received_challenges.pop_front()
427    }
428
429    pub fn on_loss_detection_timeout(
430        &mut self, handshake_status: HandshakeStatus, now: time::Instant,
431        is_server: bool, trace_id: &str,
432    ) -> (usize, usize) {
433        let (lost_packets, lost_bytes) = self.recovery.on_loss_detection_timeout(
434            handshake_status,
435            now,
436            trace_id,
437        );
438
439        let mut lost_probe_time = None;
440        self.in_flight_challenges.retain(|(_, _, sent_time)| {
441            if *sent_time <= now {
442                if lost_probe_time.is_none() {
443                    lost_probe_time = Some(*sent_time);
444                }
445                false
446            } else {
447                true
448            }
449        });
450
451        // If we lost probing packets, check if the path failed
452        // validation.
453        if let Some(lost_probe_time) = lost_probe_time {
454            self.last_probe_lost_time = match self.last_probe_lost_time {
455                Some(last) => {
456                    // Count a loss if at least 1-RTT happened.
457                    if lost_probe_time - last >= self.recovery.rtt() {
458                        self.probing_lost += 1;
459                        Some(lost_probe_time)
460                    } else {
461                        Some(last)
462                    }
463                },
464                None => {
465                    self.probing_lost += 1;
466                    Some(lost_probe_time)
467                },
468            };
469            // As a server, if requesting a challenge is not
470            // possible due to the amplification attack, declare the
471            // validation as failed.
472            if self.probing_lost >= crate::MAX_PROBING_TIMEOUTS ||
473                (is_server && self.max_send_bytes < crate::MIN_PROBING_SIZE)
474            {
475                self.on_failed_validation();
476            } else {
477                self.request_validation();
478            }
479        }
480
481        (lost_packets, lost_bytes)
482    }
483
484    pub fn reinit_recovery(
485        &mut self, recovery_config: &recovery::RecoveryConfig,
486    ) {
487        self.recovery = recovery::Recovery::new_with_config(recovery_config)
488    }
489
490    pub fn stats(&self) -> PathStats {
491        PathStats {
492            local_addr: self.local_addr,
493            peer_addr: self.peer_addr,
494            validation_state: self.state,
495            active: self.active,
496            recv: self.recv_count,
497            sent: self.sent_count,
498            lost: self.recovery.lost_count(),
499            retrans: self.retrans_count,
500            dgram_recv: self.dgram_recv_count,
501            dgram_sent: self.dgram_sent_count,
502            rtt: self.recovery.rtt(),
503            min_rtt: self.recovery.min_rtt(),
504            rttvar: self.recovery.rttvar(),
505            cwnd: self.recovery.cwnd(),
506            sent_bytes: self.sent_bytes,
507            recv_bytes: self.recv_bytes,
508            lost_bytes: self.recovery.bytes_lost,
509            stream_retrans_bytes: self.stream_retrans_bytes,
510            pmtu: self.recovery.max_datagram_size(),
511            delivery_rate: self.recovery.delivery_rate(),
512        }
513    }
514}
515
516/// An iterator over SocketAddr.
517#[derive(Default)]
518pub struct SocketAddrIter {
519    pub(crate) sockaddrs: SmallVec<[SocketAddr; 8]>,
520    pub(crate) index: usize,
521}
522
523impl Iterator for SocketAddrIter {
524    type Item = SocketAddr;
525
526    #[inline]
527    fn next(&mut self) -> Option<Self::Item> {
528        let v = self.sockaddrs.get(self.index)?;
529        self.index += 1;
530        Some(*v)
531    }
532}
533
534impl ExactSizeIterator for SocketAddrIter {
535    #[inline]
536    fn len(&self) -> usize {
537        self.sockaddrs.len() - self.index
538    }
539}
540
541/// All path-related information.
542pub struct PathMap {
543    /// The paths of the connection. Each of them has an internal identifier
544    /// that is used by `addrs_to_paths` and `ConnectionEntry`.
545    paths: Slab<Path>,
546
547    /// The maximum number of concurrent paths allowed.
548    max_concurrent_paths: usize,
549
550    /// The mapping from the (local `SocketAddr`, peer `SocketAddr`) to the
551    /// `Path` structure identifier.
552    addrs_to_paths: BTreeMap<(SocketAddr, SocketAddr), usize>,
553
554    /// Path-specific events to be notified to the application.
555    events: VecDeque<PathEvent>,
556
557    /// Whether this manager serves a connection as a server.
558    is_server: bool,
559}
560
561impl PathMap {
562    /// Creates a new `PathMap` with the initial provided `path` and a
563    /// capacity limit.
564    pub fn new(
565        mut initial_path: Path, max_concurrent_paths: usize, is_server: bool,
566        enable_pmtud: bool, max_send_udp_payload_size: usize,
567    ) -> Self {
568        let mut paths = Slab::with_capacity(1); // most connections only have one path
569        let mut addrs_to_paths = BTreeMap::new();
570
571        let local_addr = initial_path.local_addr;
572        let peer_addr = initial_path.peer_addr;
573
574        // As it is the first path, it is active by default.
575        initial_path.active = true;
576
577        // Enable path MTU Discovery and start probing with the largest datagram
578        // size.
579        if enable_pmtud {
580            initial_path.pmtud.should_probe(enable_pmtud);
581            initial_path.pmtud.set_probe_size(max_send_udp_payload_size);
582            initial_path.pmtud.enable(enable_pmtud);
583        }
584
585        let active_path_id = paths.insert(initial_path);
586        addrs_to_paths.insert((local_addr, peer_addr), active_path_id);
587
588        Self {
589            paths,
590            max_concurrent_paths,
591            addrs_to_paths,
592            events: VecDeque::new(),
593            is_server,
594        }
595    }
596
597    /// Gets an immutable reference to the path identified by `path_id`. If the
598    /// provided `path_id` does not identify any current `Path`, returns an
599    /// [`InvalidState`].
600    ///
601    /// [`InvalidState`]: enum.Error.html#variant.InvalidState
602    #[inline]
603    pub fn get(&self, path_id: usize) -> Result<&Path> {
604        self.paths.get(path_id).ok_or(Error::InvalidState)
605    }
606
607    /// Gets a mutable reference to the path identified by `path_id`. If the
608    /// provided `path_id` does not identify any current `Path`, returns an
609    /// [`InvalidState`].
610    ///
611    /// [`InvalidState`]: enum.Error.html#variant.InvalidState
612    #[inline]
613    pub fn get_mut(&mut self, path_id: usize) -> Result<&mut Path> {
614        self.paths.get_mut(path_id).ok_or(Error::InvalidState)
615    }
616
617    #[inline]
618    /// Gets an immutable reference to the active path with the value of the
619    /// lowest identifier. If there is no active path, returns `None`.
620    pub fn get_active_with_pid(&self) -> Option<(usize, &Path)> {
621        self.paths.iter().find(|(_, p)| p.active())
622    }
623
624    /// Gets an immutable reference to the active path with the lowest
625    /// identifier. If there is no active path, returns an [`InvalidState`].
626    ///
627    /// [`InvalidState`]: enum.Error.html#variant.InvalidState
628    #[inline]
629    pub fn get_active(&self) -> Result<&Path> {
630        self.get_active_with_pid()
631            .map(|(_, p)| p)
632            .ok_or(Error::InvalidState)
633    }
634
635    /// Gets the lowest active path identifier. If there is no active path,
636    /// returns an [`InvalidState`].
637    ///
638    /// [`InvalidState`]: enum.Error.html#variant.InvalidState
639    #[inline]
640    pub fn get_active_path_id(&self) -> Result<usize> {
641        self.get_active_with_pid()
642            .map(|(pid, _)| pid)
643            .ok_or(Error::InvalidState)
644    }
645
646    /// Gets an mutable reference to the active path with the lowest identifier.
647    /// If there is no active path, returns an [`InvalidState`].
648    ///
649    /// [`InvalidState`]: enum.Error.html#variant.InvalidState
650    #[inline]
651    pub fn get_active_mut(&mut self) -> Result<&mut Path> {
652        self.paths
653            .iter_mut()
654            .map(|(_, p)| p)
655            .find(|p| p.active())
656            .ok_or(Error::InvalidState)
657    }
658
659    /// Returns an iterator over all existing paths.
660    #[inline]
661    pub fn iter(&self) -> slab::Iter<Path> {
662        self.paths.iter()
663    }
664
665    /// Returns a mutable iterator over all existing paths.
666    #[inline]
667    pub fn iter_mut(&mut self) -> slab::IterMut<Path> {
668        self.paths.iter_mut()
669    }
670
671    /// Returns the number of existing paths.
672    #[inline]
673    pub fn len(&self) -> usize {
674        self.paths.len()
675    }
676
677    /// Returns the `Path` identifier related to the provided `addrs`.
678    #[inline]
679    pub fn path_id_from_addrs(
680        &self, addrs: &(SocketAddr, SocketAddr),
681    ) -> Option<usize> {
682        self.addrs_to_paths.get(addrs).copied()
683    }
684
685    /// Checks if creating a new path will not exceed the current `self.paths`
686    /// capacity. If yes, this method tries to remove one unused path. If it
687    /// fails to do so, returns [`Done`].
688    ///
689    /// [`Done`]: enum.Error.html#variant.Done
690    fn make_room_for_new_path(&mut self) -> Result<()> {
691        if self.paths.len() < self.max_concurrent_paths {
692            return Ok(());
693        }
694
695        let (pid_to_remove, _) = self
696            .paths
697            .iter()
698            .find(|(_, p)| p.unused())
699            .ok_or(Error::Done)?;
700
701        let path = self.paths.remove(pid_to_remove);
702        self.addrs_to_paths
703            .remove(&(path.local_addr, path.peer_addr));
704
705        self.notify_event(PathEvent::Closed(path.local_addr, path.peer_addr));
706
707        Ok(())
708    }
709
710    /// Records the provided `Path` and returns its assigned identifier.
711    ///
712    /// On success, this method takes care of creating a notification to the
713    /// serving application, if it serves a server-side connection.
714    ///
715    /// If there are already `max_concurrent_paths` currently recorded, this
716    /// method tries to remove an unused `Path` first. If it fails to do so,
717    /// it returns [`Done`].
718    ///
719    /// [`Done`]: enum.Error.html#variant.Done
720    pub fn insert_path(&mut self, path: Path, is_server: bool) -> Result<usize> {
721        self.make_room_for_new_path()?;
722
723        let local_addr = path.local_addr;
724        let peer_addr = path.peer_addr;
725
726        let pid = self.paths.insert(path);
727        self.addrs_to_paths.insert((local_addr, peer_addr), pid);
728
729        // Notifies the application if we are in server mode.
730        if is_server {
731            self.notify_event(PathEvent::New(local_addr, peer_addr));
732        }
733
734        Ok(pid)
735    }
736
737    /// Notifies a path event to the application served by the connection.
738    pub fn notify_event(&mut self, ev: PathEvent) {
739        self.events.push_back(ev);
740    }
741
742    /// Gets the first path event to be notified to the application.
743    pub fn pop_event(&mut self) -> Option<PathEvent> {
744        self.events.pop_front()
745    }
746
747    /// Notifies all failed validations to the application.
748    pub fn notify_failed_validations(&mut self) {
749        let validation_failed = self
750            .paths
751            .iter_mut()
752            .filter(|(_, p)| p.validation_failed() && !p.failure_notified);
753
754        for (_, p) in validation_failed {
755            self.events.push_back(PathEvent::FailedValidation(
756                p.local_addr,
757                p.peer_addr,
758            ));
759
760            p.failure_notified = true;
761        }
762    }
763
764    /// Finds a path candidate to be active and returns its identifier.
765    pub fn find_candidate_path(&self) -> Option<usize> {
766        // TODO: also consider unvalidated paths if there are no more validated.
767        self.paths
768            .iter()
769            .find(|(_, p)| p.usable())
770            .map(|(pid, _)| pid)
771    }
772
773    /// Handles incoming PATH_RESPONSE data.
774    pub fn on_response_received(&mut self, data: [u8; 8]) -> Result<()> {
775        let active_pid = self.get_active_path_id()?;
776
777        let challenge_pending =
778            self.iter_mut().find(|(_, p)| p.has_pending_challenge(data));
779
780        if let Some((pid, p)) = challenge_pending {
781            if p.on_response_received(data) {
782                let local_addr = p.local_addr;
783                let peer_addr = p.peer_addr;
784                let was_migrating = p.migrating;
785
786                p.migrating = false;
787
788                // Notifies the application.
789                self.notify_event(PathEvent::Validated(local_addr, peer_addr));
790
791                // If this path was the candidate for migration, notifies the
792                // application.
793                if pid == active_pid && was_migrating {
794                    self.notify_event(PathEvent::PeerMigrated(
795                        local_addr, peer_addr,
796                    ));
797                }
798            }
799        }
800        Ok(())
801    }
802
803    /// Sets the path with identifier 'path_id' to be active.
804    ///
805    /// There can be exactly one active path on which non-probing packets can be
806    /// sent. If another path is marked as active, it will be superseded by the
807    /// one having `path_id` as identifier.
808    ///
809    /// A server should always ensure that the active path is validated. If it
810    /// is already the case, it notifies the application that the connection
811    /// migrated. Otherwise, it triggers a path validation and defers the
812    /// notification once it is actually validated.
813    pub fn set_active_path(&mut self, path_id: usize) -> Result<()> {
814        let is_server = self.is_server;
815
816        if let Ok(old_active_path) = self.get_active_mut() {
817            old_active_path.active = false;
818        }
819
820        let new_active_path = self.get_mut(path_id)?;
821        new_active_path.active = true;
822
823        if is_server {
824            if new_active_path.validated() {
825                let local_addr = new_active_path.local_addr();
826                let peer_addr = new_active_path.peer_addr();
827
828                self.notify_event(PathEvent::PeerMigrated(local_addr, peer_addr));
829            } else {
830                new_active_path.migrating = true;
831
832                // Requests path validation if needed.
833                if !new_active_path.under_validation() {
834                    new_active_path.request_validation();
835                }
836            }
837        }
838
839        Ok(())
840    }
841}
842
843/// Statistics about the path of a connection.
844///
845/// A connection’s path statistics can be collected using the [`path_stats()`]
846/// method.
847///
848/// [`path_stats()`]: struct.Connection.html#method.path_stats
849#[derive(Clone)]
850pub struct PathStats {
851    /// The local address of the path.
852    pub local_addr: SocketAddr,
853
854    /// The peer address of the path.
855    pub peer_addr: SocketAddr,
856
857    /// The path validation state.
858    pub validation_state: PathState,
859
860    /// Whether the path is marked as active.
861    pub active: bool,
862
863    /// The number of QUIC packets received.
864    pub recv: usize,
865
866    /// The number of QUIC packets sent.
867    pub sent: usize,
868
869    /// The number of QUIC packets that were lost.
870    pub lost: usize,
871
872    /// The number of sent QUIC packets with retransmitted data.
873    pub retrans: usize,
874
875    /// The number of DATAGRAM frames received.
876    pub dgram_recv: usize,
877
878    /// The number of DATAGRAM frames sent.
879    pub dgram_sent: usize,
880
881    /// The estimated round-trip time of the connection.
882    pub rtt: time::Duration,
883
884    /// The minimum round-trip time observed.
885    pub min_rtt: Option<time::Duration>,
886
887    /// The estimated round-trip time variation in samples using a mean
888    /// variation.
889    pub rttvar: time::Duration,
890
891    /// The size of the connection's congestion window in bytes.
892    pub cwnd: usize,
893
894    /// The number of sent bytes.
895    pub sent_bytes: u64,
896
897    /// The number of received bytes.
898    pub recv_bytes: u64,
899
900    /// The number of bytes lost.
901    pub lost_bytes: u64,
902
903    /// The number of stream bytes retransmitted.
904    pub stream_retrans_bytes: u64,
905
906    /// The current PMTU for the connection.
907    pub pmtu: usize,
908
909    /// The most recent data delivery rate estimate in bytes/s.
910    ///
911    /// Note that this value could be inaccurate if the application does not
912    /// respect pacing hints (see [`SendInfo.at`] and [Pacing] for more
913    /// details).
914    ///
915    /// [`SendInfo.at`]: struct.SendInfo.html#structfield.at
916    /// [Pacing]: index.html#pacing
917    pub delivery_rate: u64,
918}
919
920impl std::fmt::Debug for PathStats {
921    #[inline]
922    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
923        write!(
924            f,
925            "local_addr={:?} peer_addr={:?} ",
926            self.local_addr, self.peer_addr,
927        )?;
928        write!(
929            f,
930            "validation_state={:?} active={} ",
931            self.validation_state, self.active,
932        )?;
933        write!(
934            f,
935            "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}",
936            self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd,
937        )?;
938
939        write!(
940            f,
941            " sent_bytes={} recv_bytes={} lost_bytes={}",
942            self.sent_bytes, self.recv_bytes, self.lost_bytes,
943        )?;
944
945        write!(
946            f,
947            " stream_retrans_bytes={} pmtu={} delivery_rate={}",
948            self.stream_retrans_bytes, self.pmtu, self.delivery_rate,
949        )
950    }
951}
952
953#[cfg(test)]
954mod tests {
955    use crate::rand;
956    use crate::MIN_CLIENT_INITIAL_LEN;
957
958    use crate::recovery::RecoveryConfig;
959    use crate::Config;
960
961    use super::*;
962
963    #[test]
964    fn path_validation_limited_mtu() {
965        let client_addr = "127.0.0.1:1234".parse().unwrap();
966        let client_addr_2 = "127.0.0.1:5678".parse().unwrap();
967        let server_addr = "127.0.0.1:4321".parse().unwrap();
968
969        let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
970        let recovery_config = RecoveryConfig::from_config(&config);
971
972        let path = Path::new(
973            client_addr,
974            server_addr,
975            &recovery_config,
976            config.path_challenge_recv_max_queue_len,
977            1200,
978            true,
979        );
980        let mut path_mgr = PathMap::new(path, 2, false, true, 1200);
981
982        let probed_path = Path::new(
983            client_addr_2,
984            server_addr,
985            &recovery_config,
986            config.path_challenge_recv_max_queue_len,
987            1200,
988            false,
989        );
990        path_mgr.insert_path(probed_path, false).unwrap();
991
992        let pid = path_mgr
993            .path_id_from_addrs(&(client_addr_2, server_addr))
994            .unwrap();
995        path_mgr.get_mut(pid).unwrap().request_validation();
996        assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
997        assert!(path_mgr.get_mut(pid).unwrap().probing_required());
998
999        // Fake sending of PathChallenge in a packet of MIN_CLIENT_INITIAL_LEN - 1
1000        // bytes.
1001        let data = rand::rand_u64().to_be_bytes();
1002        path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1003            data,
1004            MIN_CLIENT_INITIAL_LEN - 1,
1005            time::Instant::now(),
1006        );
1007
1008        assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1009        assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1010        assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1011        assert!(!path_mgr.get_mut(pid).unwrap().validated());
1012        assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validating);
1013        assert_eq!(path_mgr.pop_event(), None);
1014
1015        // Receives the response. The path is reachable, but the MTU is not
1016        // validated yet.
1017        path_mgr.on_response_received(data).unwrap();
1018
1019        assert!(path_mgr.get_mut(pid).unwrap().validation_requested());
1020        assert!(path_mgr.get_mut(pid).unwrap().probing_required());
1021        assert!(path_mgr.get_mut(pid).unwrap().under_validation());
1022        assert!(!path_mgr.get_mut(pid).unwrap().validated());
1023        assert_eq!(
1024            path_mgr.get_mut(pid).unwrap().state,
1025            PathState::ValidatingMTU
1026        );
1027        assert_eq!(path_mgr.pop_event(), None);
1028
1029        // Fake sending of PathChallenge in a packet of MIN_CLIENT_INITIAL_LEN
1030        // bytes.
1031        let data = rand::rand_u64().to_be_bytes();
1032        path_mgr.get_mut(pid).unwrap().add_challenge_sent(
1033            data,
1034            MIN_CLIENT_INITIAL_LEN,
1035            time::Instant::now(),
1036        );
1037
1038        path_mgr.on_response_received(data).unwrap();
1039
1040        assert!(!path_mgr.get_mut(pid).unwrap().validation_requested());
1041        assert!(!path_mgr.get_mut(pid).unwrap().probing_required());
1042        assert!(!path_mgr.get_mut(pid).unwrap().under_validation());
1043        assert!(path_mgr.get_mut(pid).unwrap().validated());
1044        assert_eq!(path_mgr.get_mut(pid).unwrap().state, PathState::Validated);
1045        assert_eq!(
1046            path_mgr.pop_event(),
1047            Some(PathEvent::Validated(client_addr_2, server_addr))
1048        );
1049    }
1050
1051    #[test]
1052    fn multiple_probes() {
1053        let client_addr = "127.0.0.1:1234".parse().unwrap();
1054        let server_addr = "127.0.0.1:4321".parse().unwrap();
1055
1056        let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1057        let recovery_config = RecoveryConfig::from_config(&config);
1058
1059        let path = Path::new(
1060            client_addr,
1061            server_addr,
1062            &recovery_config,
1063            config.path_challenge_recv_max_queue_len,
1064            1200,
1065            true,
1066        );
1067        let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1068        let mut server_path = Path::new(
1069            server_addr,
1070            client_addr,
1071            &recovery_config,
1072            config.path_challenge_recv_max_queue_len,
1073            1200,
1074            false,
1075        );
1076
1077        let client_pid = client_path_mgr
1078            .path_id_from_addrs(&(client_addr, server_addr))
1079            .unwrap();
1080
1081        // First probe.
1082        let data = rand::rand_u64().to_be_bytes();
1083
1084        client_path_mgr
1085            .get_mut(client_pid)
1086            .unwrap()
1087            .add_challenge_sent(
1088                data,
1089                MIN_CLIENT_INITIAL_LEN,
1090                time::Instant::now(),
1091            );
1092
1093        // Second probe.
1094        let data_2 = rand::rand_u64().to_be_bytes();
1095
1096        client_path_mgr
1097            .get_mut(client_pid)
1098            .unwrap()
1099            .add_challenge_sent(
1100                data_2,
1101                MIN_CLIENT_INITIAL_LEN,
1102                time::Instant::now(),
1103            );
1104        assert_eq!(
1105            client_path_mgr
1106                .get(client_pid)
1107                .unwrap()
1108                .in_flight_challenges
1109                .len(),
1110            2
1111        );
1112
1113        // If we receive multiple challenges, we can store them.
1114        server_path.on_challenge_received(data);
1115        assert_eq!(server_path.received_challenges.len(), 1);
1116        server_path.on_challenge_received(data_2);
1117        assert_eq!(server_path.received_challenges.len(), 2);
1118
1119        // Response for first probe.
1120        client_path_mgr.on_response_received(data).unwrap();
1121        assert_eq!(
1122            client_path_mgr
1123                .get(client_pid)
1124                .unwrap()
1125                .in_flight_challenges
1126                .len(),
1127            1
1128        );
1129
1130        // Response for second probe.
1131        client_path_mgr.on_response_received(data_2).unwrap();
1132        assert_eq!(
1133            client_path_mgr
1134                .get(client_pid)
1135                .unwrap()
1136                .in_flight_challenges
1137                .len(),
1138            0
1139        );
1140    }
1141
1142    #[test]
1143    fn too_many_probes() {
1144        let client_addr = "127.0.0.1:1234".parse().unwrap();
1145        let server_addr = "127.0.0.1:4321".parse().unwrap();
1146
1147        // Default to DEFAULT_MAX_PATH_CHALLENGE_RX_QUEUE_LEN
1148        let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1149        let recovery_config = RecoveryConfig::from_config(&config);
1150
1151        let path = Path::new(
1152            client_addr,
1153            server_addr,
1154            &recovery_config,
1155            config.path_challenge_recv_max_queue_len,
1156            1200,
1157            true,
1158        );
1159        let mut client_path_mgr = PathMap::new(path, 2, false, false, 1200);
1160        let mut server_path = Path::new(
1161            server_addr,
1162            client_addr,
1163            &recovery_config,
1164            config.path_challenge_recv_max_queue_len,
1165            1200,
1166            false,
1167        );
1168
1169        let client_pid = client_path_mgr
1170            .path_id_from_addrs(&(client_addr, server_addr))
1171            .unwrap();
1172
1173        // First probe.
1174        let data = rand::rand_u64().to_be_bytes();
1175
1176        client_path_mgr
1177            .get_mut(client_pid)
1178            .unwrap()
1179            .add_challenge_sent(
1180                data,
1181                MIN_CLIENT_INITIAL_LEN,
1182                time::Instant::now(),
1183            );
1184
1185        // Second probe.
1186        let data_2 = rand::rand_u64().to_be_bytes();
1187
1188        client_path_mgr
1189            .get_mut(client_pid)
1190            .unwrap()
1191            .add_challenge_sent(
1192                data_2,
1193                MIN_CLIENT_INITIAL_LEN,
1194                time::Instant::now(),
1195            );
1196        assert_eq!(
1197            client_path_mgr
1198                .get(client_pid)
1199                .unwrap()
1200                .in_flight_challenges
1201                .len(),
1202            2
1203        );
1204
1205        // Third probe.
1206        let data_3 = rand::rand_u64().to_be_bytes();
1207
1208        client_path_mgr
1209            .get_mut(client_pid)
1210            .unwrap()
1211            .add_challenge_sent(
1212                data_3,
1213                MIN_CLIENT_INITIAL_LEN,
1214                time::Instant::now(),
1215            );
1216        assert_eq!(
1217            client_path_mgr
1218                .get(client_pid)
1219                .unwrap()
1220                .in_flight_challenges
1221                .len(),
1222            3
1223        );
1224
1225        // Fourth probe.
1226        let data_4 = rand::rand_u64().to_be_bytes();
1227
1228        client_path_mgr
1229            .get_mut(client_pid)
1230            .unwrap()
1231            .add_challenge_sent(
1232                data_4,
1233                MIN_CLIENT_INITIAL_LEN,
1234                time::Instant::now(),
1235            );
1236        assert_eq!(
1237            client_path_mgr
1238                .get(client_pid)
1239                .unwrap()
1240                .in_flight_challenges
1241                .len(),
1242            4
1243        );
1244
1245        // If we receive multiple challenges, we can store them up to our queue
1246        // size.
1247        server_path.on_challenge_received(data);
1248        assert_eq!(server_path.received_challenges.len(), 1);
1249        server_path.on_challenge_received(data_2);
1250        assert_eq!(server_path.received_challenges.len(), 2);
1251        server_path.on_challenge_received(data_3);
1252        assert_eq!(server_path.received_challenges.len(), 3);
1253        server_path.on_challenge_received(data_4);
1254        assert_eq!(server_path.received_challenges.len(), 3);
1255
1256        // Response for first probe.
1257        client_path_mgr.on_response_received(data).unwrap();
1258        assert_eq!(
1259            client_path_mgr
1260                .get(client_pid)
1261                .unwrap()
1262                .in_flight_challenges
1263                .len(),
1264            3
1265        );
1266
1267        // Response for second probe.
1268        client_path_mgr.on_response_received(data_2).unwrap();
1269        assert_eq!(
1270            client_path_mgr
1271                .get(client_pid)
1272                .unwrap()
1273                .in_flight_challenges
1274                .len(),
1275            2
1276        );
1277
1278        // Response for third probe.
1279        client_path_mgr.on_response_received(data_3).unwrap();
1280        assert_eq!(
1281            client_path_mgr
1282                .get(client_pid)
1283                .unwrap()
1284                .in_flight_challenges
1285                .len(),
1286            1
1287        );
1288
1289        // There will never be a response for fourth probe...
1290    }
1291}