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