1#![allow(elided_lifetimes_in_paths)]
10#![allow(missing_debug_implementations)]
11#![allow(clippy::manual_is_multiple_of)]
12#![cfg_attr(not(fuzzing), warn(missing_docs))]
26#![allow(unreachable_pub)]
27#![allow(clippy::cognitive_complexity)]
28#![allow(clippy::too_many_arguments)]
29#![allow(clippy::use_self)]
30#![warn(dead_code)]
32#![allow(clippy::field_reassign_with_default)]
33#![allow(clippy::module_inception)]
34#![allow(clippy::useless_vec)]
35#![allow(private_interfaces)]
36#![allow(clippy::upper_case_acronyms)]
37#![allow(clippy::type_complexity)]
38#![allow(clippy::manual_clamp)]
39#![allow(clippy::needless_range_loop)]
40#![allow(clippy::borrowed_box)]
41#![allow(clippy::manual_strip)]
42#![allow(clippy::if_same_then_else)]
43#![allow(clippy::ptr_arg)]
44#![allow(clippy::incompatible_msrv)]
45#![allow(clippy::await_holding_lock)]
46#![allow(clippy::single_match)]
47#![allow(clippy::must_use_candidate)]
48#![allow(clippy::let_underscore_must_use)]
49#![allow(clippy::let_underscore_untyped)]
50#![allow(clippy::large_enum_variant)]
51#![allow(clippy::too_many_lines)]
52#![allow(clippy::result_large_err)]
53#![allow(clippy::enum_glob_use)]
54#![allow(clippy::match_like_matches_macro)]
55#![allow(clippy::struct_field_names)]
56#![allow(clippy::cast_precision_loss)]
57#![allow(clippy::cast_sign_loss)]
58#![allow(clippy::cast_possible_wrap)]
59#![allow(clippy::cast_possible_truncation)]
60#![allow(clippy::unnecessary_wraps)]
61#![allow(clippy::doc_markdown)]
62#![allow(clippy::module_name_repetitions)]
63#![allow(clippy::items_after_statements)]
64#![allow(clippy::missing_panics_doc)]
65#![allow(clippy::missing_errors_doc)]
66#![allow(clippy::similar_names)]
67#![allow(clippy::new_without_default)]
68#![allow(clippy::unwrap_or_default)]
69#![allow(clippy::uninlined_format_args)]
70#![allow(clippy::redundant_field_names)]
71#![allow(clippy::redundant_closure_for_method_calls)]
72#![allow(clippy::redundant_pattern_matching)]
73#![allow(clippy::option_if_let_else)]
74#![allow(clippy::trivially_copy_pass_by_ref)]
75#![allow(clippy::len_without_is_empty)]
76#![allow(clippy::explicit_auto_deref)]
77#![allow(clippy::blocks_in_conditions)]
78#![allow(clippy::collapsible_else_if)]
79#![allow(clippy::collapsible_if)]
80#![allow(clippy::unnecessary_cast)]
81#![allow(clippy::needless_bool)]
82#![allow(clippy::needless_borrow)]
83#![allow(clippy::redundant_static_lifetimes)]
84#![allow(clippy::match_ref_pats)]
85#![allow(clippy::should_implement_trait)]
86#![allow(clippy::wildcard_imports)]
87#![warn(unused_must_use)]
88#![allow(improper_ctypes)]
89#![allow(improper_ctypes_definitions)]
90#![allow(non_upper_case_globals)]
91#![allow(clippy::wrong_self_convention)]
92#![allow(clippy::vec_init_then_push)]
93#![allow(clippy::format_in_format_args)]
94#![allow(clippy::from_over_into)]
95#![allow(clippy::useless_conversion)]
96#![allow(clippy::never_loop)]
97#![allow(dropping_references)]
98#![allow(non_snake_case)]
99#![allow(clippy::unnecessary_literal_unwrap)]
100#![allow(clippy::assertions_on_constants)]
101
102use std::{
103 fmt,
104 net::{IpAddr, SocketAddr},
105 ops,
106};
107
108mod ack_frame;
110mod cid_queue;
111pub mod coding;
112mod constant_time;
113mod range_set;
114pub mod transport_parameters;
115mod varint;
116
117pub use varint::{VarInt, VarIntBoundsExceeded};
118
119pub mod bounded_pending_buffer;
123
124pub mod path_selection;
126
127pub mod shutdown;
129
130pub mod watchable;
132
133pub mod fair_polling;
135
136pub mod transport_resilience;
138
139pub mod connection_strategy;
141
142pub mod happy_eyeballs;
144
145pub mod discovery_trait;
147
148pub mod structured_events;
150
151pub mod node;
162
163pub mod node_config;
165
166pub mod node_status;
168
169mod coordinator_control;
170pub(crate) mod coordinator_health;
172pub mod mdns;
174pub mod node_event;
176mod peer_directory;
177mod port_mapping;
178
179pub mod reachability;
181
182pub mod config;
185pub mod connection;
187pub mod endpoint;
189pub mod frame;
191pub mod packet;
193pub mod shared;
195pub mod transport_error;
197pub mod candidate_discovery;
200pub mod cid_generator;
202mod congestion;
203
204pub mod nat_traversal_api;
207mod token;
208mod token_memory_cache;
209pub mod tracing;
211
212pub mod constrained;
215pub mod crypto;
217pub mod discovery;
219pub mod nat_traversal;
221pub mod transport;
223
224pub mod connection_router;
226
227pub mod chat;
231
232mod connection_lifecycle;
238
239pub mod p2p_endpoint;
244
245pub mod unified_config;
250
251pub mod stats_dashboard;
253pub mod terminal_ui;
255
256pub mod compliance_validator;
259
260pub mod logging;
263
264pub mod metrics;
266
267pub mod relay;
269
270pub mod masque;
272
273pub mod trust;
275
276pub mod token_v2;
278
279pub mod high_level;
281
282pub use high_level::{
284 Accept, Connecting, Connection as HighLevelConnection, Endpoint,
285 RecvStream as HighLevelRecvStream, SendStream as HighLevelSendStream,
286};
287
288pub mod link_transport;
290mod link_transport_impl;
291
292pub use link_transport::{
294 BoxFuture, BoxStream, BoxedHandler, Capabilities, ConnectionStats as LinkConnectionStats,
295 DisconnectReason as LinkDisconnectReason, Incoming as LinkIncoming, LinkConn, LinkError,
296 LinkEvent, LinkRecvStream, LinkResult, LinkSendStream, LinkTransport, NatHint, ProtocolHandler,
297 ProtocolHandlerExt, ProtocolId, StreamFilter, StreamType, StreamTypeFamily,
298};
299pub use link_transport_impl::{
300 P2pLinkConn, P2pLinkTransport, P2pRecvStream, P2pSendStream, SharedTransport,
301};
302
303pub mod bootstrap_cache;
305pub use bootstrap_cache::{
306 BootstrapCache, BootstrapCacheConfig, BootstrapCacheConfigBuilder, CacheEvent, CacheStats,
307 CachedPeer, ConnectionOutcome, ConnectionStats as CacheConnectionStats,
308 NatType as CacheNatType, PeerCapabilities, PeerSource, QualityWeights, SelectionStrategy,
309};
310
311pub mod host_identity;
313pub use host_identity::{EndpointKeyPolicy, HostIdentity, HostKeyStorage, StorageError};
314
315pub use crypto::raw_public_keys::key_utils::{
317 ML_DSA_65_PUBLIC_KEY_SIZE, ML_DSA_65_SECRET_KEY_SIZE, MlDsaPublicKey, MlDsaSecretKey,
318 derive_peer_id_from_key_bytes, derive_peer_id_from_public_key, generate_ml_dsa_keypair,
319 verify_peer_id,
320};
321
322pub use candidate_discovery::{
324 CandidateDiscoveryManager, DiscoveryConfig, DiscoveryError, DiscoveryEvent, NetworkInterface,
325 ValidatedCandidate,
326};
327pub use connection::nat_traversal::{CandidateSource, CandidateState};
329pub use connection::{
330 Chunk, Chunks, ClosedStream, Connection, ConnectionError, ConnectionStats, DatagramDropStats,
331 Datagrams, Event, FinishError, ReadError, ReadableError, RecvStream, SendDatagramError,
332 SendStream, StreamEvent, Streams, WriteError, Written,
333};
334pub use coordinator_control::RejectionReason;
335pub use endpoint::{
336 AcceptError, ConnectError, ConnectionHandle, DatagramEvent, Endpoint as LowLevelEndpoint,
337 Incoming,
338};
339pub use nat_traversal_api::{
340 BootstrapNode, CandidateAddress, NatTraversalConfig, NatTraversalEndpoint, NatTraversalError,
341 NatTraversalEvent, NatTraversalStatistics, PeerId, TraversalDeadlineKind,
342 TraversalFailureReason,
343};
344pub use reachability::{ReachabilityScope, TraversalMethod};
345
346pub use node::{Node, NodeError};
352
353pub use node_config::{NodeConfig, NodeConfigBuilder};
355
356pub use node_status::{NatType, NodeStatus};
358
359pub use node_event::{DisconnectReason as NodeDisconnectReason, NodeEvent};
361
362pub use ack_frame::ReceiveRejectReason;
368pub use connection_lifecycle::ConnectionCloseReason;
369pub use p2p_endpoint::{
370 ConnectionHealth, ConnectionMetrics, DirectPathStatus, DirectPathUnavailableReason,
371 DisconnectReason, EndpointError, EndpointStats, P2pEndpoint, P2pEvent, PeerConnection,
372 PeerLifecycleEvent, TraversalPhase,
373};
374
375pub use unified_config::{
377 ConfigError, MtuConfig, NatConfig, P2pConfig, P2pConfigBuilder, PortMappingConfig,
378};
379
380pub use connection_strategy::{
382 AttemptedMethod, ConnectionAttemptError, ConnectionMethod, ConnectionStage, ConnectionStrategy,
383 StrategyConfig,
384};
385
386pub use relay::{
387 AuthToken,
388 MasqueRelayClient,
390 MasqueRelayConfig,
391 MasqueRelayServer,
392 MasqueRelayStats,
393 MigrationConfig,
394 MigrationCoordinator,
395 MigrationState,
396 RelayAuthenticator,
397 RelayError,
398 RelayManager,
399 RelayManagerConfig,
400 RelayResult,
401 RelaySession,
402 RelaySessionConfig,
403 RelaySessionState,
404 RelayStatisticsCollector,
405};
406pub use shared::{ConnectionId, EcnCodepoint, EndpointEvent};
407pub use transport_error::{Code as TransportErrorCode, Error as TransportError};
408
409pub use transport::{
411 BandwidthClass, InboundDatagram, LinkQuality, LoRaParams, ProtocolEngine, ProviderError,
412 TransportAddr, TransportCapabilities, TransportCapabilitiesBuilder, TransportDiagnostics,
413 TransportProvider, TransportRegistry, TransportStats, TransportType, UdpTransport,
414};
415
416#[cfg(feature = "ble")]
417pub use transport::BleTransport;
418
419pub use connection_router::{
421 ConnectionRouter, RoutedConnection, RouterConfig, RouterError, RouterStats,
422};
423
424pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
433 0x00000001, 0xff00_001d, ];
436
437#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
439#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
440pub enum Side {
441 Client = 0,
443 Server = 1,
445}
446
447impl Side {
448 #[inline]
449 pub fn is_client(self) -> bool {
451 self == Self::Client
452 }
453
454 #[inline]
455 pub fn is_server(self) -> bool {
457 self == Self::Server
458 }
459}
460
461impl ops::Not for Side {
462 type Output = Self;
463 fn not(self) -> Self {
464 match self {
465 Self::Client => Self::Server,
466 Self::Server => Self::Client,
467 }
468 }
469}
470
471#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
473#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
474pub enum Dir {
475 Bi = 0,
477 Uni = 1,
479}
480
481impl Dir {
482 fn iter() -> impl Iterator<Item = Self> {
483 [Self::Bi, Self::Uni].iter().cloned()
484 }
485}
486
487impl fmt::Display for Dir {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 use Dir::*;
490 f.pad(match *self {
491 Bi => "bidirectional",
492 Uni => "unidirectional",
493 })
494 }
495}
496
497#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
499#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
500pub struct StreamId(u64);
501
502impl fmt::Display for StreamId {
503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504 let initiator = match self.initiator() {
505 Side::Client => "client",
506 Side::Server => "server",
507 };
508 let dir = match self.dir() {
509 Dir::Uni => "uni",
510 Dir::Bi => "bi",
511 };
512 write!(
513 f,
514 "{} {}directional stream {}",
515 initiator,
516 dir,
517 self.index()
518 )
519 }
520}
521
522impl StreamId {
523 pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
525 Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
526 }
527 pub fn initiator(self) -> Side {
529 if self.0 & 0x1 == 0 {
530 Side::Client
531 } else {
532 Side::Server
533 }
534 }
535 pub fn dir(self) -> Dir {
537 if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
538 }
539 pub fn index(self) -> u64 {
541 self.0 >> 2
542 }
543}
544
545impl From<StreamId> for VarInt {
546 fn from(x: StreamId) -> Self {
547 unsafe { Self::from_u64_unchecked(x.0) }
548 }
549}
550
551impl From<VarInt> for StreamId {
552 fn from(v: VarInt) -> Self {
553 Self(v.0)
554 }
555}
556
557impl From<StreamId> for u64 {
558 fn from(x: StreamId) -> Self {
559 x.0
560 }
561}
562
563impl coding::Codec for StreamId {
564 fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
565 VarInt::decode(buf).map(|x| Self(x.into_inner()))
566 }
567 fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
568 match VarInt::from_u64(self.0) {
570 Ok(varint) => varint.encode(buf),
571 Err(_) => {
572 VarInt::MAX.encode(buf);
574 }
575 }
576 }
577}
578
579#[derive(Debug)]
581#[must_use]
582pub struct Transmit {
583 pub destination: SocketAddr,
585 pub ecn: Option<EcnCodepoint>,
587 pub size: usize,
589 pub segment_size: Option<usize>,
592 pub src_ip: Option<IpAddr>,
594}
595
596#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
598pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
599#[cfg(all(target_family = "wasm", target_os = "unknown"))]
600pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
601
602pub const SHUTDOWN_DRAIN_TIMEOUT: Duration = Duration::from_secs(5);
610
611pub(crate) const LOC_CID_COUNT: u64 = 8;
613pub(crate) const RESET_TOKEN_SIZE: usize = 16;
614pub(crate) const MAX_CID_SIZE: usize = 20;
615pub(crate) const MIN_INITIAL_SIZE: u16 = 1200;
616pub(crate) const INITIAL_MTU: u16 = 1200;
618pub(crate) const MAX_UDP_PAYLOAD: u16 = 65527;
619pub(crate) const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
620pub(crate) const MAX_STREAM_COUNT: u64 = 1 << 60;
622
623pub use cid_generator::RandomConnectionIdGenerator;
625pub use config::{
626 AckFrequencyConfig, ClientConfig, EndpointConfig, MtuDiscoveryConfig, ServerConfig,
627 TransportConfig,
628};
629
630pub use crypto::pqc::{MlDsa65, MlKem768, PqcConfig, PqcConfigBuilder, PqcError, PqcResult};
633pub(crate) use frame::Frame;
634pub use token::TokenStore;
635pub(crate) use token::{NoneTokenLog, ResetToken, TokenLog};
636pub(crate) use token_memory_cache::TokenMemoryCache;