#![cfg_attr(not(fuzzing), warn(missing_docs))]
#![cfg_attr(test, allow(dead_code))]
#![allow(clippy::too_many_arguments)]
#![warn(unreachable_pub)]
#![warn(clippy::use_self)]
use std::{
fmt,
net::{IpAddr, SocketAddr},
ops,
};
mod cid_queue;
pub mod coding;
mod constant_time;
mod range_set;
#[cfg(all(test, feature = "rustls", any(feature = "aws-lc-rs", feature = "ring")))]
mod tests;
pub mod transport_parameters;
mod varint;
pub use varint::{VarInt, VarIntBoundsExceeded};
#[cfg(feature = "bloom")]
mod bloom_token_log;
#[cfg(feature = "bloom")]
pub use bloom_token_log::BloomTokenLog;
pub(crate) mod connection;
pub use crate::connection::{
Chunk, Chunks, ClosePathError, ClosedPath, ClosedStream, Connection, ConnectionError,
ConnectionStats, Datagrams, Event, FinishError, FrameStats, MultipathNotNegotiated,
NetworkChangeHint, PathAbandonReason, PathError, PathEvent, PathId, PathStats, PathStatus,
ReadError, ReadableError, RecvStream, RttEstimator, SendDatagramError, SendStream,
SetPathStatusError, ShouldTransmit, StreamEvent, Streams, UdpStats, WriteError, Written,
};
#[cfg(test)]
use test_strategy::Arbitrary;
#[cfg(feature = "rustls")]
pub use rustls;
mod config;
#[cfg(doc)]
pub use config::DEFAULT_CONCURRENT_MULTIPATH_PATHS_WHEN_ENABLED;
pub use config::{
AckFrequencyConfig, ClientConfig, ConfigError, EndpointConfig, IdleTimeout, MtuDiscoveryConfig,
ServerConfig, StdSystemTime, TimeSource, TransportConfig, ValidationTokenConfig,
};
#[cfg(feature = "qlog")]
pub use config::{QlogConfig, QlogFactory, QlogFileFactory};
pub mod crypto;
mod frame;
pub use crate::frame::{
ApplicationClose, ConnectionClose, Datagram, DatagramInfo, FrameType, InvalidFrameId,
MaybeFrame, StreamInfo,
};
use crate::{
coding::{Decodable, Encodable},
frame::Frame,
};
mod endpoint;
pub use crate::endpoint::{
AcceptError, ConnectError, ConnectionHandle, DatagramEvent, DecryptedInitial, Endpoint,
Incoming, IncomingAlpns, RetryError,
};
mod packet;
pub use packet::{
ConnectionIdParser, FixedLengthConnectionIdParser, LongType, PacketDecodeError, PartialDecode,
ProtectedHeader, ProtectedInitialHeader,
};
mod shared;
pub use crate::shared::{ConnectionEvent, ConnectionId, EcnCodepoint, EndpointEvent};
mod transport_error;
pub use crate::transport_error::{Code as TransportErrorCode, Error as TransportError};
pub mod congestion;
mod cid_generator;
pub use crate::cid_generator::{
ConnectionIdGenerator, HashedConnectionIdGenerator, InvalidCid, RandomConnectionIdGenerator,
};
mod token;
use token::ResetToken;
pub use token::{NoneTokenLog, NoneTokenStore, TokenLog, TokenReuseError, TokenStore};
mod address_discovery;
mod token_memory_cache;
pub use token_memory_cache::TokenMemoryCache;
pub mod n0_nat_traversal;
#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
#[cfg(feature = "bench")]
pub mod bench_exports {
pub use crate::connection::send_buffer::send_buffer_benches;
}
#[cfg(fuzzing)]
pub mod fuzzing {
pub use crate::connection::{Retransmits, State as ConnectionState, StreamsState};
pub use crate::frame::ResetStream;
pub use crate::packet::PartialDecode;
pub use crate::transport_parameters::TransportParameters;
pub use bytes::{BufMut, BytesMut};
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Result, Unstructured};
#[cfg(feature = "arbitrary")]
impl<'arbitrary> Arbitrary<'arbitrary> for TransportParameters {
fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
Ok(Self {
initial_max_streams_bidi: u.arbitrary()?,
initial_max_streams_uni: u.arbitrary()?,
ack_delay_exponent: u.arbitrary()?,
max_udp_payload_size: u.arbitrary()?,
..Self::default()
})
}
}
#[derive(Debug)]
pub struct PacketParams {
pub local_cid_len: usize,
pub buf: BytesMut,
pub grease_quic_bit: bool,
}
#[cfg(feature = "arbitrary")]
impl<'arbitrary> Arbitrary<'arbitrary> for PacketParams {
fn arbitrary(u: &mut Unstructured<'arbitrary>) -> Result<Self> {
let local_cid_len: usize = u.int_in_range(0..=crate::MAX_CID_SIZE)?;
let bytes: Vec<u8> = Vec::arbitrary(u)?;
let mut buf = BytesMut::new();
buf.put_slice(&bytes[..]);
Ok(Self {
local_cid_len,
buf,
grease_quic_bit: bool::arbitrary(u)?,
})
}
}
}
pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
0x00000001,
0xff00_001d,
0xff00_001e,
0xff00_001f,
0xff00_0020,
0xff00_0021,
0xff00_0022,
];
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(test, derive(Arbitrary))]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Side {
Client = 0,
Server = 1,
}
impl Side {
#[inline]
pub fn is_client(self) -> bool {
self == Self::Client
}
#[inline]
pub fn is_server(self) -> bool {
self == Self::Server
}
}
impl ops::Not for Side {
type Output = Self;
fn not(self) -> Self {
match self {
Self::Client => Self::Server,
Self::Server => Self::Client,
}
}
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(test, derive(Arbitrary))]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Dir {
Bi = 0,
Uni = 1,
}
impl Dir {
fn iter() -> impl Iterator<Item = Self> {
[Self::Bi, Self::Uni].iter().cloned()
}
}
impl fmt::Display for Dir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Dir::*;
f.pad(match *self {
Bi => "bidirectional",
Uni => "unidirectional",
})
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(test, derive(Arbitrary))]
pub struct StreamId(#[cfg_attr(test, strategy(crate::varint::varint_u64()))] u64);
impl fmt::Display for StreamId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let initiator = match self.initiator() {
Side::Client => "client",
Side::Server => "server",
};
let dir = match self.dir() {
Dir::Uni => "uni",
Dir::Bi => "bi",
};
write!(
f,
"{} {}directional stream {}",
initiator,
dir,
self.index()
)
}
}
impl StreamId {
pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
}
pub fn initiator(self) -> Side {
if self.0 & 0x1 == 0 {
Side::Client
} else {
Side::Server
}
}
pub fn dir(self) -> Dir {
if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
}
pub fn index(self) -> u64 {
self.0 >> 2
}
}
impl From<StreamId> for VarInt {
fn from(x: StreamId) -> Self {
unsafe { Self::from_u64_unchecked(x.0) }
}
}
impl From<VarInt> for StreamId {
fn from(v: VarInt) -> Self {
Self(v.0)
}
}
impl From<StreamId> for u64 {
fn from(x: StreamId) -> Self {
x.0
}
}
impl Decodable for StreamId {
fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
VarInt::decode(buf).map(|x| Self(x.into_inner()))
}
}
impl Encodable for StreamId {
fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
VarInt::from_u64(self.0).unwrap().encode(buf);
}
}
#[cfg(feature = "arbitrary")]
impl<'arbitrary> arbitrary::Arbitrary<'arbitrary> for StreamId {
fn arbitrary(u: &mut arbitrary::Unstructured<'arbitrary>) -> arbitrary::Result<Self> {
Ok(VarInt::arbitrary(u)?.into())
}
}
#[derive(Debug)]
#[must_use]
pub struct Transmit {
pub destination: SocketAddr,
pub ecn: Option<EcnCodepoint>,
pub size: usize,
pub segment_size: Option<usize>,
pub src_ip: Option<IpAddr>,
}
const LOCAL_CID_COUNT: u64 = 12;
const RESET_TOKEN_SIZE: usize = 16;
const MAX_CID_SIZE: usize = 20;
const MIN_INITIAL_SIZE: u16 = 1200;
const INITIAL_MTU: u16 = 1200;
const MAX_UDP_PAYLOAD: u16 = 65527;
const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
const MAX_STREAM_COUNT: u64 = 1 << 60;
#[derive(Hash, Eq, PartialEq, Copy, Clone)]
pub struct FourTuple {
remote: SocketAddr,
local_ip: Option<IpAddr>,
}
impl FourTuple {
pub fn new(mut remote: SocketAddr, local_ip: Option<IpAddr>) -> Self {
if let SocketAddr::V6(socket_addr) = &mut remote {
socket_addr.set_flowinfo(0);
let requires_scope_id =
socket_addr.ip().is_unicast_link_local() || socket_addr.ip().is_multicast();
if !requires_scope_id {
socket_addr.set_scope_id(0);
}
}
Self { remote, local_ip }
}
pub fn from_remote(remote: SocketAddr) -> Self {
Self::new(remote, None)
}
pub fn remote(&self) -> SocketAddr {
self.remote
}
pub fn local_ip(&self) -> Option<IpAddr> {
self.local_ip
}
pub fn is_probably_same_path(&self, other: &Self) -> bool {
self.remote == other.remote && (self.local_ip.is_none() || self.local_ip == other.local_ip)
}
pub fn update_local_if_same_remote(&mut self, other: &Self) -> bool {
if self.remote != other.remote {
return false;
}
if self.local_ip.is_some() && self.local_ip != other.local_ip {
return false;
}
self.local_ip = other.local_ip;
true
}
}
impl fmt::Display for FourTuple {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("(local: ")?;
if let Some(local_ip) = &self.local_ip {
local_ip.fmt(f)?;
f.write_str(", ")?;
} else {
f.write_str("<unspecified>, ")?;
}
f.write_str("remote: ")?;
self.remote.fmt(f)?;
f.write_str(")")
}
}
impl fmt::Debug for FourTuple {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self, f)
}
}