quiche/
cid.rs

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