ant_quic/
lib.rs

1//! Low-level protocol logic for the QUIC protoocol
2//!
3//! quinn-proto contains a fully deterministic implementation of QUIC protocol logic. It contains
4//! no networking code and does not get any relevant timestamps from the operating system. Most
5//! users may want to use the futures-based quinn API instead.
6//!
7//! The quinn-proto API might be of interest if you want to use it from a C or C++ project
8//! through C bindings or if you want to use a different event loop than the one tokio provides.
9//!
10//! The most important types are `Endpoint`, which conceptually represents the protocol state for
11//! a single socket and mostly manages configuration and dispatches incoming datagrams to the
12//! related `Connection`. `Connection` types contain the bulk of the protocol logic related to
13//! managing a single connection and all the related state (such as streams).
14
15#![cfg_attr(not(fuzzing), warn(missing_docs))]
16#![cfg_attr(test, allow(dead_code))]
17// Fixes welcome:
18#![warn(unreachable_pub)]
19#![allow(clippy::cognitive_complexity)]
20#![allow(clippy::too_many_arguments)]
21#![warn(clippy::use_self)]
22
23use std::{
24    fmt,
25    net::{IpAddr, SocketAddr},
26    ops,
27};
28
29mod cid_queue;
30pub mod coding;
31mod constant_time;
32mod range_set;
33#[cfg(all(test, any(feature = "rustls-aws-lc-rs", feature = "rustls-ring")))]
34mod tests;
35pub mod transport_parameters;
36mod varint;
37
38pub use varint::{VarInt, VarIntBoundsExceeded};
39
40#[cfg(feature = "bloom")]
41mod bloom_token_log;
42#[cfg(feature = "bloom")]
43pub use bloom_token_log::BloomTokenLog;
44
45mod connection;
46pub use crate::connection::{
47    Chunk, Chunks, ClosedStream, Connection, ConnectionError, ConnectionStats, Datagrams, Event,
48    FinishError, FrameStats, PathStats, ReadError, ReadableError, RecvStream, RttEstimator,
49    SendDatagramError, SendStream, ShouldTransmit, StreamEvent, Streams, UdpStats, WriteError,
50    Written,
51};
52
53#[cfg(feature = "rustls")]
54pub use rustls;
55
56mod config;
57pub use config::{
58    AckFrequencyConfig, ClientConfig, ConfigError, EndpointConfig, IdleTimeout, MtuDiscoveryConfig,
59    ServerConfig, StdSystemTime, TimeSource, TransportConfig, ValidationTokenConfig,
60};
61
62pub mod crypto;
63
64mod frame;
65use crate::frame::Frame;
66pub use crate::frame::{ApplicationClose, ConnectionClose, Datagram, FrameType};
67
68mod endpoint;
69pub use crate::endpoint::{
70    AcceptError, ConnectError, ConnectionHandle, DatagramEvent, Endpoint, Incoming, RetryError,
71};
72
73mod packet;
74pub use packet::{
75    ConnectionIdParser, FixedLengthConnectionIdParser, LongType, PacketDecodeError, PartialDecode,
76    ProtectedHeader, ProtectedInitialHeader,
77};
78
79mod shared;
80pub use crate::shared::{ConnectionEvent, ConnectionId, EcnCodepoint, EndpointEvent};
81
82mod transport_error;
83pub use crate::transport_error::{Code as TransportErrorCode, Error as TransportError};
84
85pub mod congestion;
86
87mod cid_generator;
88pub use crate::cid_generator::{
89    ConnectionIdGenerator, HashedConnectionIdGenerator, InvalidCid, RandomConnectionIdGenerator,
90};
91
92mod token;
93use token::ResetToken;
94pub use token::{NoneTokenLog, NoneTokenStore, TokenLog, TokenReuseError, TokenStore};
95
96mod token_memory_cache;
97pub use token_memory_cache::TokenMemoryCache;
98
99mod candidate_discovery;
100pub use candidate_discovery::{
101    CandidateDiscoveryManager, DiscoveryConfig, DiscoveryEvent, DiscoveryError,
102    NetworkInterface, ValidatedCandidate,
103};
104
105mod connection_establishment_simple;
106pub use connection_establishment_simple::{
107    SimpleConnectionEstablishmentManager, SimpleEstablishmentConfig,
108    SimpleConnectionEvent, SimpleConnectionStatus,
109};
110
111pub mod nat_traversal_api;
112pub use nat_traversal_api::{
113    NatTraversalEndpoint, NatTraversalConfig, EndpointRole, PeerId, BootstrapNode,
114    CandidateAddress, NatTraversalEvent, NatTraversalError, NatTraversalStatistics,
115};
116
117// Re-export NAT traversal types from connection module
118pub use connection::nat_traversal::{CandidateSource, CandidateState, NatTraversalRole};
119
120#[cfg(feature = "arbitrary")]
121use arbitrary::Arbitrary;
122
123// Deal with time
124#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
125pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
126#[cfg(all(target_family = "wasm", target_os = "unknown"))]
127pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
128
129#[cfg(fuzzing)]
130pub mod fuzzing {
131    pub use crate::connection::{Retransmits, State as ConnectionState, StreamsState};
132    pub use crate::frame::ResetStream;
133    pub use crate::packet::PartialDecode;
134    pub use crate::transport_parameters::TransportParameters;
135    pub use bytes::{BufMut, BytesMut};
136
137    #[cfg(feature = "arbitrary")]
138    use arbitrary::{Arbitrary, Result, Unstructured};
139
140    #[cfg(feature = "arbitrary")]
141    impl<'arbitrary> Arbitrary<'arbitrary> for TransportParameters {
142        fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
143            Ok(Self {
144                initial_max_streams_bidi: u.arbitrary()?,
145                initial_max_streams_uni: u.arbitrary()?,
146                ack_delay_exponent: u.arbitrary()?,
147                max_udp_payload_size: u.arbitrary()?,
148                ..Self::default()
149            })
150        }
151    }
152
153    #[derive(Debug)]
154    pub struct PacketParams {
155        pub local_cid_len: usize,
156        pub buf: BytesMut,
157        pub grease_quic_bit: bool,
158    }
159
160    #[cfg(feature = "arbitrary")]
161    impl<'arbitrary> Arbitrary<'arbitrary> for PacketParams {
162        fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
163            let local_cid_len: usize = u.int_in_range(0..=crate::MAX_CID_SIZE)?;
164            let bytes: Vec<u8> = Vec::arbitrary(u)?;
165            let mut buf = BytesMut::new();
166            buf.put_slice(&bytes[..]);
167            Ok(Self {
168                local_cid_len,
169                buf,
170                grease_quic_bit: bool::arbitrary(u)?,
171            })
172        }
173    }
174}
175
176/// The QUIC protocol version implemented.
177pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
178    0x00000001,
179    0xff00_001d,
180    0xff00_001e,
181    0xff00_001f,
182    0xff00_0020,
183    0xff00_0021,
184    0xff00_0022,
185];
186
187/// Whether an endpoint was the initiator of a connection
188#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
189#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
190pub enum Side {
191    /// The initiator of a connection
192    Client = 0,
193    /// The acceptor of a connection
194    Server = 1,
195}
196
197impl Side {
198    #[inline]
199    /// Shorthand for `self == Side::Client`
200    pub fn is_client(self) -> bool {
201        self == Self::Client
202    }
203
204    #[inline]
205    /// Shorthand for `self == Side::Server`
206    pub fn is_server(self) -> bool {
207        self == Self::Server
208    }
209}
210
211impl ops::Not for Side {
212    type Output = Self;
213    fn not(self) -> Self {
214        match self {
215            Self::Client => Self::Server,
216            Self::Server => Self::Client,
217        }
218    }
219}
220
221/// Whether a stream communicates data in both directions or only from the initiator
222#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
223#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
224pub enum Dir {
225    /// Data flows in both directions
226    Bi = 0,
227    /// Data flows only from the stream's initiator
228    Uni = 1,
229}
230
231impl Dir {
232    fn iter() -> impl Iterator<Item = Self> {
233        [Self::Bi, Self::Uni].iter().cloned()
234    }
235}
236
237impl fmt::Display for Dir {
238    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239        use Dir::*;
240        f.pad(match *self {
241            Bi => "bidirectional",
242            Uni => "unidirectional",
243        })
244    }
245}
246
247/// Identifier for a stream within a particular connection
248#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
249#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
250pub struct StreamId(u64);
251
252impl fmt::Display for StreamId {
253    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254        let initiator = match self.initiator() {
255            Side::Client => "client",
256            Side::Server => "server",
257        };
258        let dir = match self.dir() {
259            Dir::Uni => "uni",
260            Dir::Bi => "bi",
261        };
262        write!(
263            f,
264            "{} {}directional stream {}",
265            initiator,
266            dir,
267            self.index()
268        )
269    }
270}
271
272impl StreamId {
273    /// Create a new StreamId
274    pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
275        Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
276    }
277    /// Which side of a connection initiated the stream
278    pub fn initiator(self) -> Side {
279        if self.0 & 0x1 == 0 {
280            Side::Client
281        } else {
282            Side::Server
283        }
284    }
285    /// Which directions data flows in
286    pub fn dir(self) -> Dir {
287        if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
288    }
289    /// Distinguishes streams of the same initiator and directionality
290    pub fn index(self) -> u64 {
291        self.0 >> 2
292    }
293}
294
295impl From<StreamId> for VarInt {
296    fn from(x: StreamId) -> Self {
297        unsafe { Self::from_u64_unchecked(x.0) }
298    }
299}
300
301impl From<VarInt> for StreamId {
302    fn from(v: VarInt) -> Self {
303        Self(v.0)
304    }
305}
306
307impl From<StreamId> for u64 {
308    fn from(x: StreamId) -> Self {
309        x.0
310    }
311}
312
313impl coding::Codec for StreamId {
314    fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
315        VarInt::decode(buf).map(|x| Self(x.into_inner()))
316    }
317    fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
318        VarInt::from_u64(self.0).unwrap().encode(buf);
319    }
320}
321
322/// An outgoing packet
323#[derive(Debug)]
324#[must_use]
325pub struct Transmit {
326    /// The socket this datagram should be sent to
327    pub destination: SocketAddr,
328    /// Explicit congestion notification bits to set on the packet
329    pub ecn: Option<EcnCodepoint>,
330    /// Amount of data written to the caller-supplied buffer
331    pub size: usize,
332    /// The segment size if this transmission contains multiple datagrams.
333    /// This is `None` if the transmit only contains a single datagram
334    pub segment_size: Option<usize>,
335    /// Optional source IP address for the datagram
336    pub src_ip: Option<IpAddr>,
337}
338
339//
340// Useful internal constants
341//
342
343/// The maximum number of CIDs we bother to issue per connection
344const LOC_CID_COUNT: u64 = 8;
345const RESET_TOKEN_SIZE: usize = 16;
346const MAX_CID_SIZE: usize = 20;
347const MIN_INITIAL_SIZE: u16 = 1200;
348/// <https://www.rfc-editor.org/rfc/rfc9000.html#name-datagram-size>
349const INITIAL_MTU: u16 = 1200;
350const MAX_UDP_PAYLOAD: u16 = 65527;
351const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
352/// Maximum number of streams that can be uniquely identified by a stream ID
353const MAX_STREAM_COUNT: u64 = 1 << 60;