Skip to main content

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 the element is the last one remaining in the collection, this method
183    /// 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        let index = match self.inner.iter().position(|e| e.seq == seq) {
191            Some(i) => i,
192            None => return Ok(None),
193        };
194
195        if self.inner.len() <= 1 {
196            return Err(Error::OutOfIdentifiers);
197        }
198
199        Ok(self.inner.remove(index))
200    }
201
202    /// Removes all elements in the collection with sequence numbers less than
203    /// `retire_prior_to`. The inspect closure is run on each element before it
204    /// is removed.
205    ///
206    /// The deque is in arrival order (not necessarily sorted by seq), so we
207    /// have to check each entry.
208    fn retire_prior_to<F>(&mut self, retire_prior_to: u64, mut inspect: F)
209    where
210        F: FnMut(&mut ConnectionIdEntry),
211    {
212        self.inner.retain_mut(|e| {
213            if e.seq < retire_prior_to {
214                inspect(e);
215                return false;
216            }
217            true
218        });
219    }
220}
221
222#[derive(Default)]
223pub struct ConnectionIdentifiers {
224    /// All the Destination Connection IDs provided by our peer.
225    dcids: BoundedNonEmptyConnectionIdVecDeque,
226
227    /// All the Source Connection IDs we provide to our peer.
228    scids: BoundedNonEmptyConnectionIdVecDeque,
229
230    /// Source Connection IDs that should be announced to the peer.
231    advertise_new_scid_seqs: VecDeque<u64>,
232
233    /// Retired Destination Connection IDs that should be announced to the peer.
234    retire_dcid_seqs: BoundedConnectionIdSeqSet,
235
236    /// Retired Source Connection IDs that should be notified to the
237    /// application.
238    retired_scids: VecDeque<ConnectionId<'static>>,
239
240    /// Largest "Retire Prior To" we received from the peer.
241    largest_peer_retire_prior_to: u64,
242
243    /// Largest sequence number we received from the peer.
244    largest_destination_seq: u64,
245
246    /// Next sequence number to use.
247    next_scid_seq: u64,
248
249    /// "Retire Prior To" value to advertise to the peer.
250    retire_prior_to: u64,
251
252    /// The maximum number of source Connection IDs our peer allows us.
253    source_conn_id_limit: usize,
254
255    /// Does the host use zero-length source Connection ID.
256    zero_length_scid: bool,
257
258    /// Does the host use zero-length destination Connection ID.
259    zero_length_dcid: bool,
260}
261
262impl ConnectionIdentifiers {
263    /// Creates a new `ConnectionIdentifiers` with the specified destination
264    /// connection ID limit and initial source Connection ID. The destination
265    /// Connection ID is set to the empty one.
266    pub fn new(
267        mut destination_conn_id_limit: usize, initial_scid: &ConnectionId,
268        initial_path_id: usize, reset_token: Option<u128>,
269    ) -> ConnectionIdentifiers {
270        // It must be at least 2.
271        if destination_conn_id_limit < 2 {
272            destination_conn_id_limit = 2;
273        }
274
275        // Initially, the limit of active source connection IDs is 2.
276        let source_conn_id_limit = 2;
277
278        // Record the zero-length SCID status.
279        let zero_length_scid = initial_scid.is_empty();
280
281        let initial_scid =
282            ConnectionId::from_ref(initial_scid.as_ref()).into_owned();
283
284        // We need to track up to (2 * source_conn_id_limit - 1) source
285        // Connection IDs when the host wants to force their renewal.
286        let scids = BoundedNonEmptyConnectionIdVecDeque::new(
287            2 * source_conn_id_limit - 1,
288            ConnectionIdEntry {
289                cid: initial_scid,
290                seq: 0,
291                reset_token,
292                path_id: Some(initial_path_id),
293            },
294        );
295
296        let dcids = BoundedNonEmptyConnectionIdVecDeque::new(
297            destination_conn_id_limit,
298            ConnectionIdEntry {
299                cid: ConnectionId::default(),
300                seq: 0,
301                reset_token: None,
302                path_id: Some(initial_path_id),
303            },
304        );
305
306        // Guard against overflow.
307        let value =
308            (destination_conn_id_limit as u64) * RETIRED_CONN_ID_LIMIT_MULTIPLIER;
309        let size = cmp::min(usize::MAX as u64, value) as usize;
310        // Because we already inserted the initial SCID.
311        let next_scid_seq = 1;
312        ConnectionIdentifiers {
313            scids,
314            dcids,
315            retire_dcid_seqs: BoundedConnectionIdSeqSet::new(size),
316            next_scid_seq,
317            source_conn_id_limit,
318            zero_length_scid,
319            ..Default::default()
320        }
321    }
322
323    /// Sets the maximum number of source connection IDs our peer allows us.
324    pub fn set_source_conn_id_limit(&mut self, v: u64) {
325        // Bound conn id limit so our scids queue sizing is valid.
326        let v = cmp::min(v, (usize::MAX / 2) as u64) as usize;
327
328        // It must be at least 2.
329        if v >= 2 {
330            self.source_conn_id_limit = v;
331            // We need to track up to (2 * source_conn_id_limit - 1) source
332            // Connection IDs when the host wants to force their renewal.
333            self.scids.resize(2 * v - 1);
334        }
335    }
336
337    /// Gets the destination Connection ID associated with the provided sequence
338    /// number.
339    #[inline]
340    pub fn get_dcid(&self, seq_num: u64) -> Result<&ConnectionIdEntry> {
341        self.dcids.get(seq_num).ok_or(Error::InvalidState)
342    }
343
344    /// Gets the source Connection ID associated with the provided sequence
345    /// number.
346    #[inline]
347    pub fn get_scid(&self, seq_num: u64) -> Result<&ConnectionIdEntry> {
348        self.scids.get(seq_num).ok_or(Error::InvalidState)
349    }
350
351    /// Adds a new source identifier, and indicates whether it should be
352    /// advertised through a `NEW_CONNECTION_ID` frame or not.
353    ///
354    /// At any time, the peer cannot have more Destination Connection IDs than
355    /// the maximum number of active Connection IDs it negotiated. In such case
356    /// (i.e., when [`active_source_cids()`] - `peer_active_conn_id_limit` = 0,
357    /// if the caller agrees to request the removal of previous connection IDs,
358    /// it sets the `retire_if_needed` parameter. Otherwise, an [`IdLimit`] is
359    /// returned.
360    ///
361    /// Note that setting `retire_if_needed` does not prevent this function from
362    /// returning an [`IdLimit`] in the case the caller wants to retire still
363    /// unannounced Connection IDs.
364    ///
365    /// When setting the initial Source Connection ID, the `reset_token` may be
366    /// `None`. However, other Source CIDs must have an associated
367    /// `reset_token`. Providing `None` as the `reset_token` for non-initial
368    /// SCIDs raises an [`InvalidState`].
369    ///
370    /// In the case the provided `cid` is already present, it does not add it.
371    /// If the provided `reset_token` differs from the one already registered,
372    /// returns an `InvalidState`.
373    ///
374    /// Returns the sequence number associated to that new source identifier.
375    ///
376    /// [`active_source_cids()`]:  struct.ConnectionIdentifiers.html#method.active_source_cids
377    /// [`InvalidState`]: enum.Error.html#InvalidState
378    /// [`IdLimit`]: enum.Error.html#IdLimit
379    pub fn new_scid(
380        &mut self, cid: ConnectionId<'static>, reset_token: Option<u128>,
381        advertise: bool, path_id: Option<usize>, retire_if_needed: bool,
382    ) -> Result<u64> {
383        if self.zero_length_scid {
384            return Err(Error::InvalidState);
385        }
386
387        // Check whether the number of source Connection IDs does not exceed the
388        // limit. If the host agrees to retire old CIDs, it can store up to
389        // (2 * source_active_conn_id - 1) source CIDs. This limit is enforced
390        // when calling `self.scids.insert()`.
391        if self.scids.len() >= self.source_conn_id_limit {
392            if !retire_if_needed {
393                return Err(Error::IdLimit);
394            }
395
396            // We need to retire the lowest one.
397            self.retire_prior_to = self.lowest_usable_scid_seq()? + 1;
398        }
399
400        let seq = self.next_scid_seq;
401
402        if reset_token.is_none() && seq != 0 {
403            return Err(Error::InvalidState);
404        }
405
406        // Check first that the SCID has not been inserted before.
407        if let Some(e) = self.scids.iter().find(|e| e.cid == cid) {
408            if e.reset_token != reset_token {
409                return Err(Error::InvalidState);
410            }
411            return Ok(e.seq);
412        }
413
414        self.scids.insert(ConnectionIdEntry {
415            cid,
416            seq,
417            reset_token,
418            path_id,
419        })?;
420        self.next_scid_seq += 1;
421
422        self.mark_advertise_new_scid_seq(seq, advertise);
423
424        Ok(seq)
425    }
426
427    /// Sets the initial destination identifier.
428    pub fn set_initial_dcid(
429        &mut self, cid: ConnectionId<'static>, reset_token: Option<u128>,
430        path_id: Option<usize>,
431    ) {
432        // Record the zero-length DCID status.
433        self.zero_length_dcid = cid.is_empty();
434        self.dcids.clear_and_insert(ConnectionIdEntry {
435            cid,
436            seq: 0,
437            reset_token,
438            path_id,
439        });
440    }
441
442    /// Adds a new Destination Connection ID (originating from a
443    /// NEW_CONNECTION_ID frame) and process all its related metadata.
444    ///
445    /// Returns an error if the provided Connection ID or its metadata are
446    /// invalid.
447    ///
448    /// Returns a list of tuples (DCID sequence number, Path ID), containing the
449    /// sequence number of retired DCIDs that were linked to their respective
450    /// Path ID.
451    pub fn new_dcid(
452        &mut self, cid: ConnectionId<'static>, seq: u64, reset_token: u128,
453        retire_prior_to: u64, retired_path_ids: &mut SmallVec<[(u64, usize); 1]>,
454    ) -> Result<()> {
455        if self.zero_length_dcid {
456            return Err(Error::InvalidState);
457        }
458
459        // If an endpoint receives a NEW_CONNECTION_ID frame that repeats a
460        // previously issued connection ID with a different Stateless Reset
461        // Token field value or a different Sequence Number field value, or if a
462        // sequence number is used for different connection IDs, the endpoint
463        // MAY treat that receipt as a connection error of type
464        // PROTOCOL_VIOLATION.
465        if let Some(e) = self.dcids.iter().find(|e| e.cid == cid || e.seq == seq)
466        {
467            if e.cid != cid || e.seq != seq || e.reset_token != Some(reset_token)
468            {
469                return Err(Error::InvalidFrame);
470            }
471            // The identifier is already there, nothing to do.
472            return Ok(());
473        }
474
475        // The value in the Retire Prior To field MUST be less than or equal to
476        // the value in the Sequence Number field. Receiving a value in the
477        // Retire Prior To field that is greater than that in the Sequence
478        // Number field MUST be treated as a connection error of type
479        // FRAME_ENCODING_ERROR.
480        if retire_prior_to > seq {
481            return Err(Error::InvalidFrame);
482        }
483
484        // An endpoint that receives a NEW_CONNECTION_ID frame with a sequence
485        // number smaller than the Retire Prior To field of a previously
486        // received NEW_CONNECTION_ID frame MUST send a corresponding
487        // RETIRE_CONNECTION_ID frame that retires the newly received connection
488        // ID, unless it has already done so for that sequence number.
489        if seq < self.largest_peer_retire_prior_to {
490            self.mark_retire_dcid_seq(seq, true)?;
491            return Ok(());
492        }
493
494        if seq > self.largest_destination_seq {
495            self.largest_destination_seq = seq;
496        }
497
498        let new_entry = ConnectionIdEntry {
499            cid: cid.clone(),
500            seq,
501            reset_token: Some(reset_token),
502            path_id: None,
503        };
504
505        let mut retired_dcid_queue_err = None;
506
507        // A receiver MUST ignore any Retire Prior To fields that do not
508        // increase the largest received Retire Prior To value.
509        //
510        // After processing a NEW_CONNECTION_ID frame and adding and retiring
511        // active connection IDs, if the number of active connection IDs exceeds
512        // the value advertised in its active_connection_id_limit transport
513        // parameter, an endpoint MUST close the connection with an error of
514        // type CONNECTION_ID_LIMIT_ERROR.
515        if retire_prior_to > self.largest_peer_retire_prior_to {
516            let retired = &mut self.retire_dcid_seqs;
517
518            // The insert entry MUST have a sequence higher or equal to the ones
519            // being retired.
520            if new_entry.seq < retire_prior_to {
521                return Err(Error::OutOfIdentifiers);
522            }
523
524            // To avoid exceeding the capacity of the inner `VecDeque`, we first
525            // remove the elements and then insert the new one.
526            self.dcids.retire_prior_to(retire_prior_to, |e| {
527                if let Some(pid) = e.path_id {
528                    retired_path_ids.push((e.seq, pid));
529                }
530
531                if let Err(e) = retired.insert(e.seq) {
532                    // Keep the first error we encounter and report it _after_
533                    // inserting the new DCID. We still have to process the
534                    // remaining retired DCIDs.
535                    retired_dcid_queue_err.get_or_insert(e);
536                }
537            });
538
539            self.largest_peer_retire_prior_to = retire_prior_to;
540        }
541
542        // Note that if no element has been retired and the `VecDeque` reaches
543        // its capacity limit, this will raise an `IdLimit`.
544        self.dcids.insert(new_entry)?;
545
546        // Propagate the error triggered when inserting a retired DCID seq to
547        // the queue.
548        if let Some(e) = retired_dcid_queue_err {
549            return Err(e);
550        }
551
552        Ok(())
553    }
554
555    /// Retires the Source Connection ID having the provided sequence number.
556    ///
557    /// In case the retired Connection ID is the same as the one used by the
558    /// packet requesting the retiring, or if the retired sequence number is
559    /// greater than any previously advertised sequence numbers, it returns an
560    /// [`InvalidState`].
561    ///
562    /// Returns the path ID that was associated to the retired CID, if any.
563    ///
564    /// [`InvalidState`]: enum.Error.html#InvalidState
565    pub fn retire_scid(
566        &mut self, seq: u64, pkt_dcid: &ConnectionId,
567    ) -> Result<Option<usize>> {
568        if seq >= self.next_scid_seq {
569            return Err(Error::InvalidState);
570        }
571
572        let pid = if let Some(e) = self.scids.remove(seq)? {
573            if e.cid == *pkt_dcid {
574                return Err(Error::InvalidState);
575            }
576
577            // Notifies the application.
578            self.retired_scids.push_back(e.cid);
579
580            // Retiring this SCID may increase the retire prior to.
581            let lowest_scid_seq = self.lowest_usable_scid_seq()?;
582            self.retire_prior_to = lowest_scid_seq;
583
584            e.path_id
585        } else {
586            None
587        };
588
589        Ok(pid)
590    }
591
592    /// Retires the Destination Connection ID having the provided sequence
593    /// number.
594    ///
595    /// If the caller tries to retire the last destination Connection ID, this
596    /// method triggers an [`OutOfIdentifiers`].
597    ///
598    /// If the caller tries to retire a non-existing Destination Connection
599    /// ID sequence number, this method returns an [`InvalidState`].
600    ///
601    /// Returns the path ID that was associated to the retired CID, if any.
602    ///
603    /// [`OutOfIdentifiers`]: enum.Error.html#OutOfIdentifiers
604    /// [`InvalidState`]: enum.Error.html#InvalidState
605    pub fn retire_dcid(&mut self, seq: u64) -> Result<Option<usize>> {
606        if self.zero_length_dcid {
607            return Err(Error::InvalidState);
608        }
609
610        let e = self.dcids.remove(seq)?.ok_or(Error::InvalidState)?;
611
612        self.mark_retire_dcid_seq(seq, true)?;
613
614        Ok(e.path_id)
615    }
616
617    /// Returns an iterator over the source connection IDs.
618    pub fn scids_iter(&self) -> impl Iterator<Item = &ConnectionId<'_>> {
619        self.scids.iter().map(|e| &e.cid)
620    }
621
622    /// Updates the Source Connection ID entry with the provided sequence number
623    /// to indicate that it is now linked to the provided path ID.
624    pub fn link_scid_to_path_id(
625        &mut self, dcid_seq: u64, path_id: usize,
626    ) -> Result<()> {
627        let e = self.scids.get_mut(dcid_seq).ok_or(Error::InvalidState)?;
628        e.path_id = Some(path_id);
629        Ok(())
630    }
631
632    /// Updates the Destination Connection ID entry with the provided sequence
633    /// number to indicate that it is now linked to the provided path ID.
634    pub fn link_dcid_to_path_id(
635        &mut self, dcid_seq: u64, path_id: usize,
636    ) -> Result<()> {
637        let e = self.dcids.get_mut(dcid_seq).ok_or(Error::InvalidState)?;
638        e.path_id = Some(path_id);
639        Ok(())
640    }
641
642    /// Gets the minimum Source Connection ID sequence number whose removal has
643    /// not been requested yet.
644    #[inline]
645    pub fn lowest_usable_scid_seq(&self) -> Result<u64> {
646        self.scids
647            .iter()
648            .filter_map(|e| {
649                if e.seq >= self.retire_prior_to {
650                    Some(e.seq)
651                } else {
652                    None
653                }
654            })
655            .min()
656            .ok_or(Error::InvalidState)
657    }
658
659    /// Gets the lowest Destination Connection ID sequence number that is not
660    /// associated to a path.
661    #[inline]
662    pub fn lowest_available_dcid_seq(&self) -> Option<u64> {
663        self.dcids
664            .iter()
665            .filter_map(|e| {
666                if e.path_id.is_none() {
667                    Some(e.seq)
668                } else {
669                    None
670                }
671            })
672            .min()
673    }
674
675    /// Finds the sequence number of the Source Connection ID having the
676    /// provided value and the identifier of the path using it, if any.
677    #[inline]
678    pub fn find_scid_seq(
679        &self, scid: &ConnectionId,
680    ) -> Option<(u64, Option<usize>)> {
681        self.scids.iter().find_map(|e| {
682            if e.cid == *scid {
683                Some((e.seq, e.path_id))
684            } else {
685                None
686            }
687        })
688    }
689
690    /// Returns the number of Source Connection IDs that have not been
691    /// assigned to a path yet.
692    ///
693    /// Note that this function is only meaningful if the host uses non-zero
694    /// length Source Connection IDs.
695    #[inline]
696    pub fn available_scids(&self) -> usize {
697        self.scids.iter().filter(|e| e.path_id.is_none()).count()
698    }
699
700    /// Returns the number of Destination Connection IDs that have not been
701    /// assigned to a path yet.
702    ///
703    /// Note that this function returns 0 if the host uses zero length
704    /// Destination Connection IDs.
705    #[inline]
706    pub fn available_dcids(&self) -> usize {
707        if self.zero_length_dcid() {
708            return 0;
709        }
710        self.dcids.iter().filter(|e| e.path_id.is_none()).count()
711    }
712
713    /// Returns the oldest active source Connection ID of this connection.
714    #[inline]
715    pub fn oldest_scid(&self) -> &ConnectionIdEntry {
716        self.scids.get_oldest()
717    }
718
719    /// Returns the oldest known active destination Connection ID of this
720    /// connection.
721    ///
722    /// Note that due to e.g., reordering at reception side, the oldest known
723    /// active destination Connection ID is not necessarily the one having the
724    /// lowest sequence.
725    #[inline]
726    pub fn oldest_dcid(&self) -> &ConnectionIdEntry {
727        self.dcids.get_oldest()
728    }
729
730    /// Adds or remove the source Connection ID sequence number from the
731    /// source Connection ID set that need to be advertised to the peer through
732    /// NEW_CONNECTION_ID frames.
733    #[inline]
734    pub fn mark_advertise_new_scid_seq(
735        &mut self, scid_seq: u64, advertise: bool,
736    ) {
737        if advertise {
738            self.advertise_new_scid_seqs.push_back(scid_seq);
739        } else if let Some(index) = self
740            .advertise_new_scid_seqs
741            .iter()
742            .position(|s| *s == scid_seq)
743        {
744            self.advertise_new_scid_seqs.remove(index);
745        }
746    }
747
748    /// Adds or remove the destination Connection ID sequence number from the
749    /// retired destination Connection ID set that need to be advertised to the
750    /// peer through RETIRE_CONNECTION_ID frames.
751    #[inline]
752    pub fn mark_retire_dcid_seq(
753        &mut self, dcid_seq: u64, retire: bool,
754    ) -> Result<()> {
755        if retire {
756            self.retire_dcid_seqs.insert(dcid_seq)?;
757        } else {
758            self.retire_dcid_seqs.remove(&dcid_seq);
759        }
760
761        Ok(())
762    }
763
764    /// Gets a source Connection ID's sequence number requiring advertising it
765    /// to the peer through NEW_CONNECTION_ID frame, if any.
766    ///
767    /// If `Some`, it always returns the same value until it has been removed
768    /// using `mark_advertise_new_scid_seq`.
769    #[inline]
770    pub fn next_advertise_new_scid_seq(&self) -> Option<u64> {
771        self.advertise_new_scid_seqs.front().copied()
772    }
773
774    /// Returns a copy of the set of destination Connection IDs's sequence
775    /// numbers to send RETIRE_CONNECTION_ID frames.
776    ///
777    /// Note that the set includes sequence numbers at the time the copy was
778    /// created. To account for newly inserted or removed sequence numbers, a
779    /// new copy needs to be created.
780    #[inline]
781    pub fn retire_dcid_seqs(&self) -> HashSet<u64> {
782        self.retire_dcid_seqs.inner.clone()
783    }
784
785    /// Returns true if there are new source Connection IDs to advertise.
786    #[inline]
787    pub fn has_new_scids(&self) -> bool {
788        !self.advertise_new_scid_seqs.is_empty()
789    }
790
791    /// Returns true if there are retired destination Connection IDs to\
792    /// advertise.
793    #[inline]
794    pub fn has_retire_dcids(&self) -> bool {
795        !self.retire_dcid_seqs.is_empty()
796    }
797
798    /// Returns whether zero-length source CIDs are used.
799    #[inline]
800    pub fn zero_length_scid(&self) -> bool {
801        self.zero_length_scid
802    }
803
804    /// Returns whether zero-length destination CIDs are used.
805    #[inline]
806    pub fn zero_length_dcid(&self) -> bool {
807        self.zero_length_dcid
808    }
809
810    /// Gets the NEW_CONNECTION_ID frame related to the source connection ID
811    /// with sequence `seq_num`.
812    pub fn get_new_connection_id_frame_for(
813        &self, seq_num: u64,
814    ) -> Result<frame::Frame> {
815        let e = self.scids.get(seq_num).ok_or(Error::InvalidState)?;
816        Ok(frame::Frame::NewConnectionId {
817            seq_num,
818            retire_prior_to: self.retire_prior_to,
819            conn_id: e.cid.to_vec(),
820            reset_token: e.reset_token.ok_or(Error::InvalidState)?.to_be_bytes(),
821        })
822    }
823
824    /// Returns the number of source Connection IDs that are active. This is
825    /// only meaningful if the host uses non-zero length Source Connection IDs.
826    #[inline]
827    pub fn active_source_cids(&self) -> usize {
828        self.scids.len()
829    }
830
831    /// Returns the number of source Connection IDs that are retired. This is
832    /// only meaningful if the host uses non-zero length Source Connection IDs.
833    #[inline]
834    pub fn retired_source_cids(&self) -> usize {
835        self.retired_scids.len()
836    }
837
838    pub fn pop_retired_scid(&mut self) -> Option<ConnectionId<'static>> {
839        self.retired_scids.pop_front()
840    }
841}
842
843#[cfg(test)]
844mod tests {
845    use super::*;
846    use crate::test_utils::create_cid_and_reset_token;
847
848    #[test]
849    fn ids_new_scids() {
850        let (scid, _) = create_cid_and_reset_token(16);
851        let (dcid, _) = create_cid_and_reset_token(16);
852
853        let mut ids = ConnectionIdentifiers::new(2, &scid, 0, None);
854        ids.set_source_conn_id_limit(3);
855        ids.set_initial_dcid(dcid, None, Some(0));
856
857        assert_eq!(ids.available_dcids(), 0);
858        assert_eq!(ids.available_scids(), 0);
859        assert!(!ids.has_new_scids());
860        assert_eq!(ids.next_advertise_new_scid_seq(), None);
861
862        let (scid2, rt2) = create_cid_and_reset_token(16);
863
864        assert_eq!(ids.new_scid(scid2, Some(rt2), true, None, false), Ok(1));
865        assert_eq!(ids.available_dcids(), 0);
866        assert_eq!(ids.available_scids(), 1);
867        assert!(ids.has_new_scids());
868        assert_eq!(ids.next_advertise_new_scid_seq(), Some(1));
869
870        let (scid3, rt3) = create_cid_and_reset_token(16);
871
872        assert_eq!(ids.new_scid(scid3, Some(rt3), true, None, false), Ok(2));
873        assert_eq!(ids.available_dcids(), 0);
874        assert_eq!(ids.available_scids(), 2);
875        assert!(ids.has_new_scids());
876        assert_eq!(ids.next_advertise_new_scid_seq(), Some(1));
877
878        // If now we give another CID, it reports an error since it exceeds the
879        // limit of active CIDs.
880        let (scid4, rt4) = create_cid_and_reset_token(16);
881
882        assert_eq!(
883            ids.new_scid(scid4, Some(rt4), true, None, false),
884            Err(Error::IdLimit),
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(), Some(1));
890
891        // Assume we sent one of them.
892        ids.mark_advertise_new_scid_seq(1, false);
893        assert_eq!(ids.available_dcids(), 0);
894        assert_eq!(ids.available_scids(), 2);
895        assert!(ids.has_new_scids());
896        assert_eq!(ids.next_advertise_new_scid_seq(), Some(2));
897
898        // Send the other.
899        ids.mark_advertise_new_scid_seq(2, false);
900
901        assert_eq!(ids.available_dcids(), 0);
902        assert_eq!(ids.available_scids(), 2);
903        assert!(!ids.has_new_scids());
904        assert_eq!(ids.next_advertise_new_scid_seq(), None);
905    }
906
907    #[test]
908    fn new_dcid_event() {
909        let (scid, _) = create_cid_and_reset_token(16);
910        let (dcid, _) = create_cid_and_reset_token(16);
911
912        let mut retired_path_ids = SmallVec::new();
913
914        let mut ids = ConnectionIdentifiers::new(2, &scid, 0, None);
915        ids.set_initial_dcid(dcid, None, Some(0));
916
917        assert_eq!(ids.available_dcids(), 0);
918        assert_eq!(ids.dcids.len(), 1);
919
920        let (dcid2, rt2) = create_cid_and_reset_token(16);
921
922        assert_eq!(
923            ids.new_dcid(dcid2, 1, rt2, 0, &mut retired_path_ids),
924            Ok(()),
925        );
926        assert_eq!(retired_path_ids, SmallVec::from_buf([]));
927        assert_eq!(ids.available_dcids(), 1);
928        assert_eq!(ids.dcids.len(), 2);
929
930        // Now we assume that the client wants to advertise more source
931        // Connection IDs than the advertised limit. This is valid if it
932        // requests its peer to retire enough Connection IDs to fit within the
933        // limits.
934        let (dcid3, rt3) = create_cid_and_reset_token(16);
935        assert_eq!(
936            ids.new_dcid(dcid3, 2, rt3, 1, &mut retired_path_ids),
937            Ok(())
938        );
939        assert_eq!(retired_path_ids, SmallVec::from_buf([(0, 0)]));
940        // The CID module does not handle path replacing. Fake it now.
941        ids.link_dcid_to_path_id(1, 0).unwrap();
942        assert_eq!(ids.available_dcids(), 1);
943        assert_eq!(ids.dcids.len(), 2);
944        assert!(ids.has_retire_dcids());
945        assert_eq!(ids.retire_dcid_seqs().iter().next(), Some(&0));
946
947        // Fake RETIRE_CONNECTION_ID sending.
948        let _ = ids.mark_retire_dcid_seq(0, false);
949        assert!(!ids.has_retire_dcids());
950        assert_eq!(ids.retire_dcid_seqs().iter().next(), None);
951
952        // Now tries to experience CID retirement. If the server tries to remove
953        // non-existing DCIDs, it fails.
954        assert_eq!(ids.retire_dcid(0), Err(Error::InvalidState));
955        assert_eq!(ids.retire_dcid(3), Err(Error::InvalidState));
956        assert!(!ids.has_retire_dcids());
957        assert_eq!(ids.dcids.len(), 2);
958
959        // Now it removes DCID with sequence 1.
960        assert_eq!(ids.retire_dcid(1), Ok(Some(0)));
961        // The CID module does not handle path replacing. Fake it now.
962        ids.link_dcid_to_path_id(2, 0).unwrap();
963        assert_eq!(ids.available_dcids(), 0);
964        assert!(ids.has_retire_dcids());
965        assert_eq!(ids.retire_dcid_seqs().iter().next(), Some(&1));
966        assert_eq!(ids.dcids.len(), 1);
967
968        // Fake RETIRE_CONNECTION_ID sending.
969        let _ = ids.mark_retire_dcid_seq(1, false);
970        assert!(!ids.has_retire_dcids());
971        assert_eq!(ids.retire_dcid_seqs().iter().next(), None);
972
973        // Trying to remove the last DCID triggers an error.
974        assert_eq!(ids.retire_dcid(2), Err(Error::OutOfIdentifiers));
975        assert_eq!(ids.retire_dcid(0), Err(Error::InvalidState));
976        assert_eq!(ids.retire_dcid(1), Err(Error::InvalidState));
977        assert_eq!(ids.available_dcids(), 0);
978        assert!(!ids.has_retire_dcids());
979        assert_eq!(ids.dcids.len(), 1);
980    }
981
982    #[test]
983    fn new_dcid_reordered() {
984        let (scid, _) = create_cid_and_reset_token(16);
985        let (dcid, _) = create_cid_and_reset_token(16);
986
987        let mut retired_path_ids = SmallVec::new();
988
989        let mut ids = ConnectionIdentifiers::new(2, &scid, 0, None);
990        ids.set_initial_dcid(dcid, None, Some(0));
991
992        assert_eq!(ids.available_dcids(), 0);
993        assert_eq!(ids.dcids.len(), 1);
994
995        // Skip DCID #1 (e.g due to packet loss) and insert DCID #2.
996        let (dcid, rt) = create_cid_and_reset_token(16);
997        assert!(ids.new_dcid(dcid, 2, rt, 1, &mut retired_path_ids).is_ok());
998        assert_eq!(ids.dcids.len(), 1);
999
1000        let (dcid, rt) = create_cid_and_reset_token(16);
1001        assert!(ids.new_dcid(dcid, 3, rt, 2, &mut retired_path_ids).is_ok());
1002        assert_eq!(ids.dcids.len(), 2);
1003
1004        let (dcid, rt) = create_cid_and_reset_token(16);
1005        assert!(ids.new_dcid(dcid, 4, rt, 3, &mut retired_path_ids).is_ok());
1006        assert_eq!(ids.dcids.len(), 2);
1007
1008        // Insert DCID #1 (e.g due to packet reordering). It should be discarded
1009        // due to `largest_peer_retire_prior_to`.
1010        let (dcid, rt) = create_cid_and_reset_token(16);
1011        assert!(ids.new_dcid(dcid, 1, rt, 0, &mut retired_path_ids).is_ok());
1012        assert_eq!(ids.dcids.len(), 2);
1013        assert!(ids.get_dcid(1).is_err());
1014
1015        // Try inserting DCID #1 again (e.g. due to retransmission).
1016        let (dcid, rt) = create_cid_and_reset_token(16);
1017        assert!(ids.new_dcid(dcid, 1, rt, 0, &mut retired_path_ids).is_ok());
1018        assert_eq!(ids.dcids.len(), 2);
1019        assert!(ids.get_dcid(1).is_err());
1020    }
1021
1022    #[test]
1023    fn new_dcid_partial_retire_prior_to() {
1024        let (scid, _) = create_cid_and_reset_token(16);
1025        let (dcid, _) = create_cid_and_reset_token(16);
1026
1027        let mut retired_path_ids = SmallVec::new();
1028
1029        let mut ids = ConnectionIdentifiers::new(5, &scid, 0, None);
1030        ids.set_initial_dcid(dcid, None, Some(0));
1031
1032        assert_eq!(ids.available_dcids(), 0);
1033        assert_eq!(ids.dcids.len(), 1);
1034
1035        let (dcid, rt) = create_cid_and_reset_token(16);
1036        assert!(ids.new_dcid(dcid, 1, rt, 0, &mut retired_path_ids).is_ok());
1037        assert_eq!(ids.dcids.len(), 2);
1038
1039        let (dcid, rt) = create_cid_and_reset_token(16);
1040        assert!(ids.new_dcid(dcid, 2, rt, 0, &mut retired_path_ids).is_ok());
1041        assert_eq!(ids.dcids.len(), 3);
1042
1043        let (dcid, rt) = create_cid_and_reset_token(16);
1044        assert!(ids.new_dcid(dcid, 3, rt, 0, &mut retired_path_ids).is_ok());
1045        assert_eq!(ids.dcids.len(), 4);
1046
1047        let (dcid, rt) = create_cid_and_reset_token(16);
1048        assert!(ids.new_dcid(dcid, 4, rt, 0, &mut retired_path_ids).is_ok());
1049        assert_eq!(ids.dcids.len(), 5);
1050
1051        // Retire a DCID from the middle of the list
1052        assert!(ids.retire_dcid(3).is_ok());
1053
1054        // Retire prior to DCID that was just retired.
1055        //
1056        // This is largely to test that `retire_prior_to()` works correctly even
1057        // if the actual sequence that is searched isn't present in the list.
1058        let (dcid, rt) = create_cid_and_reset_token(16);
1059        assert!(ids.new_dcid(dcid, 5, rt, 3, &mut retired_path_ids).is_ok());
1060        assert_eq!(ids.dcids.len(), 2);
1061
1062        // Retire all current DCIDs while adding a new one
1063        let (dcid, rt) = create_cid_and_reset_token(16);
1064        assert!(ids.new_dcid(dcid, 6, rt, 6, &mut retired_path_ids).is_ok());
1065        assert_eq!(ids.dcids.len(), 1);
1066    }
1067
1068    #[test]
1069    fn new_dcid_partial_retire_out_of_order() {
1070        let (scid, _) = create_cid_and_reset_token(16);
1071        let (dcid, _) = create_cid_and_reset_token(16);
1072
1073        let mut retired_path_ids = SmallVec::new();
1074
1075        let mut ids = ConnectionIdentifiers::new(5, &scid, 0, None);
1076        ids.set_initial_dcid(dcid, None, Some(0));
1077
1078        assert_eq!(ids.available_dcids(), 0);
1079        assert_eq!(ids.dcids.len(), 1);
1080
1081        // Insert 5 DCIDs where some are out of order
1082        let seq_nums = [5, 3, 2, 19, 8];
1083        for &seq in &seq_nums {
1084            let (dcid, rt) = create_cid_and_reset_token(16);
1085            assert!(ids
1086                .new_dcid(dcid, seq, rt, 1, &mut retired_path_ids)
1087                .is_ok());
1088        }
1089        assert_eq!(ids.dcids.len(), 5);
1090
1091        // Trigger a retire of sequence numbers 2 and 3, inserting #20
1092        let (dcid, rt) = create_cid_and_reset_token(16);
1093        assert!(ids.new_dcid(dcid, 20, rt, 4, &mut retired_path_ids).is_ok());
1094        assert_eq!(ids.dcids.len(), 4);
1095        assert!(ids.get_dcid(20).is_ok());
1096
1097        for &seq in &seq_nums {
1098            let dcid = ids.get_dcid(seq);
1099            assert_eq!(dcid.is_ok(), seq >= 4);
1100        }
1101
1102        // Check that the DCID deque maintains insertion order
1103        let seq_iter = ids.dcids.inner.iter().map(|e| e.seq);
1104        for (seq, expected) in seq_iter.zip([5, 19, 8, 20]) {
1105            assert_eq!(seq, expected);
1106        }
1107    }
1108
1109    #[test]
1110    fn retire_scids() {
1111        let (scid, _) = create_cid_and_reset_token(16);
1112        let (dcid, _) = create_cid_and_reset_token(16);
1113
1114        let mut ids = ConnectionIdentifiers::new(3, &scid, 0, None);
1115        ids.set_initial_dcid(dcid, None, Some(0));
1116        ids.set_source_conn_id_limit(3);
1117
1118        let (scid2, rt2) = create_cid_and_reset_token(16);
1119        let (scid3, rt3) = create_cid_and_reset_token(16);
1120
1121        assert_eq!(
1122            ids.new_scid(scid2.clone(), Some(rt2), true, None, false),
1123            Ok(1),
1124        );
1125        assert_eq!(ids.scids.len(), 2);
1126        assert_eq!(
1127            ids.new_scid(scid3.clone(), Some(rt3), true, None, false),
1128            Ok(2),
1129        );
1130        assert_eq!(ids.scids.len(), 3);
1131
1132        assert_eq!(ids.pop_retired_scid(), None);
1133
1134        assert_eq!(ids.retire_scid(0, &scid2), Ok(Some(0)));
1135
1136        assert_eq!(ids.pop_retired_scid(), Some(scid));
1137        assert_eq!(ids.pop_retired_scid(), None);
1138
1139        assert_eq!(ids.retire_scid(1, &scid3), Ok(None));
1140        assert_eq!(ids.scids.len(), 1);
1141
1142        // The peer may retransmit RETIRE_CONNECTION_ID.
1143        assert_eq!(ids.retire_scid(1, &scid3), Ok(None));
1144        assert_eq!(ids.scids.len(), 1);
1145
1146        assert_eq!(ids.pop_retired_scid(), Some(scid2));
1147        assert_eq!(ids.pop_retired_scid(), None);
1148
1149        // The last SCID cannot be retired.
1150        assert_eq!(ids.retire_scid(2, &scid3), Err(Error::OutOfIdentifiers));
1151        assert_eq!(ids.scids.len(), 1);
1152    }
1153}