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 crate::Error; 28 use crate::Result; 29 30 use crate::frame; 31 use crate::packet::ConnectionId; 32 33 use std::collections::VecDeque; 34 35 /// A structure holding a `ConnectionId` and all its related metadata. 36 #[derive(Debug, Default)] 37 pub struct ConnectionIdEntry { 38 /// The Connection ID. 39 pub cid: ConnectionId<'static>, 40 41 /// Its associated sequence number. 42 pub seq: u64, 43 44 /// Its associated reset token. Initial CIDs may not have any reset token. 45 pub reset_token: Option<u128>, 46 47 /// The path identifier using this CID, if any. 48 pub path_id: Option<usize>, 49 } 50 51 #[derive(Default)] 52 struct BoundedNonEmptyConnectionIdVecDeque { 53 /// The inner `VecDeque`. 54 inner: VecDeque<ConnectionIdEntry>, 55 56 /// The maximum number of elements that the `VecDeque` can have. 57 capacity: usize, 58 } 59 60 impl BoundedNonEmptyConnectionIdVecDeque { 61 /// Creates a `VecDeque` bounded by `capacity` and inserts 62 /// `initial_entry` in it. new(capacity: usize, initial_entry: ConnectionIdEntry) -> Self63 fn new(capacity: usize, initial_entry: ConnectionIdEntry) -> Self { 64 let mut inner = VecDeque::with_capacity(1); 65 inner.push_back(initial_entry); 66 Self { inner, capacity } 67 } 68 69 /// Updates the maximum capacity of the inner `VecDeque` to `new_capacity`. 70 /// Does nothing if `new_capacity` is lower or equal to the current 71 /// `capacity`. resize(&mut self, new_capacity: usize)72 fn resize(&mut self, new_capacity: usize) { 73 if new_capacity > self.capacity { 74 self.capacity = new_capacity; 75 } 76 } 77 78 /// Returns the oldest inserted entry still present in the `VecDeque`. get_oldest(&self) -> &ConnectionIdEntry79 fn get_oldest(&self) -> &ConnectionIdEntry { 80 self.inner.front().expect("vecdeque is empty") 81 } 82 83 /// Gets a immutable reference to the entry having the provided `seq`. get(&self, seq: u64) -> Option<&ConnectionIdEntry>84 fn get(&self, seq: u64) -> Option<&ConnectionIdEntry> { 85 // We need to iterate over the whole map to find the key. 86 self.inner.iter().find(|e| e.seq == seq) 87 } 88 89 /// Gets a mutable reference to the entry having the provided `seq`. get_mut(&mut self, seq: u64) -> Option<&mut ConnectionIdEntry>90 fn get_mut(&mut self, seq: u64) -> Option<&mut ConnectionIdEntry> { 91 // We need to iterate over the whole map to find the key. 92 self.inner.iter_mut().find(|e| e.seq == seq) 93 } 94 95 /// Returns an iterator over the entries in the `VecDeque`. iter(&self) -> impl Iterator<Item = &ConnectionIdEntry>96 fn iter(&self) -> impl Iterator<Item = &ConnectionIdEntry> { 97 self.inner.iter() 98 } 99 100 /// Returns the number of elements in the `VecDeque`. len(&self) -> usize101 fn len(&self) -> usize { 102 self.inner.len() 103 } 104 105 /// Inserts the provided entry in the `VecDeque`. 106 /// 107 /// This method ensures the unicity of the `seq` associated to an entry. If 108 /// an entry has the same `seq` than `e`, this method updates the entry in 109 /// the `VecDeque` and the number of stored elements remains unchanged. 110 /// 111 /// If inserting a new element would exceed the collection's capacity, this 112 /// method raises an [`IdLimit`]. 113 /// 114 /// [`IdLimit`]: enum.Error.html#IdLimit insert(&mut self, e: ConnectionIdEntry) -> Result<()>115 fn insert(&mut self, e: ConnectionIdEntry) -> Result<()> { 116 // Ensure we don't have duplicates. 117 match self.get_mut(e.seq) { 118 Some(oe) => *oe = e, 119 None => { 120 if self.inner.len() == self.capacity { 121 return Err(Error::IdLimit); 122 } 123 self.inner.push_back(e); 124 }, 125 }; 126 Ok(()) 127 } 128 129 /// Removes all the elements in the collection and inserts the provided one. clear_and_insert(&mut self, e: ConnectionIdEntry)130 fn clear_and_insert(&mut self, e: ConnectionIdEntry) { 131 self.inner.clear(); 132 self.inner.push_back(e); 133 } 134 135 /// Removes the element in the collection having the provided `seq`. 136 /// 137 /// If this method is called when there remains a single element in the 138 /// collection, this method raises an [`OutOfIdentifiers`]. 139 /// 140 /// Returns `Some` if the element was in the collection and removed, or 141 /// `None` if it was not and nothing was modified. 142 /// 143 /// [`OutOfIdentifiers`]: enum.Error.html#OutOfIdentifiers remove(&mut self, seq: u64) -> Result<Option<ConnectionIdEntry>>144 fn remove(&mut self, seq: u64) -> Result<Option<ConnectionIdEntry>> { 145 if self.inner.len() <= 1 { 146 return Err(Error::OutOfIdentifiers); 147 } 148 149 Ok(self 150 .inner 151 .iter() 152 .position(|e| e.seq == seq) 153 .and_then(|index| self.inner.remove(index))) 154 } 155 156 /// Removes all the elements in the collection whose `seq` is lower than the 157 /// provided one, and inserts `e` in the collection. 158 /// 159 /// For each removed element `re`, `f(re)` is called. 160 /// 161 /// If the inserted element has a `seq` lower than the one used to remove 162 /// elements, it raises an [`OutOfIdentifiers`]. 163 /// 164 /// [`OutOfIdentifiers`]: enum.Error.html#OutOfIdentifiers remove_lower_than_and_insert<F>( &mut self, seq: u64, e: ConnectionIdEntry, mut f: F, ) -> Result<()> where F: FnMut(&ConnectionIdEntry),165 fn remove_lower_than_and_insert<F>( 166 &mut self, seq: u64, e: ConnectionIdEntry, mut f: F, 167 ) -> Result<()> 168 where 169 F: FnMut(&ConnectionIdEntry), 170 { 171 // The insert entry MUST have a sequence higher or equal to the ones 172 // being retired. 173 if e.seq < seq { 174 return Err(Error::OutOfIdentifiers); 175 } 176 177 // To avoid exceeding the capacity of the inner `VecDeque`, we first 178 // remove the elements and then insert the new one. 179 self.inner.retain(|e| { 180 if e.seq < seq { 181 f(e); 182 false 183 } else { 184 true 185 } 186 }); 187 188 // Note that if no element has been retired and the `VecDeque` reaches 189 // its capacity limit, this will raise an `IdLimit`. 190 self.insert(e) 191 } 192 } 193 194 /// An iterator over QUIC Connection IDs. 195 pub struct ConnectionIdIter { 196 cids: VecDeque<ConnectionId<'static>>, 197 } 198 199 impl Iterator for ConnectionIdIter { 200 type Item = ConnectionId<'static>; 201 202 #[inline] next(&mut self) -> Option<Self::Item>203 fn next(&mut self) -> Option<Self::Item> { 204 self.cids.pop_front() 205 } 206 } 207 208 impl ExactSizeIterator for ConnectionIdIter { 209 #[inline] len(&self) -> usize210 fn len(&self) -> usize { 211 self.cids.len() 212 } 213 } 214 215 #[derive(Default)] 216 pub struct ConnectionIdentifiers { 217 /// All the Destination Connection IDs provided by our peer. 218 dcids: BoundedNonEmptyConnectionIdVecDeque, 219 220 /// All the Source Connection IDs we provide to our peer. 221 scids: BoundedNonEmptyConnectionIdVecDeque, 222 223 /// Source Connection IDs that should be announced to the peer. 224 advertise_new_scid_seqs: VecDeque<u64>, 225 226 /// Retired Destination Connection IDs that should be announced to the peer. 227 retire_dcid_seqs: VecDeque<u64>, 228 229 /// Retired Source Connection IDs that should be notified to the 230 /// application. 231 retired_scids: VecDeque<ConnectionId<'static>>, 232 233 /// Largest "Retire Prior To" we received from the peer. 234 largest_peer_retire_prior_to: u64, 235 236 /// Largest sequence number we received from the peer. 237 largest_destination_seq: u64, 238 239 /// Next sequence number to use. 240 next_scid_seq: u64, 241 242 /// "Retire Prior To" value to advertise to the peer. 243 retire_prior_to: u64, 244 245 /// The maximum number of source Connection IDs our peer allows us. 246 source_conn_id_limit: usize, 247 248 /// Does the host use zero-length source Connection ID. 249 zero_length_scid: bool, 250 251 /// Does the host use zero-length destination Connection ID. 252 zero_length_dcid: bool, 253 } 254 255 impl ConnectionIdentifiers { 256 /// Creates a new `ConnectionIdentifiers` with the specified destination 257 /// connection ID limit and initial source Connection ID. The destination 258 /// Connection ID is set to the empty one. new( mut destination_conn_id_limit: usize, initial_scid: &ConnectionId, initial_path_id: usize, reset_token: Option<u128>, ) -> ConnectionIdentifiers259 pub fn new( 260 mut destination_conn_id_limit: usize, initial_scid: &ConnectionId, 261 initial_path_id: usize, reset_token: Option<u128>, 262 ) -> ConnectionIdentifiers { 263 // It must be at least 2. 264 if destination_conn_id_limit < 2 { 265 destination_conn_id_limit = 2; 266 } 267 268 // Initially, the limit of active source connection IDs is 2. 269 let source_conn_id_limit = 2; 270 271 // Record the zero-length SCID status. 272 let zero_length_scid = initial_scid.is_empty(); 273 274 let initial_scid = 275 ConnectionId::from_ref(initial_scid.as_ref()).into_owned(); 276 277 // We need to track up to (2 * source_conn_id_limit - 1) source 278 // Connection IDs when the host wants to force their renewal. 279 let scids = BoundedNonEmptyConnectionIdVecDeque::new( 280 2 * source_conn_id_limit - 1, 281 ConnectionIdEntry { 282 cid: initial_scid, 283 seq: 0, 284 reset_token, 285 path_id: Some(initial_path_id), 286 }, 287 ); 288 289 let dcids = BoundedNonEmptyConnectionIdVecDeque::new( 290 destination_conn_id_limit, 291 ConnectionIdEntry { 292 cid: ConnectionId::default(), 293 seq: 0, 294 reset_token: None, 295 path_id: Some(initial_path_id), 296 }, 297 ); 298 299 // Because we already inserted the initial SCID. 300 let next_scid_seq = 1; 301 ConnectionIdentifiers { 302 scids, 303 dcids, 304 retired_scids: VecDeque::new(), 305 next_scid_seq, 306 source_conn_id_limit, 307 zero_length_scid, 308 ..Default::default() 309 } 310 } 311 312 /// Sets the maximum number of source connection IDs our peer allows us. set_source_conn_id_limit(&mut self, v: u64)313 pub fn set_source_conn_id_limit(&mut self, v: u64) { 314 // Bound conn id limit so our scids queue sizing is valid. 315 let v = std::cmp::min(v, (usize::MAX / 2) as u64) as usize; 316 317 // It must be at least 2. 318 if v >= 2 { 319 self.source_conn_id_limit = v; 320 // We need to track up to (2 * source_conn_id_limit - 1) source 321 // Connection IDs when the host wants to force their renewal. 322 self.scids.resize(2 * v - 1); 323 } 324 } 325 326 /// Gets the destination Connection ID associated with the provided sequence 327 /// number. 328 #[inline] get_dcid(&self, seq_num: u64) -> Result<&ConnectionIdEntry>329 pub fn get_dcid(&self, seq_num: u64) -> Result<&ConnectionIdEntry> { 330 self.dcids.get(seq_num).ok_or(Error::InvalidState) 331 } 332 333 /// Gets the source Connection ID associated with the provided sequence 334 /// number. 335 #[inline] get_scid(&self, seq_num: u64) -> Result<&ConnectionIdEntry>336 pub fn get_scid(&self, seq_num: u64) -> Result<&ConnectionIdEntry> { 337 self.scids.get(seq_num).ok_or(Error::InvalidState) 338 } 339 340 /// Adds a new source identifier, and indicates whether it should be 341 /// advertised through a `NEW_CONNECTION_ID` frame or not. 342 /// 343 /// At any time, the peer cannot have more Destination Connection IDs than 344 /// the maximum number of active Connection IDs it negotiated. In such case 345 /// (i.e., when [`active_source_cids()`] - `peer_active_conn_id_limit` = 0, 346 /// if the caller agrees to request the removal of previous connection IDs, 347 /// it sets the `retire_if_needed` parameter. Otherwise, an [`IdLimit`] is 348 /// returned. 349 /// 350 /// Note that setting `retire_if_needed` does not prevent this function from 351 /// returning an [`IdLimit`] in the case the caller wants to retire still 352 /// unannounced Connection IDs. 353 /// 354 /// When setting the initial Source Connection ID, the `reset_token` may be 355 /// `None`. However, other Source CIDs must have an associated 356 /// `reset_token`. Providing `None` as the `reset_token` for non-initial 357 /// SCIDs raises an [`InvalidState`]. 358 /// 359 /// In the case the provided `cid` is already present, it does not add it. 360 /// If the provided `reset_token` differs from the one already registered, 361 /// returns an `InvalidState`. 362 /// 363 /// Returns the sequence number associated to that new source identifier. 364 /// 365 /// [`active_source_cids()`]: struct.ConnectionIdentifiers.html#method.active_source_cids 366 /// [`InvalidState`]: enum.Error.html#InvalidState 367 /// [`IdLimit`]: enum.Error.html#IdLimit new_scid( &mut self, cid: ConnectionId<'static>, reset_token: Option<u128>, advertise: bool, path_id: Option<usize>, retire_if_needed: bool, ) -> Result<u64>368 pub fn new_scid( 369 &mut self, cid: ConnectionId<'static>, reset_token: Option<u128>, 370 advertise: bool, path_id: Option<usize>, retire_if_needed: bool, 371 ) -> Result<u64> { 372 if self.zero_length_scid { 373 return Err(Error::InvalidState); 374 } 375 376 // Check whether the number of source Connection IDs does not exceed the 377 // limit. If the host agrees to retire old CIDs, it can store up to 378 // (2 * source_active_conn_id - 1) source CIDs. This limit is enforced 379 // when calling `self.scids.insert()`. 380 if self.scids.len() >= self.source_conn_id_limit { 381 if !retire_if_needed { 382 return Err(Error::IdLimit); 383 } 384 385 // We need to retire the lowest one. 386 self.retire_prior_to = self.lowest_usable_scid_seq()? + 1; 387 } 388 389 let seq = self.next_scid_seq; 390 391 if reset_token.is_none() && seq != 0 { 392 return Err(Error::InvalidState); 393 } 394 395 // Check first that the SCID has not been inserted before. 396 if let Some(e) = self.scids.iter().find(|e| e.cid == cid) { 397 if e.reset_token != reset_token { 398 return Err(Error::InvalidState); 399 } 400 return Ok(e.seq); 401 } 402 403 self.scids.insert(ConnectionIdEntry { 404 cid, 405 seq, 406 reset_token, 407 path_id, 408 })?; 409 self.next_scid_seq += 1; 410 411 self.mark_advertise_new_scid_seq(seq, advertise); 412 413 Ok(seq) 414 } 415 416 /// Sets the initial destination identifier. set_initial_dcid( &mut self, cid: ConnectionId<'static>, reset_token: Option<u128>, path_id: Option<usize>, )417 pub fn set_initial_dcid( 418 &mut self, cid: ConnectionId<'static>, reset_token: Option<u128>, 419 path_id: Option<usize>, 420 ) { 421 // Record the zero-length DCID status. 422 self.zero_length_dcid = cid.is_empty(); 423 self.dcids.clear_and_insert(ConnectionIdEntry { 424 cid, 425 seq: 0, 426 reset_token, 427 path_id, 428 }); 429 } 430 431 /// Adds a new Destination Connection ID (originating from a 432 /// NEW_CONNECTION_ID frame) and process all its related metadata. 433 /// 434 /// Returns an error if the provided Connection ID or its metadata are 435 /// invalid. 436 /// 437 /// Returns a list of tuples (DCID sequence number, Path ID), containing the 438 /// sequence number of retired DCIDs that were linked to their respective 439 /// Path ID. new_dcid( &mut self, cid: ConnectionId<'static>, seq: u64, reset_token: u128, retire_prior_to: u64, ) -> Result<Vec<(u64, usize)>>440 pub fn new_dcid( 441 &mut self, cid: ConnectionId<'static>, seq: u64, reset_token: u128, 442 retire_prior_to: u64, 443 ) -> Result<Vec<(u64, usize)>> { 444 if self.zero_length_dcid { 445 return Err(Error::InvalidState); 446 } 447 448 let mut retired_path_ids = Vec::new(); 449 // If an endpoint receives a NEW_CONNECTION_ID frame that repeats a 450 // previously issued connection ID with a different Stateless Reset 451 // Token field value or a different Sequence Number field value, or if a 452 // sequence number is used for different connection IDs, the endpoint 453 // MAY treat that receipt as a connection error of type 454 // PROTOCOL_VIOLATION. 455 if let Some(e) = self.dcids.iter().find(|e| e.cid == cid || e.seq == seq) 456 { 457 if e.cid != cid || e.seq != seq || e.reset_token != Some(reset_token) 458 { 459 return Err(Error::InvalidFrame); 460 } 461 // The identifier is already there, nothing to do. 462 return Ok(retired_path_ids); 463 } 464 465 // The value in the Retire Prior To field MUST be less than or equal to 466 // the value in the Sequence Number field. Receiving a value in the 467 // Retire Prior To field that is greater than that in the Sequence 468 // Number field MUST be treated as a connection error of type 469 // FRAME_ENCODING_ERROR. 470 if retire_prior_to > seq { 471 return Err(Error::InvalidFrame); 472 } 473 474 // An endpoint that receives a NEW_CONNECTION_ID frame with a sequence 475 // number smaller than the Retire Prior To field of a previously 476 // received NEW_CONNECTION_ID frame MUST send a corresponding 477 // RETIRE_CONNECTION_ID frame that retires the newly received connection 478 // ID, unless it has already done so for that sequence number. 479 if seq < self.largest_peer_retire_prior_to && 480 !self.retire_dcid_seqs.contains(&seq) 481 { 482 self.retire_dcid_seqs.push_back(seq); 483 return Ok(retired_path_ids); 484 } 485 486 if seq > self.largest_destination_seq { 487 self.largest_destination_seq = seq; 488 } 489 490 let new_entry = ConnectionIdEntry { 491 cid: cid.clone(), 492 seq, 493 reset_token: Some(reset_token), 494 path_id: None, 495 }; 496 497 // A receiver MUST ignore any Retire Prior To fields that do not 498 // increase the largest received Retire Prior To value. 499 // 500 // After processing a NEW_CONNECTION_ID frame and adding and retiring 501 // active connection IDs, if the number of active connection IDs exceeds 502 // the value advertised in its active_connection_id_limit transport 503 // parameter, an endpoint MUST close the connection with an error of type 504 // CONNECTION_ID_LIMIT_ERROR. 505 if retire_prior_to > self.largest_peer_retire_prior_to { 506 let retired = &mut self.retire_dcid_seqs; 507 self.dcids.remove_lower_than_and_insert( 508 retire_prior_to, 509 new_entry, 510 |e| { 511 retired.push_back(e.seq); 512 513 if let Some(pid) = e.path_id { 514 retired_path_ids.push((e.seq, pid)); 515 } 516 }, 517 )?; 518 self.largest_peer_retire_prior_to = retire_prior_to; 519 } else { 520 self.dcids.insert(new_entry)?; 521 } 522 523 Ok(retired_path_ids) 524 } 525 526 /// Retires the Source Connection ID having the provided sequence number. 527 /// 528 /// In case the retired Connection ID is the same as the one used by the 529 /// packet requesting the retiring, or if the retired sequence number is 530 /// greater than any previously advertised sequence numbers, it returns an 531 /// [`InvalidState`]. 532 /// 533 /// Returns the path ID that was associated to the retired CID, if any. 534 /// 535 /// [`InvalidState`]: enum.Error.html#InvalidState retire_scid( &mut self, seq: u64, pkt_dcid: &ConnectionId, ) -> Result<Option<usize>>536 pub fn retire_scid( 537 &mut self, seq: u64, pkt_dcid: &ConnectionId, 538 ) -> Result<Option<usize>> { 539 if seq >= self.next_scid_seq { 540 return Err(Error::InvalidState); 541 } 542 543 let pid = if let Some(e) = self.scids.remove(seq)? { 544 if e.cid == *pkt_dcid { 545 return Err(Error::InvalidState); 546 } 547 548 // Notifies the application. 549 self.retired_scids.push_back(e.cid); 550 551 // Retiring this SCID may increase the retire prior to. 552 let lowest_scid_seq = self.lowest_usable_scid_seq()?; 553 self.retire_prior_to = lowest_scid_seq; 554 555 e.path_id 556 } else { 557 None 558 }; 559 560 Ok(pid) 561 } 562 563 /// Retires the Destination Connection ID having the provided sequence 564 /// number. 565 /// 566 /// If the caller tries to retire the last destination Connection ID, this 567 /// method triggers an [`OutOfIdentifiers`]. 568 /// 569 /// If the caller tries to retire a non-existing Destination Connection 570 /// ID sequence number, this method returns an [`InvalidState`]. 571 /// 572 /// Returns the path ID that was associated to the retired CID, if any. 573 /// 574 /// [`OutOfIdentifiers`]: enum.Error.html#OutOfIdentifiers 575 /// [`InvalidState`]: enum.Error.html#InvalidState retire_dcid(&mut self, seq: u64) -> Result<Option<usize>>576 pub fn retire_dcid(&mut self, seq: u64) -> Result<Option<usize>> { 577 if self.zero_length_dcid { 578 return Err(Error::InvalidState); 579 } 580 581 let e = self.dcids.remove(seq)?.ok_or(Error::InvalidState)?; 582 583 self.retire_dcid_seqs.push_back(seq); 584 585 Ok(e.path_id) 586 } 587 588 /// Updates the Source Connection ID entry with the provided sequence number 589 /// to indicate that it is now linked to the provided path ID. link_scid_to_path_id( &mut self, dcid_seq: u64, path_id: usize, ) -> Result<()>590 pub fn link_scid_to_path_id( 591 &mut self, dcid_seq: u64, path_id: usize, 592 ) -> Result<()> { 593 let e = self.scids.get_mut(dcid_seq).ok_or(Error::InvalidState)?; 594 e.path_id = Some(path_id); 595 Ok(()) 596 } 597 598 /// Updates the Destination Connection ID entry with the provided sequence 599 /// number to indicate that it is now linked to the provided path ID. link_dcid_to_path_id( &mut self, dcid_seq: u64, path_id: usize, ) -> Result<()>600 pub fn link_dcid_to_path_id( 601 &mut self, dcid_seq: u64, path_id: usize, 602 ) -> Result<()> { 603 let e = self.dcids.get_mut(dcid_seq).ok_or(Error::InvalidState)?; 604 e.path_id = Some(path_id); 605 Ok(()) 606 } 607 608 /// Gets the minimum Source Connection ID sequence number whose removal has 609 /// not been requested yet. 610 #[inline] lowest_usable_scid_seq(&self) -> Result<u64>611 pub fn lowest_usable_scid_seq(&self) -> Result<u64> { 612 self.scids 613 .iter() 614 .filter_map(|e| { 615 if e.seq >= self.retire_prior_to { 616 Some(e.seq) 617 } else { 618 None 619 } 620 }) 621 .min() 622 .ok_or(Error::InvalidState) 623 } 624 625 /// Gets the lowest Destination Connection ID sequence number that is not 626 /// associated to a path. 627 #[inline] lowest_available_dcid_seq(&self) -> Option<u64>628 pub fn lowest_available_dcid_seq(&self) -> Option<u64> { 629 self.dcids 630 .iter() 631 .filter_map(|e| { 632 if e.path_id.is_none() { 633 Some(e.seq) 634 } else { 635 None 636 } 637 }) 638 .min() 639 } 640 641 /// Finds the sequence number of the Source Connection ID having the 642 /// provided value and the identifier of the path using it, if any. 643 #[inline] find_scid_seq( &self, scid: &ConnectionId, ) -> Option<(u64, Option<usize>)>644 pub fn find_scid_seq( 645 &self, scid: &ConnectionId, 646 ) -> Option<(u64, Option<usize>)> { 647 self.scids.iter().find_map(|e| { 648 if e.cid == *scid { 649 Some((e.seq, e.path_id)) 650 } else { 651 None 652 } 653 }) 654 } 655 656 /// Returns the number of Source Connection IDs that have not been 657 /// assigned to a path yet. 658 /// 659 /// Note that this function is only meaningful if the host uses non-zero 660 /// length Source Connection IDs. 661 #[inline] available_scids(&self) -> usize662 pub fn available_scids(&self) -> usize { 663 self.scids.iter().filter(|e| e.path_id.is_none()).count() 664 } 665 666 /// Returns the number of Destination Connection IDs that have not been 667 /// assigned to a path yet. 668 /// 669 /// Note that this function returns 0 if the host uses zero length 670 /// Destination Connection IDs. 671 #[inline] available_dcids(&self) -> usize672 pub fn available_dcids(&self) -> usize { 673 if self.zero_length_dcid() { 674 return 0; 675 } 676 self.dcids.iter().filter(|e| e.path_id.is_none()).count() 677 } 678 679 /// Returns the oldest active source Connection ID of this connection. 680 #[inline] oldest_scid(&self) -> &ConnectionIdEntry681 pub fn oldest_scid(&self) -> &ConnectionIdEntry { 682 self.scids.get_oldest() 683 } 684 685 /// Returns the oldest known active destination Connection ID of this 686 /// connection. 687 /// 688 /// Note that due to e.g., reordering at reception side, the oldest known 689 /// active destination Connection ID is not necessarily the one having the 690 /// lowest sequence. 691 #[inline] oldest_dcid(&self) -> &ConnectionIdEntry692 pub fn oldest_dcid(&self) -> &ConnectionIdEntry { 693 self.dcids.get_oldest() 694 } 695 696 /// Adds or remove the source Connection ID sequence number from the 697 /// source Connection ID set that need to be advertised to the peer through 698 /// NEW_CONNECTION_ID frames. 699 #[inline] mark_advertise_new_scid_seq( &mut self, scid_seq: u64, advertise: bool, )700 pub fn mark_advertise_new_scid_seq( 701 &mut self, scid_seq: u64, advertise: bool, 702 ) { 703 if advertise { 704 self.advertise_new_scid_seqs.push_back(scid_seq); 705 } else if let Some(index) = self 706 .advertise_new_scid_seqs 707 .iter() 708 .position(|s| *s == scid_seq) 709 { 710 self.advertise_new_scid_seqs.remove(index); 711 } 712 } 713 714 /// Adds or remove the destination Connection ID sequence number from the 715 /// retired destination Connection ID set that need to be advertised to the 716 /// peer through RETIRE_CONNECTION_ID frames. 717 #[inline] mark_retire_dcid_seq(&mut self, dcid_seq: u64, retire: bool)718 pub fn mark_retire_dcid_seq(&mut self, dcid_seq: u64, retire: bool) { 719 if retire { 720 self.retire_dcid_seqs.push_back(dcid_seq); 721 } else if let Some(index) = 722 self.retire_dcid_seqs.iter().position(|s| *s == dcid_seq) 723 { 724 self.retire_dcid_seqs.remove(index); 725 } 726 } 727 728 /// Gets a source Connection ID's sequence number requiring advertising it 729 /// to the peer through NEW_CONNECTION_ID frame, if any. 730 /// 731 /// If `Some`, it always returns the same value until it has been removed 732 /// using `mark_advertise_new_scid_seq`. 733 #[inline] next_advertise_new_scid_seq(&self) -> Option<u64>734 pub fn next_advertise_new_scid_seq(&self) -> Option<u64> { 735 self.advertise_new_scid_seqs.front().copied() 736 } 737 738 /// Gets a destination Connection IDs's sequence number that need to send 739 /// RETIRE_CONNECTION_ID frames. 740 /// 741 /// If `Some`, it always returns the same value until it has been removed 742 /// using `mark_retire_dcid_seq`. 743 #[inline] next_retire_dcid_seq(&self) -> Option<u64>744 pub fn next_retire_dcid_seq(&self) -> Option<u64> { 745 self.retire_dcid_seqs.front().copied() 746 } 747 748 /// Returns true if there are new source Connection IDs to advertise. 749 #[inline] has_new_scids(&self) -> bool750 pub fn has_new_scids(&self) -> bool { 751 !self.advertise_new_scid_seqs.is_empty() 752 } 753 754 /// Returns true if there are retired destination Connection IDs to\ 755 /// advertise. 756 #[inline] has_retire_dcids(&self) -> bool757 pub fn has_retire_dcids(&self) -> bool { 758 !self.retire_dcid_seqs.is_empty() 759 } 760 761 /// Returns whether zero-length source CIDs are used. 762 #[inline] zero_length_scid(&self) -> bool763 pub fn zero_length_scid(&self) -> bool { 764 self.zero_length_scid 765 } 766 767 /// Returns whether zero-length destination CIDs are used. 768 #[inline] zero_length_dcid(&self) -> bool769 pub fn zero_length_dcid(&self) -> bool { 770 self.zero_length_dcid 771 } 772 773 /// Gets the NEW_CONNECTION_ID frame related to the source connection ID 774 /// with sequence `seq_num`. get_new_connection_id_frame_for( &self, seq_num: u64, ) -> Result<frame::Frame>775 pub fn get_new_connection_id_frame_for( 776 &self, seq_num: u64, 777 ) -> Result<frame::Frame> { 778 let e = self.scids.get(seq_num).ok_or(Error::InvalidState)?; 779 Ok(frame::Frame::NewConnectionId { 780 seq_num, 781 retire_prior_to: self.retire_prior_to, 782 conn_id: e.cid.to_vec(), 783 reset_token: e.reset_token.ok_or(Error::InvalidState)?.to_be_bytes(), 784 }) 785 } 786 787 /// Returns the number of source Connection IDs that are active. This is 788 /// only meaningful if the host uses non-zero length Source Connection IDs. 789 #[inline] active_source_cids(&self) -> usize790 pub fn active_source_cids(&self) -> usize { 791 self.scids.len() 792 } 793 pop_retired_scid(&mut self) -> Option<ConnectionId<'static>>794 pub fn pop_retired_scid(&mut self) -> Option<ConnectionId<'static>> { 795 self.retired_scids.pop_front() 796 } 797 } 798 799 #[cfg(test)] 800 mod tests { 801 use super::*; 802 use crate::testing::create_cid_and_reset_token; 803 804 #[test] ids_new_scids()805 fn ids_new_scids() { 806 let (scid, _) = create_cid_and_reset_token(16); 807 let (dcid, _) = create_cid_and_reset_token(16); 808 809 let mut ids = ConnectionIdentifiers::new(2, &scid, 0, None); 810 ids.set_source_conn_id_limit(3); 811 ids.set_initial_dcid(dcid, None, Some(0)); 812 813 assert_eq!(ids.available_dcids(), 0); 814 assert_eq!(ids.available_scids(), 0); 815 assert_eq!(ids.has_new_scids(), false); 816 assert_eq!(ids.next_advertise_new_scid_seq(), None); 817 818 let (scid2, rt2) = create_cid_and_reset_token(16); 819 820 assert_eq!(ids.new_scid(scid2, Some(rt2), true, None, false), Ok(1)); 821 assert_eq!(ids.available_dcids(), 0); 822 assert_eq!(ids.available_scids(), 1); 823 assert_eq!(ids.has_new_scids(), true); 824 assert_eq!(ids.next_advertise_new_scid_seq(), Some(1)); 825 826 let (scid3, rt3) = create_cid_and_reset_token(16); 827 828 assert_eq!(ids.new_scid(scid3, Some(rt3), true, None, false), Ok(2)); 829 assert_eq!(ids.available_dcids(), 0); 830 assert_eq!(ids.available_scids(), 2); 831 assert_eq!(ids.has_new_scids(), true); 832 assert_eq!(ids.next_advertise_new_scid_seq(), Some(1)); 833 834 // If now we give another CID, it reports an error since it exceeds the 835 // limit of active CIDs. 836 let (scid4, rt4) = create_cid_and_reset_token(16); 837 838 assert_eq!( 839 ids.new_scid(scid4, Some(rt4), true, None, false), 840 Err(Error::IdLimit), 841 ); 842 assert_eq!(ids.available_dcids(), 0); 843 assert_eq!(ids.available_scids(), 2); 844 assert_eq!(ids.has_new_scids(), true); 845 assert_eq!(ids.next_advertise_new_scid_seq(), Some(1)); 846 847 // Assume we sent one of them. 848 ids.mark_advertise_new_scid_seq(1, false); 849 assert_eq!(ids.available_dcids(), 0); 850 assert_eq!(ids.available_scids(), 2); 851 assert_eq!(ids.has_new_scids(), true); 852 assert_eq!(ids.next_advertise_new_scid_seq(), Some(2)); 853 854 // Send the other. 855 ids.mark_advertise_new_scid_seq(2, false); 856 857 assert_eq!(ids.available_dcids(), 0); 858 assert_eq!(ids.available_scids(), 2); 859 assert_eq!(ids.has_new_scids(), false); 860 assert_eq!(ids.next_advertise_new_scid_seq(), None); 861 } 862 863 #[test] new_dcid_event()864 fn new_dcid_event() { 865 let (scid, _) = create_cid_and_reset_token(16); 866 let (dcid, _) = create_cid_and_reset_token(16); 867 868 let mut ids = ConnectionIdentifiers::new(2, &scid, 0, None); 869 ids.set_initial_dcid(dcid, None, Some(0)); 870 871 assert_eq!(ids.available_dcids(), 0); 872 assert_eq!(ids.dcids.len(), 1); 873 874 let (dcid2, rt2) = create_cid_and_reset_token(16); 875 876 assert_eq!( 877 ids.new_dcid(dcid2.clone(), 1, rt2, 0), 878 Ok(Vec::<(u64, usize)>::new()), 879 ); 880 assert_eq!(ids.available_dcids(), 1); 881 assert_eq!(ids.dcids.len(), 2); 882 883 // Now we assume that the client wants to advertise more source 884 // Connection IDs than the advertised limit. This is valid if it 885 // requests its peer to retire enough Connection IDs to fit within the 886 // limits. 887 let (dcid3, rt3) = create_cid_and_reset_token(16); 888 assert_eq!(ids.new_dcid(dcid3.clone(), 2, rt3, 1), Ok(vec![(0, 0)])); 889 // The CID module does not handle path replacing. Fake it now. 890 ids.link_dcid_to_path_id(1, 0).unwrap(); 891 assert_eq!(ids.available_dcids(), 1); 892 assert_eq!(ids.dcids.len(), 2); 893 assert_eq!(ids.has_retire_dcids(), true); 894 assert_eq!(ids.next_retire_dcid_seq(), Some(0)); 895 896 // Fake RETIRE_CONNECTION_ID sending. 897 ids.mark_retire_dcid_seq(0, false); 898 assert_eq!(ids.has_retire_dcids(), false); 899 assert_eq!(ids.next_retire_dcid_seq(), None); 900 901 // Now tries to experience CID retirement. If the server tries to remove 902 // non-existing DCIDs, it fails. 903 assert_eq!(ids.retire_dcid(0), Err(Error::InvalidState)); 904 assert_eq!(ids.retire_dcid(3), Err(Error::InvalidState)); 905 assert_eq!(ids.has_retire_dcids(), false); 906 assert_eq!(ids.dcids.len(), 2); 907 908 // Now it removes DCID with sequence 1. 909 assert_eq!(ids.retire_dcid(1), Ok(Some(0))); 910 // The CID module does not handle path replacing. Fake it now. 911 ids.link_dcid_to_path_id(2, 0).unwrap(); 912 assert_eq!(ids.available_dcids(), 0); 913 assert_eq!(ids.has_retire_dcids(), true); 914 assert_eq!(ids.next_retire_dcid_seq(), Some(1)); 915 assert_eq!(ids.dcids.len(), 1); 916 917 // Fake RETIRE_CONNECTION_ID sending. 918 ids.mark_retire_dcid_seq(1, false); 919 assert_eq!(ids.has_retire_dcids(), false); 920 assert_eq!(ids.next_retire_dcid_seq(), None); 921 922 // Trying to remove the last DCID triggers an error. 923 assert_eq!(ids.retire_dcid(2), Err(Error::OutOfIdentifiers)); 924 assert_eq!(ids.available_dcids(), 0); 925 assert_eq!(ids.has_retire_dcids(), false); 926 assert_eq!(ids.dcids.len(), 1); 927 } 928 929 #[test] retire_scids()930 fn retire_scids() { 931 let (scid, _) = create_cid_and_reset_token(16); 932 let (dcid, _) = create_cid_and_reset_token(16); 933 934 let mut ids = ConnectionIdentifiers::new(3, &scid, 0, None); 935 ids.set_initial_dcid(dcid, None, Some(0)); 936 ids.set_source_conn_id_limit(3); 937 938 let (scid2, rt2) = create_cid_and_reset_token(16); 939 let (scid3, rt3) = create_cid_and_reset_token(16); 940 941 assert_eq!( 942 ids.new_scid(scid2.clone(), Some(rt2), true, None, false), 943 Ok(1), 944 ); 945 assert_eq!(ids.scids.len(), 2); 946 assert_eq!( 947 ids.new_scid(scid3.clone(), Some(rt3), true, None, false), 948 Ok(2), 949 ); 950 assert_eq!(ids.scids.len(), 3); 951 952 assert_eq!(ids.pop_retired_scid(), None); 953 954 assert_eq!(ids.retire_scid(0, &scid2), Ok(Some(0))); 955 956 assert_eq!(ids.pop_retired_scid(), Some(scid)); 957 assert_eq!(ids.pop_retired_scid(), None); 958 959 assert_eq!(ids.retire_scid(1, &scid3), Ok(None)); 960 961 assert_eq!(ids.pop_retired_scid(), Some(scid2)); 962 assert_eq!(ids.pop_retired_scid(), None); 963 } 964 } 965