ant_quic/
shared.rs

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