ant_quic/
lib.rs

1//! ant-quic: QUIC transport protocol with advanced NAT traversal for P2P networks
2//!
3//! This library provides a clean, modular implementation of QUIC-native NAT traversal
4//! using raw public keys for authentication. It is designed to be minimal, focused,
5//! and highly testable, with exceptional cross-platform support.
6//!
7//! The library is organized into the following main modules:
8//! - `transport`: Core QUIC transport functionality
9//! - `nat_traversal`: QUIC-native NAT traversal protocol
10//! - `discovery`: Platform-specific network interface discovery
11//! - `crypto`: Raw public key authentication
12//! - `api`: High-level P2P networking API
13
14#![cfg_attr(not(fuzzing), warn(missing_docs))]
15#![cfg_attr(test, allow(dead_code))]
16#![warn(unreachable_pub)]
17#![allow(clippy::cognitive_complexity)]
18#![allow(clippy::too_many_arguments)]
19#![warn(clippy::use_self)]
20
21use std::{
22    fmt,
23    net::{IpAddr, SocketAddr},
24    ops,
25};
26
27// Core modules
28mod cid_queue;
29pub mod coding;
30mod constant_time;
31mod range_set;
32pub mod transport_parameters;
33mod varint;
34
35pub use varint::{VarInt, VarIntBoundsExceeded};
36
37// Removed optional bloom module
38
39// Core implementation modules
40pub mod connection;
41pub mod config;
42pub mod frame;
43pub mod endpoint;
44pub mod packet;
45pub mod shared;
46pub mod transport_error;
47// Simplified congestion control
48mod congestion;
49pub mod cid_generator;
50mod token;
51mod token_memory_cache;
52pub mod candidate_discovery;
53mod connection_establishment_simple;
54pub mod nat_traversal_api;
55
56// Public modules with new structure
57pub mod transport;
58pub mod nat_traversal;
59pub mod discovery;
60pub mod crypto;
61pub mod api;
62
63// Additional modules
64pub mod quic_node;
65pub mod terminal_ui;
66pub mod workflow;
67pub mod monitoring;
68pub mod optimization;
69
70// High-level async API modules (ported from quinn crate)
71pub mod quinn_high_level;
72
73// Re-export high-level API types for easier usage
74#[cfg(feature = "production-ready")]
75pub use quinn_high_level::{
76    Endpoint,
77    Connection as HighLevelConnection,
78    Connecting,
79    Accept,
80    RecvStream as HighLevelRecvStream,
81    SendStream as HighLevelSendStream,
82};
83
84// When production-ready feature is not enabled, use low-level endpoint as default
85#[cfg(not(feature = "production-ready"))]
86pub use endpoint::Endpoint;
87
88// Re-export crypto utilities for peer ID management
89pub use crypto::raw_public_keys::key_utils::{
90    generate_ed25519_keypair, derive_peer_id_from_public_key,
91    derive_peer_id_from_key_bytes, verify_peer_id,
92    public_key_to_bytes, public_key_from_bytes,
93};
94
95// Re-export key types for backward compatibility
96pub use connection::{
97    Connection, ConnectionError, ConnectionStats, Event, 
98    RecvStream, SendStream, Streams, StreamEvent, SendDatagramError,
99    Chunk, Chunks, ClosedStream, FinishError, ReadError, ReadableError,
100    WriteError, Written, Datagrams,
101};
102pub use endpoint::{Endpoint as LowLevelEndpoint, ConnectionHandle, Incoming, AcceptError, ConnectError, DatagramEvent};
103pub use shared::{ConnectionId, EcnCodepoint, EndpointEvent};
104pub use transport_error::{Code as TransportErrorCode, Error as TransportError};
105pub use candidate_discovery::{
106    CandidateDiscoveryManager, DiscoveryConfig, DiscoveryEvent, DiscoveryError,
107    NetworkInterface, ValidatedCandidate,
108};
109pub use connection_establishment_simple::{
110    SimpleConnectionEstablishmentManager, SimpleEstablishmentConfig,
111    SimpleConnectionEvent,
112};
113pub use nat_traversal_api::{
114    NatTraversalEndpoint, NatTraversalConfig, EndpointRole, PeerId, BootstrapNode,
115    CandidateAddress, NatTraversalEvent, NatTraversalError, NatTraversalStatistics,
116};
117pub use connection::nat_traversal::{CandidateSource, CandidateState, NatTraversalRole};
118pub use quic_node::{QuicP2PNode, QuicNodeConfig, NodeStats as QuicNodeStats};
119
120#[cfg(fuzzing)]
121pub mod fuzzing;
122
123/// The QUIC protocol version implemented.
124/// 
125/// Simplified to include only the essential versions:
126/// - 0x00000001: QUIC v1 (RFC 9000)
127/// - 0xff00_001d: Draft 29
128pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
129    0x00000001, // QUIC v1 (RFC 9000)
130    0xff00_001d, // Draft 29
131];
132
133/// Whether an endpoint was the initiator of a connection
134#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
135#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
136pub enum Side {
137    /// The initiator of a connection
138    Client = 0,
139    /// The acceptor of a connection
140    Server = 1,
141}
142
143impl Side {
144    #[inline]
145    /// Shorthand for `self == Side::Client`
146    pub fn is_client(self) -> bool {
147        self == Self::Client
148    }
149
150    #[inline]
151    /// Shorthand for `self == Side::Server`
152    pub fn is_server(self) -> bool {
153        self == Self::Server
154    }
155}
156
157impl ops::Not for Side {
158    type Output = Self;
159    fn not(self) -> Self {
160        match self {
161            Self::Client => Self::Server,
162            Self::Server => Self::Client,
163        }
164    }
165}
166
167/// Whether a stream communicates data in both directions or only from the initiator
168#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
169#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
170pub enum Dir {
171    /// Data flows in both directions
172    Bi = 0,
173    /// Data flows only from the stream's initiator
174    Uni = 1,
175}
176
177impl Dir {
178    fn iter() -> impl Iterator<Item = Self> {
179        [Self::Bi, Self::Uni].iter().cloned()
180    }
181}
182
183impl fmt::Display for Dir {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        use Dir::*;
186        f.pad(match *self {
187            Bi => "bidirectional",
188            Uni => "unidirectional",
189        })
190    }
191}
192
193/// Identifier for a stream within a particular connection
194#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
195#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
196pub struct StreamId(u64);
197
198impl fmt::Display for StreamId {
199    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200        let initiator = match self.initiator() {
201            Side::Client => "client",
202            Side::Server => "server",
203        };
204        let dir = match self.dir() {
205            Dir::Uni => "uni",
206            Dir::Bi => "bi",
207        };
208        write!(
209            f,
210            "{} {}directional stream {}",
211            initiator,
212            dir,
213            self.index()
214        )
215    }
216}
217
218impl StreamId {
219    /// Create a new StreamId
220    pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
221        Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
222    }
223    /// Which side of a connection initiated the stream
224    pub fn initiator(self) -> Side {
225        if self.0 & 0x1 == 0 {
226            Side::Client
227        } else {
228            Side::Server
229        }
230    }
231    /// Which directions data flows in
232    pub fn dir(self) -> Dir {
233        if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
234    }
235    /// Distinguishes streams of the same initiator and directionality
236    pub fn index(self) -> u64 {
237        self.0 >> 2
238    }
239}
240
241impl From<StreamId> for VarInt {
242    fn from(x: StreamId) -> Self {
243        unsafe { Self::from_u64_unchecked(x.0) }
244    }
245}
246
247impl From<VarInt> for StreamId {
248    fn from(v: VarInt) -> Self {
249        Self(v.0)
250    }
251}
252
253impl From<StreamId> for u64 {
254    fn from(x: StreamId) -> Self {
255        x.0
256    }
257}
258
259impl coding::Codec for StreamId {
260    fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
261        VarInt::decode(buf).map(|x| Self(x.into_inner()))
262    }
263    fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
264        VarInt::from_u64(self.0).unwrap().encode(buf);
265    }
266}
267
268/// An outgoing packet
269#[derive(Debug)]
270#[must_use]
271pub struct Transmit {
272    /// The socket this datagram should be sent to
273    pub destination: SocketAddr,
274    /// Explicit congestion notification bits to set on the packet
275    pub ecn: Option<EcnCodepoint>,
276    /// Amount of data written to the caller-supplied buffer
277    pub size: usize,
278    /// The segment size if this transmission contains multiple datagrams.
279    /// This is `None` if the transmit only contains a single datagram
280    pub segment_size: Option<usize>,
281    /// Optional source IP address for the datagram
282    pub src_ip: Option<IpAddr>,
283}
284
285// Deal with time
286#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
287pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
288#[cfg(all(target_family = "wasm", target_os = "unknown"))]
289pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
290
291//
292// Useful internal constants
293//
294
295/// The maximum number of CIDs we bother to issue per connection
296pub(crate) const LOC_CID_COUNT: u64 = 8;
297pub(crate) const RESET_TOKEN_SIZE: usize = 16;
298pub(crate) const MAX_CID_SIZE: usize = 20;
299pub(crate) const MIN_INITIAL_SIZE: u16 = 1200;
300/// <https://www.rfc-editor.org/rfc/rfc9000.html#name-datagram-size>
301pub(crate) const INITIAL_MTU: u16 = 1200;
302pub(crate) const MAX_UDP_PAYLOAD: u16 = 65527;
303pub(crate) const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
304/// Maximum number of streams that can be tracked per connection
305pub(crate) const MAX_STREAM_COUNT: u64 = 1 << 60;
306
307// Internal type re-exports for crate modules
308pub(crate) use token::{ResetToken, TokenStore, TokenLog, NoneTokenLog};
309pub(crate) use token_memory_cache::TokenMemoryCache;
310pub(crate) use frame::Frame;
311pub use config::{EndpointConfig, TransportConfig, ServerConfig, AckFrequencyConfig, MtuDiscoveryConfig, ClientConfig};
312pub use cid_generator::RandomConnectionIdGenerator;