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
40mod connection;
41pub use crate::connection::{
42 BytesSource, Chunk, Chunks, ClosedStream, Connection, ConnectionError, ConnectionStats,
43 Datagrams, Event, FinishError, FrameStats, PathStats, ReadError, ReadableError, RecvStream,
44 RttEstimator, SendDatagramError, SendStream, ShouldTransmit, StreamEvent, Streams, UdpStats,
45 WriteError, Written,
46};
47
48#[cfg(feature = "rustls")]
49pub use rustls;
50
51mod config;
52pub use config::{
53 AckFrequencyConfig, ClientConfig, ConfigError, EndpointConfig, IdleTimeout, MtuDiscoveryConfig,
54 ServerConfig, StdSystemTime, TimeSource, TransportConfig, ValidationTokenConfig,
55};
56
57pub mod crypto;
58
59mod frame;
60use crate::frame::Frame;
61pub use crate::frame::{ApplicationClose, ConnectionClose, Datagram, FrameType};
62
63mod endpoint;
64pub use crate::endpoint::{
65 AcceptError, ConnectError, ConnectionHandle, DatagramEvent, Endpoint, Incoming, RetryError,
66};
67
68mod packet;
69pub use packet::{
70 ConnectionIdParser, FixedLengthConnectionIdParser, LongType, PacketDecodeError, PartialDecode,
71 ProtectedHeader, ProtectedInitialHeader,
72};
73
74mod shared;
75pub use crate::shared::{ConnectionEvent, ConnectionId, EcnCodepoint, EndpointEvent};
76
77mod transport_error;
78pub use crate::transport_error::{Code as TransportErrorCode, Error as TransportError};
79
80pub mod congestion;
81
82mod cid_generator;
83pub use crate::cid_generator::{
84 ConnectionIdGenerator, HashedConnectionIdGenerator, InvalidCid, RandomConnectionIdGenerator,
85};
86
87mod token;
88use token::ResetToken;
89pub use token::{NoneTokenLog, NoneTokenStore, TokenLog, TokenReuseError, TokenStore};
90
91#[cfg(feature = "arbitrary")]
92use arbitrary::Arbitrary;
93
94#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
96pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
97#[cfg(all(target_family = "wasm", target_os = "unknown"))]
98pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
99
100#[cfg(fuzzing)]
101pub mod fuzzing {
102 pub use crate::connection::{Retransmits, State as ConnectionState, StreamsState};
103 pub use crate::frame::ResetStream;
104 pub use crate::packet::PartialDecode;
105 pub use crate::transport_parameters::TransportParameters;
106 pub use bytes::{BufMut, BytesMut};
107
108 #[cfg(feature = "arbitrary")]
109 use arbitrary::{Arbitrary, Result, Unstructured};
110
111 #[cfg(feature = "arbitrary")]
112 impl<'arbitrary> Arbitrary<'arbitrary> for TransportParameters {
113 fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
114 Ok(Self {
115 initial_max_streams_bidi: u.arbitrary()?,
116 initial_max_streams_uni: u.arbitrary()?,
117 ack_delay_exponent: u.arbitrary()?,
118 max_udp_payload_size: u.arbitrary()?,
119 ..Self::default()
120 })
121 }
122 }
123
124 #[derive(Debug)]
125 pub struct PacketParams {
126 pub local_cid_len: usize,
127 pub buf: BytesMut,
128 pub grease_quic_bit: bool,
129 }
130
131 #[cfg(feature = "arbitrary")]
132 impl<'arbitrary> Arbitrary<'arbitrary> for PacketParams {
133 fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
134 let local_cid_len: usize = u.int_in_range(0..=crate::MAX_CID_SIZE)?;
135 let bytes: Vec<u8> = Vec::arbitrary(u)?;
136 let mut buf = BytesMut::new();
137 buf.put_slice(&bytes[..]);
138 Ok(Self {
139 local_cid_len,
140 buf,
141 grease_quic_bit: bool::arbitrary(u)?,
142 })
143 }
144 }
145}
146
147pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
149 0x00000001,
150 0xff00_001d,
151 0xff00_001e,
152 0xff00_001f,
153 0xff00_0020,
154 0xff00_0021,
155 0xff00_0022,
156];
157
158#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
160#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
161pub enum Side {
162 Client = 0,
164 Server = 1,
166}
167
168impl Side {
169 #[inline]
170 pub fn is_client(self) -> bool {
172 self == Self::Client
173 }
174
175 #[inline]
176 pub fn is_server(self) -> bool {
178 self == Self::Server
179 }
180}
181
182impl ops::Not for Side {
183 type Output = Self;
184 fn not(self) -> Self {
185 match self {
186 Self::Client => Self::Server,
187 Self::Server => Self::Client,
188 }
189 }
190}
191
192#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
194#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
195pub enum Dir {
196 Bi = 0,
198 Uni = 1,
200}
201
202impl Dir {
203 fn iter() -> impl Iterator<Item = Self> {
204 [Self::Bi, Self::Uni].iter().cloned()
205 }
206}
207
208impl fmt::Display for Dir {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 use Dir::*;
211 f.pad(match *self {
212 Bi => "bidirectional",
213 Uni => "unidirectional",
214 })
215 }
216}
217
218#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
220#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
221pub struct StreamId(u64);
222
223impl fmt::Display for StreamId {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 let initiator = match self.initiator() {
226 Side::Client => "client",
227 Side::Server => "server",
228 };
229 let dir = match self.dir() {
230 Dir::Uni => "uni",
231 Dir::Bi => "bi",
232 };
233 write!(
234 f,
235 "{} {}directional stream {}",
236 initiator,
237 dir,
238 self.index()
239 )
240 }
241}
242
243impl StreamId {
244 pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
246 Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
247 }
248 pub fn initiator(self) -> Side {
250 if self.0 & 0x1 == 0 {
251 Side::Client
252 } else {
253 Side::Server
254 }
255 }
256 pub fn dir(self) -> Dir {
258 if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
259 }
260 pub fn index(self) -> u64 {
262 self.0 >> 2
263 }
264}
265
266impl From<StreamId> for VarInt {
267 fn from(x: StreamId) -> Self {
268 unsafe { Self::from_u64_unchecked(x.0) }
269 }
270}
271
272impl From<VarInt> for StreamId {
273 fn from(v: VarInt) -> Self {
274 Self(v.0)
275 }
276}
277
278impl From<StreamId> for u64 {
279 fn from(x: StreamId) -> Self {
280 x.0
281 }
282}
283
284impl coding::Codec for StreamId {
285 fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
286 VarInt::decode(buf).map(|x| Self(x.into_inner()))
287 }
288 fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
289 VarInt::from_u64(self.0).unwrap().encode(buf);
290 }
291}
292
293#[derive(Debug)]
295#[must_use]
296pub struct Transmit {
297 pub destination: SocketAddr,
299 pub ecn: Option<EcnCodepoint>,
301 pub size: usize,
303 pub segment_size: Option<usize>,
306 pub src_ip: Option<IpAddr>,
308}
309
310const LOC_CID_COUNT: u64 = 8;
316const RESET_TOKEN_SIZE: usize = 16;
317const MAX_CID_SIZE: usize = 20;
318const MIN_INITIAL_SIZE: u16 = 1200;
319const INITIAL_MTU: u16 = 1200;
321const MAX_UDP_PAYLOAD: u16 = 65527;
322const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
323const MAX_STREAM_COUNT: u64 = 1 << 60;