1#![cfg_attr(not(fuzzing), warn(missing_docs))]
16#![cfg_attr(test, allow(dead_code))]
17#![allow(clippy::too_many_arguments)]
19#![warn(unreachable_pub)]
20#![warn(clippy::use_self)]
21
22use std::{
23 fmt,
24 net::{IpAddr, SocketAddr},
25 ops,
26};
27
28mod cid_queue;
29pub mod coding;
30mod constant_time;
31mod range_set;
32#[cfg(all(test, feature = "rustls", any(feature = "aws-lc-rs", feature = "ring")))]
33mod tests;
34pub mod transport_parameters;
35mod varint;
36
37pub use varint::{VarInt, VarIntBoundsExceeded};
38
39#[cfg(feature = "bloom")]
40mod bloom_token_log;
41#[cfg(feature = "bloom")]
42pub use bloom_token_log::BloomTokenLog;
43
44pub(crate) mod connection;
45pub use crate::connection::{
46 Chunk, Chunks, ClosePathError, ClosedPath, ClosedStream, Connection, ConnectionError,
47 ConnectionStats, Datagrams, Event, FinishError, FrameStats, MultipathNotNegotiated,
48 NetworkChangeHint, PathAbandonReason, PathError, PathEvent, PathId, PathStats, PathStatus,
49 ReadError, ReadableError, RecvStream, RttEstimator, SendDatagramError, SendStream,
50 SetPathStatusError, ShouldTransmit, StreamEvent, Streams, UdpStats, WriteError, Written,
51};
52#[cfg(test)]
53use test_strategy::Arbitrary;
54
55#[cfg(feature = "rustls")]
56pub use rustls;
57
58mod config;
59#[cfg(doc)]
60pub use config::DEFAULT_CONCURRENT_MULTIPATH_PATHS_WHEN_ENABLED;
61pub use config::{
62 AckFrequencyConfig, ClientConfig, ConfigError, EndpointConfig, IdleTimeout, MtuDiscoveryConfig,
63 ServerConfig, StdSystemTime, TimeSource, TransportConfig, ValidationTokenConfig,
64};
65#[cfg(feature = "qlog")]
66pub use config::{QlogConfig, QlogFactory, QlogFileFactory};
67
68pub mod crypto;
69
70mod frame;
71pub use crate::frame::{
72 ApplicationClose, ConnectionClose, Datagram, DatagramInfo, FrameType, InvalidFrameId,
73 MaybeFrame, StreamInfo,
74};
75use crate::{
76 coding::{Decodable, Encodable},
77 frame::Frame,
78};
79
80mod endpoint;
81pub use crate::endpoint::{
82 AcceptError, ConnectError, ConnectionHandle, DatagramEvent, DecryptedInitial, Endpoint,
83 Incoming, IncomingAlpns, RetryError,
84};
85
86mod packet;
87pub use packet::{
88 ConnectionIdParser, FixedLengthConnectionIdParser, LongType, PacketDecodeError, PartialDecode,
89 ProtectedHeader, ProtectedInitialHeader,
90};
91
92mod shared;
93pub use crate::shared::{ConnectionEvent, ConnectionId, EcnCodepoint, EndpointEvent};
94
95mod transport_error;
96pub use crate::transport_error::{Code as TransportErrorCode, Error as TransportError};
97
98pub mod congestion;
99
100mod cid_generator;
101pub use crate::cid_generator::{
102 ConnectionIdGenerator, HashedConnectionIdGenerator, InvalidCid, RandomConnectionIdGenerator,
103};
104
105mod token;
106use token::ResetToken;
107pub use token::{NoneTokenLog, NoneTokenStore, TokenLog, TokenReuseError, TokenStore};
108
109mod address_discovery;
110
111mod token_memory_cache;
112pub use token_memory_cache::TokenMemoryCache;
113
114pub mod n0_nat_traversal;
115
116#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
118pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
119#[cfg(all(target_family = "wasm", target_os = "unknown"))]
120pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
121
122#[cfg(feature = "bench")]
123pub mod bench_exports {
124 pub use crate::connection::send_buffer::send_buffer_benches;
126}
127
128#[cfg(fuzzing)]
129pub mod fuzzing {
130 pub use crate::connection::{Retransmits, State as ConnectionState, StreamsState};
131 pub use crate::frame::ResetStream;
132 pub use crate::packet::PartialDecode;
133 pub use crate::transport_parameters::TransportParameters;
134 pub use bytes::{BufMut, BytesMut};
135
136 #[cfg(feature = "arbitrary")]
137 use arbitrary::{Arbitrary, Result, Unstructured};
138
139 #[cfg(feature = "arbitrary")]
140 impl<'arbitrary> Arbitrary<'arbitrary> for TransportParameters {
141 fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
142 Ok(Self {
143 initial_max_streams_bidi: u.arbitrary()?,
144 initial_max_streams_uni: u.arbitrary()?,
145 ack_delay_exponent: u.arbitrary()?,
146 max_udp_payload_size: u.arbitrary()?,
147 ..Self::default()
148 })
149 }
150 }
151
152 #[derive(Debug)]
153 pub struct PacketParams {
154 pub local_cid_len: usize,
155 pub buf: BytesMut,
156 pub grease_quic_bit: bool,
157 }
158
159 #[cfg(feature = "arbitrary")]
160 impl<'arbitrary> Arbitrary<'arbitrary> for PacketParams {
161 fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
162 let local_cid_len: usize = u.int_in_range(0..=crate::MAX_CID_SIZE)?;
163 let bytes: Vec<u8> = Vec::arbitrary(u)?;
164 let mut buf = BytesMut::new();
165 buf.put_slice(&bytes[..]);
166 Ok(Self {
167 local_cid_len,
168 buf,
169 grease_quic_bit: bool::arbitrary(u)?,
170 })
171 }
172 }
173}
174
175pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
177 0x00000001,
178 0xff00_001d,
179 0xff00_001e,
180 0xff00_001f,
181 0xff00_0020,
182 0xff00_0021,
183 0xff00_0022,
184];
185
186#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
188#[cfg_attr(test, derive(Arbitrary))]
189#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
190pub enum Side {
191 Client = 0,
193 Server = 1,
195}
196
197impl Side {
198 #[inline]
199 pub fn is_client(self) -> bool {
201 self == Self::Client
202 }
203
204 #[inline]
205 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#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
223#[cfg_attr(test, derive(Arbitrary))]
224#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
225pub enum Dir {
226 Bi = 0,
228 Uni = 1,
230}
231
232impl Dir {
233 fn iter() -> impl Iterator<Item = Self> {
234 [Self::Bi, Self::Uni].iter().cloned()
235 }
236}
237
238impl fmt::Display for Dir {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 use Dir::*;
241 f.pad(match *self {
242 Bi => "bidirectional",
243 Uni => "unidirectional",
244 })
245 }
246}
247
248#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
250#[cfg_attr(test, derive(Arbitrary))]
251pub struct StreamId(#[cfg_attr(test, strategy(crate::varint::varint_u64()))] u64);
252
253impl fmt::Display for StreamId {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 let initiator = match self.initiator() {
256 Side::Client => "client",
257 Side::Server => "server",
258 };
259 let dir = match self.dir() {
260 Dir::Uni => "uni",
261 Dir::Bi => "bi",
262 };
263 write!(
264 f,
265 "{} {}directional stream {}",
266 initiator,
267 dir,
268 self.index()
269 )
270 }
271}
272
273impl StreamId {
274 pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
276 Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
277 }
278 pub fn initiator(self) -> Side {
280 if self.0 & 0x1 == 0 {
281 Side::Client
282 } else {
283 Side::Server
284 }
285 }
286 pub fn dir(self) -> Dir {
288 if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
289 }
290 pub fn index(self) -> u64 {
292 self.0 >> 2
293 }
294}
295
296impl From<StreamId> for VarInt {
297 fn from(x: StreamId) -> Self {
298 unsafe { Self::from_u64_unchecked(x.0) }
299 }
300}
301
302impl From<VarInt> for StreamId {
303 fn from(v: VarInt) -> Self {
304 Self(v.0)
305 }
306}
307
308impl From<StreamId> for u64 {
309 fn from(x: StreamId) -> Self {
310 x.0
311 }
312}
313
314impl Decodable for StreamId {
315 fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
316 VarInt::decode(buf).map(|x| Self(x.into_inner()))
317 }
318}
319
320impl Encodable for StreamId {
321 fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
322 VarInt::from_u64(self.0).unwrap().encode(buf);
323 }
324}
325
326#[cfg(feature = "arbitrary")]
327impl<'arbitrary> arbitrary::Arbitrary<'arbitrary> for StreamId {
328 fn arbitrary(u: &mut arbitrary::Unstructured<'arbitrary>) -> arbitrary::Result<Self> {
329 Ok(VarInt::arbitrary(u)?.into())
330 }
331}
332
333#[derive(Debug)]
335#[must_use]
336pub struct Transmit {
337 pub destination: SocketAddr,
339 pub ecn: Option<EcnCodepoint>,
341 pub size: usize,
343 pub segment_size: Option<usize>,
346 pub src_ip: Option<IpAddr>,
348}
349
350const LOCAL_CID_COUNT: u64 = 12;
356const RESET_TOKEN_SIZE: usize = 16;
357const MAX_CID_SIZE: usize = 20;
358const MIN_INITIAL_SIZE: u16 = 1200;
359const INITIAL_MTU: u16 = 1200;
361const MAX_UDP_PAYLOAD: u16 = 65527;
362const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
363const MAX_STREAM_COUNT: u64 = 1 << 60;
365
366#[derive(Hash, Eq, PartialEq, Copy, Clone)]
372pub struct FourTuple {
373 pub remote: SocketAddr,
375 pub local_ip: Option<IpAddr>,
381}
382
383impl FourTuple {
384 pub fn is_probably_same_path(&self, other: &Self) -> bool {
395 self.remote == other.remote && (self.local_ip.is_none() || self.local_ip == other.local_ip)
396 }
397
398 pub fn update_local_if_same_remote(&mut self, other: &Self) -> bool {
405 if self.remote != other.remote {
406 return false;
407 }
408 if self.local_ip.is_some() && self.local_ip != other.local_ip {
409 return false;
410 }
411 self.local_ip = other.local_ip;
412 true
413 }
414}
415
416impl fmt::Display for FourTuple {
417 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418 f.write_str("(local: ")?;
419 if let Some(local_ip) = &self.local_ip {
420 local_ip.fmt(f)?;
421 f.write_str(", ")?;
422 } else {
423 f.write_str("<unspecified>, ")?;
424 }
425 f.write_str("remote: ")?;
426 self.remote.fmt(f)?;
427 f.write_str(")")
428 }
429}
430
431impl fmt::Debug for FourTuple {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 fmt::Display::fmt(&self, f)
434 }
435}