noq_proto/
shared.rs

1use std::{fmt, net::SocketAddr};
2
3use bytes::{Buf, BufMut, BytesMut};
4
5use crate::FourTuple;
6use crate::PathId;
7use crate::{Duration, Instant, MAX_CID_SIZE, ResetToken, coding::BufExt, packet::PartialDecode};
8
9/// Events sent from an Endpoint to a Connection
10#[derive(Debug)]
11pub struct ConnectionEvent(pub(crate) ConnectionEventInner);
12
13#[derive(Debug)]
14pub(crate) enum ConnectionEventInner {
15    /// A datagram has been received for the Connection
16    Datagram(DatagramConnectionEvent),
17    /// New connection identifiers have been issued for the Connection
18    NewIdentifiers(Vec<IssuedCid>, Instant, usize, Option<Duration>),
19}
20
21/// Variant of [`ConnectionEventInner`].
22#[derive(Debug)]
23pub(crate) struct DatagramConnectionEvent {
24    pub(crate) now: Instant,
25    pub(crate) network_path: FourTuple,
26    pub(crate) path_id: PathId,
27    pub(crate) ecn: Option<EcnCodepoint>,
28    pub(crate) first_decode: PartialDecode,
29    pub(crate) remaining: Option<BytesMut>,
30}
31
32/// Events sent from a Connection to an Endpoint
33#[derive(Debug)]
34pub struct EndpointEvent(pub(crate) EndpointEventInner);
35
36impl EndpointEvent {
37    /// Construct an event that indicating that a `Connection` will no longer emit events
38    ///
39    /// Useful for notifying an `Endpoint` that a `Connection` has been destroyed outside of the
40    /// usual state machine flow, e.g. when being dropped by the user.
41    pub fn drained() -> Self {
42        Self(EndpointEventInner::Drained)
43    }
44
45    /// Determine whether this is the last event a `Connection` will emit
46    ///
47    /// Useful for determining when connection-related event loop state can be freed.
48    pub fn is_drained(&self) -> bool {
49        self.0 == EndpointEventInner::Drained
50    }
51
52    /// Whether this is the event is the event indicating the start of the draining period.
53    pub fn is_draining(&self) -> bool {
54        self.0 == EndpointEventInner::Draining
55    }
56}
57
58#[derive(Clone, Debug, Eq, PartialEq)]
59pub(crate) enum EndpointEventInner {
60    /// The connection started draining
61    Draining,
62    /// The connection has been drained
63    Drained,
64    /// The connection has a new active reset token
65    ///
66    /// Whenever the connection switches to a new remote CID issued by the peer, it also
67    /// switches the matching reset token that can be used to abort this connection. This
68    /// event provides a new reset token for the active remote CID.
69    ResetToken(PathId, SocketAddr, ResetToken),
70    /// Retire the remotely issued reset token for a path, without replacing it with a new one
71    ///
72    /// This is like `ResetToken` above, but without replacing the `ResetToken` with a new
73    /// one. See `ConnectionIndex::connection_reset_tokens`.
74    RetireResetToken(PathId),
75    /// The connection needs connection identifiers.
76    ///
77    /// The fields are:
78    /// - The path ID for which the identifiers are needed.
79    /// - The time when the identifiers were needed, not used to generate the CIDs but sent
80    ///   back via the [`ConnectionEventInner::NewIdentifiers`] so the connection can track
81    ///   the lifetime of when it needs to be rotated.  should be rotated.
82    /// - The number of CIDs needed.
83    NeedIdentifiers(PathId, Instant, u64),
84    /// Retire a locally issued CID
85    ///
86    /// Stop routing connection ID for this sequence number to the connection
87    /// When `bool == true`, a new connection ID will be issued to peer
88    RetireConnectionId(Instant, PathId, u64, bool),
89}
90
91/// Protocol-level identifier for a connection.
92///
93/// Mainly useful for identifying this connection's packets on the wire with tools like Wireshark.
94#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
95#[cfg_attr(test, derive(test_strategy::Arbitrary))]
96pub struct ConnectionId {
97    /// length of CID
98    #[cfg_attr(test, strategy(1u8..=MAX_CID_SIZE as u8))]
99    len: u8,
100    /// CID in byte array
101    bytes: [u8; MAX_CID_SIZE],
102}
103
104impl ConnectionId {
105    /// Construct cid from byte array
106    pub fn new(bytes: &[u8]) -> Self {
107        debug_assert!(bytes.len() <= MAX_CID_SIZE);
108        let mut res = Self {
109            len: bytes.len() as u8,
110            bytes: [0; MAX_CID_SIZE],
111        };
112        res.bytes[..bytes.len()].copy_from_slice(bytes);
113        res
114    }
115
116    /// Constructs cid by reading `len` bytes from a `Buf`
117    ///
118    /// Callers need to assure that `buf.remaining() >= len`
119    pub fn from_buf(buf: &mut (impl Buf + ?Sized), len: usize) -> Self {
120        debug_assert!(len <= MAX_CID_SIZE);
121        let mut res = Self {
122            len: len as u8,
123            bytes: [0; MAX_CID_SIZE],
124        };
125        buf.copy_to_slice(&mut res[..len]);
126        res
127    }
128
129    pub(crate) fn len(&self) -> usize {
130        self.len as usize
131    }
132
133    /// Decode from long header format
134    pub(crate) fn decode_long(buf: &mut impl Buf) -> Option<Self> {
135        let len = buf.get::<u8>().ok()? as usize;
136        match len > MAX_CID_SIZE || buf.remaining() < len {
137            false => Some(Self::from_buf(buf, len)),
138            true => None,
139        }
140    }
141
142    /// Encode in long header format
143    pub(crate) fn encode_long(&self, buf: &mut impl BufMut) {
144        buf.put_u8(self.len() as u8);
145        buf.put_slice(self);
146    }
147}
148
149impl ::std::ops::Deref for ConnectionId {
150    type Target = [u8];
151    fn deref(&self) -> &[u8] {
152        &self.bytes[0..self.len as usize]
153    }
154}
155
156impl ::std::ops::DerefMut for ConnectionId {
157    fn deref_mut(&mut self) -> &mut [u8] {
158        &mut self.bytes[0..self.len as usize]
159    }
160}
161
162impl fmt::Debug for ConnectionId {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        self.bytes[0..self.len as usize].fmt(f)
165    }
166}
167
168impl fmt::Display for ConnectionId {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        for byte in self.iter() {
171            write!(f, "{byte:02x}")?;
172        }
173        Ok(())
174    }
175}
176
177/// Explicit congestion notification codepoint
178#[repr(u8)]
179#[derive(Debug, Copy, Clone, Eq, PartialEq)]
180pub enum EcnCodepoint {
181    /// The ECT(0) codepoint, indicating that an endpoint is ECN-capable
182    Ect0 = 0b10,
183    /// The ECT(1) codepoint, indicating that an endpoint is ECN-capable
184    Ect1 = 0b01,
185    /// The CE codepoint, signalling that congestion was experienced
186    Ce = 0b11,
187}
188
189impl EcnCodepoint {
190    /// Create new object from the given bits
191    pub fn from_bits(x: u8) -> Option<Self> {
192        use EcnCodepoint::*;
193        Some(match x & 0b11 {
194            0b10 => Ect0,
195            0b01 => Ect1,
196            0b11 => Ce,
197            _ => {
198                return None;
199            }
200        })
201    }
202
203    /// Returns whether the codepoint is a CE, signalling that congestion was experienced
204    pub fn is_ce(self) -> bool {
205        matches!(self, Self::Ce)
206    }
207}
208
209#[derive(Debug, Copy, Clone)]
210pub(crate) struct IssuedCid {
211    pub(crate) path_id: PathId,
212    pub(crate) sequence: u64,
213    pub(crate) id: ConnectionId,
214    pub(crate) reset_token: ResetToken,
215}