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