1#![cfg_attr(not(fuzzing), warn(missing_docs))]
16#![cfg_attr(test, allow(dead_code))]
17#![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 BytesSource, Chunk, Chunks, ClosedStream, Connection, ConnectionError, ConnectionStats,
48 Datagrams, Event, FinishError, FrameStats, PathStats, ReadError, ReadableError, RecvStream,
49 RttEstimator, SendDatagramError, SendStream, ShouldTransmit, StreamEvent, Streams, UdpStats,
50 WriteError, 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
99#[cfg(feature = "arbitrary")]
100use arbitrary::Arbitrary;
101
102#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
104pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
105#[cfg(all(target_family = "wasm", target_os = "unknown"))]
106pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
107
108#[cfg(fuzzing)]
109pub mod fuzzing {
110 pub use crate::connection::{Retransmits, State as ConnectionState, StreamsState};
111 pub use crate::frame::ResetStream;
112 pub use crate::packet::PartialDecode;
113 pub use crate::transport_parameters::TransportParameters;
114 pub use bytes::{BufMut, BytesMut};
115
116 #[cfg(feature = "arbitrary")]
117 use arbitrary::{Arbitrary, Result, Unstructured};
118
119 #[cfg(feature = "arbitrary")]
120 impl<'arbitrary> Arbitrary<'arbitrary> for TransportParameters {
121 fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
122 Ok(Self {
123 initial_max_streams_bidi: u.arbitrary()?,
124 initial_max_streams_uni: u.arbitrary()?,
125 ack_delay_exponent: u.arbitrary()?,
126 max_udp_payload_size: u.arbitrary()?,
127 ..Self::default()
128 })
129 }
130 }
131
132 #[derive(Debug)]
133 pub struct PacketParams {
134 pub local_cid_len: usize,
135 pub buf: BytesMut,
136 pub grease_quic_bit: bool,
137 }
138
139 #[cfg(feature = "arbitrary")]
140 impl<'arbitrary> Arbitrary<'arbitrary> for PacketParams {
141 fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
142 let local_cid_len: usize = u.int_in_range(0..=crate::MAX_CID_SIZE)?;
143 let bytes: Vec<u8> = Vec::arbitrary(u)?;
144 let mut buf = BytesMut::new();
145 buf.put_slice(&bytes[..]);
146 Ok(Self {
147 local_cid_len,
148 buf,
149 grease_quic_bit: bool::arbitrary(u)?,
150 })
151 }
152 }
153}
154
155pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
157 0x00000001,
158 0xff00_001d,
159 0xff00_001e,
160 0xff00_001f,
161 0xff00_0020,
162 0xff00_0021,
163 0xff00_0022,
164];
165
166#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
168#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
169pub enum Side {
170 Client = 0,
172 Server = 1,
174}
175
176impl Side {
177 #[inline]
178 pub fn is_client(self) -> bool {
180 self == Self::Client
181 }
182
183 #[inline]
184 pub fn is_server(self) -> bool {
186 self == Self::Server
187 }
188}
189
190impl ops::Not for Side {
191 type Output = Self;
192 fn not(self) -> Self {
193 match self {
194 Self::Client => Self::Server,
195 Self::Server => Self::Client,
196 }
197 }
198}
199
200#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
202#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
203pub enum Dir {
204 Bi = 0,
206 Uni = 1,
208}
209
210impl Dir {
211 fn iter() -> impl Iterator<Item = Self> {
212 [Self::Bi, Self::Uni].iter().cloned()
213 }
214}
215
216impl fmt::Display for Dir {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 use Dir::*;
219 f.pad(match *self {
220 Bi => "bidirectional",
221 Uni => "unidirectional",
222 })
223 }
224}
225
226#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
228#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
229pub struct StreamId(u64);
230
231impl fmt::Display for StreamId {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 let initiator = match self.initiator() {
234 Side::Client => "client",
235 Side::Server => "server",
236 };
237 let dir = match self.dir() {
238 Dir::Uni => "uni",
239 Dir::Bi => "bi",
240 };
241 write!(
242 f,
243 "{} {}directional stream {}",
244 initiator,
245 dir,
246 self.index()
247 )
248 }
249}
250
251impl StreamId {
252 pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
254 Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
255 }
256 pub fn initiator(self) -> Side {
258 if self.0 & 0x1 == 0 {
259 Side::Client
260 } else {
261 Side::Server
262 }
263 }
264 pub fn dir(self) -> Dir {
266 if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
267 }
268 pub fn index(self) -> u64 {
270 self.0 >> 2
271 }
272}
273
274impl From<StreamId> for VarInt {
275 fn from(x: StreamId) -> Self {
276 unsafe { Self::from_u64_unchecked(x.0) }
277 }
278}
279
280impl From<VarInt> for StreamId {
281 fn from(v: VarInt) -> Self {
282 Self(v.0)
283 }
284}
285
286impl From<StreamId> for u64 {
287 fn from(x: StreamId) -> Self {
288 x.0
289 }
290}
291
292impl coding::Codec for StreamId {
293 fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
294 VarInt::decode(buf).map(|x| Self(x.into_inner()))
295 }
296 fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
297 VarInt::from_u64(self.0).unwrap().encode(buf);
298 }
299}
300
301#[derive(Debug)]
303#[must_use]
304pub struct Transmit {
305 pub destination: SocketAddr,
307 pub ecn: Option<EcnCodepoint>,
309 pub size: usize,
311 pub segment_size: Option<usize>,
314 pub src_ip: Option<IpAddr>,
316}
317
318const LOC_CID_COUNT: u64 = 8;
324const RESET_TOKEN_SIZE: usize = 16;
325const MAX_CID_SIZE: usize = 20;
326const MIN_INITIAL_SIZE: u16 = 1200;
327const INITIAL_MTU: u16 = 1200;
329const MAX_UDP_PAYLOAD: u16 = 65527;
330const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
331const MAX_STREAM_COUNT: u64 = 1 << 60;