• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 use 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