iroh_quinn_proto/
shared.rs

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