mod accessors_impl;
mod acl;
mod bloom;
mod core_impl;
mod decrypt_worker;
mod discovery_rate_limit;
mod encrypt_worker;
mod endpoint_event;
mod endpoint_traffic;
mod error;
mod handlers;
mod identity_cache;
mod io_impl;
mod lifecycle;
mod link_registry;
mod peer_lifecycle;
mod peer_runtime;
mod rate_limit;
mod recent_requests;
mod retry;
mod route_impl;
mod routing;
mod routing_error_rate_limit;
mod send_impl;
pub(crate) mod session;
mod session_access_impl;
mod session_registry;
pub(crate) mod session_wire;
mod state;
pub(crate) mod stats;
pub(crate) mod stats_history;
mod support_state;
#[cfg(test)]
mod tests;
mod tree;
pub(crate) mod wire;
pub use endpoint_event::ExternalPacketIo;
pub use endpoint_traffic::{
EndpointPayloadClass, EndpointPayloadLane, classify_endpoint_payload,
endpoint_payload_is_latency_sensitive,
};
pub use error::NodeError;
pub use identity_cache::NodeDeliveredPacket;
pub use state::NodeState;
pub(crate) use endpoint_event::EndpointBulkSendFeedback;
#[cfg(test)]
pub(in crate::node) use endpoint_event::EndpointEventDequeueCounts;
pub(in crate::node) use endpoint_event::EndpointEventRuntime;
#[cfg(test)]
pub(in crate::node) use endpoint_event::release_endpoint_event_messages;
#[cfg(unix)]
pub(in crate::node) use endpoint_event::{
EndpointBulkSendFeedbackRecord, EndpointBulkSendSessionBookkeeping,
};
#[cfg(unix)]
pub(crate) use endpoint_event::{
EndpointBulkSendFmpLease, EndpointBulkSendFspLease, EndpointBulkSendLease,
EndpointBulkSendRuntime,
};
pub(crate) use endpoint_event::{
EndpointDataDelivery, EndpointDataIo, EndpointEventReceiver, EndpointEventSender,
EndpointSendBatchCommand, EndpointSendCommand, NodeEndpointCommand, NodeEndpointEvent,
NodeEndpointPeer, NodeEndpointRelayStatus, UpdatePeersOutcome, endpoint_data_command_capacity,
};
#[cfg(unix)]
pub(in crate::node) use endpoint_traffic::reserve_fmp_worker_send;
pub(crate) use endpoint_traffic::{
EndpointCommandLane, EndpointDataPayload, EndpointDataSend, PendingSessionTrafficQueues,
};
#[cfg(test)]
pub(crate) use endpoint_traffic::{PendingEndpointDataQueue, PendingTunPacketQueue};
#[cfg(unix)]
pub(in crate::node) use endpoint_traffic::{
classify_fmp_plaintext_traffic, endpoint_flow_dispatch_key,
};
#[cfg(test)]
pub(in crate::node) use endpoint_traffic::{
endpoint_command_lane_for_payload, endpoint_payload_is_tcp,
fmp_plaintext_is_bulk_session_datagram,
};
pub(in crate::node) use identity_cache::IdentityCache;
#[cfg(test)]
pub(in crate::node) use link_registry::LinkAddressIndex;
pub(in crate::node) use link_registry::{LinkRegistry, PendingConnect, TransportDropTracker};
pub(in crate::node) use peer_lifecycle::*;
pub(in crate::node) use peer_runtime::*;
#[cfg(test)]
pub(crate) use recent_requests::RecentRequest;
pub(crate) use recent_requests::{RecentDiscoveryRequests, RecentResponseForward};
pub(in crate::node) use session_registry::*;
pub(in crate::node) use support_state::{
BootstrapTransports, DiscoveryFallbackTransit, LocalSendFailures, SessionDirectDegradation,
};
use self::decrypt_worker::DecryptSessionKey;
use self::discovery_rate_limit::{DiscoveryBackoff, DiscoveryForwardRateLimiter};
use self::rate_limit::HandshakeRateLimiter;
use self::routing::{LearnedRouteTable, LearnedRouteTableSnapshot};
use self::routing_error_rate_limit::RoutingErrorRateLimiter;
#[cfg(unix)]
use self::wire::ESTABLISHED_HEADER_SIZE;
use self::wire::{
FLAG_CE, FLAG_KEY_EPOCH, FLAG_SP, build_encrypted, build_established_header,
prepend_inner_header,
};
use crate::bloom::{BloomFilter, BloomState};
use crate::cache::CoordCache;
use crate::config::{NostrDiscoveryPolicy, PeerConfig, RoutingMode};
#[cfg(unix)]
use crate::node::session::FspSendReservation;
use crate::node::session::SessionEntry;
use crate::node::session_wire::{FSP_PHASE_ESTABLISHED, FspCommonPrefix};
use crate::peer::{ActivePeer, PeerConnection};
#[cfg(any(target_os = "linux", target_os = "macos"))]
use crate::transport::ethernet::EthernetTransport;
use crate::transport::tcp::TcpTransport;
use crate::transport::tor::TorTransport;
use crate::transport::udp::UdpTransport;
#[cfg(feature = "webrtc-transport")]
use crate::transport::webrtc::WebRtcTransport;
use crate::transport::{
ConnectionState, Link, LinkId, PacketRx, PacketTx, TransportAddr, TransportError,
TransportHandle, TransportId,
};
use crate::tree::TreeState;
use crate::upper::hosts::HostMap;
use crate::upper::icmp_rate_limit::IcmpRateLimiter;
use crate::upper::tun::{TunError, TunOutboundRx, TunState, TunTx};
use crate::utils::index::{IndexAllocator, SessionIndex};
use crate::{
Config, ConfigError, FipsAddress, Identity, IdentityError, LinkMessageType, NodeAddr,
PeerIdentity, encode_npub,
};
use rand::Rng;
use std::collections::{HashMap, HashSet, VecDeque};
use std::fmt;
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use std::sync::{Arc, Condvar, Mutex as StdMutex};
use std::thread::JoinHandle;
use thiserror::Error;
use tracing::{debug, warn};
const LOCAL_SEND_FAILURE_FAST_DEAD_WINDOW: std::time::Duration = std::time::Duration::from_secs(3);
pub(crate) const ENDPOINT_EVENT_PRIORITY_MAX_LEN: usize = 512;
const SESSION_DIRECT_DEGRADED_HOLD_MS: u64 = 20_000;
const SESSION_DIRECT_DEGRADED_MIN_SAMPLE: u64 = 16;
const SESSION_DIRECT_DEGRADED_LOSS_THRESHOLD: f64 = 0.08;
const SESSION_DIRECT_RECOVERY_LOSS_THRESHOLD: f64 = 0.02;
const SESSION_DIRECT_MIN_EXCLUSIVE_TRUST_MS: u64 = 6_500;
const ROUTING_FALLBACK_MIN_COST_ADVANTAGE: f64 = 0.25;
const ENDPOINT_EVENT_BACKLOG_HIGH_WATER: usize = 4096;
pub(crate) const REKEY_JITTER_SECS: i64 = 15;
pub struct Node {
identity: Identity,
startup_epoch: [u8; 8],
started_at: std::time::Instant,
config: Config,
state: NodeState,
is_leaf_only: bool,
tree_state: TreeState,
bloom_state: BloomState,
coord_cache: CoordCache,
learned_routes: LearnedRouteTable,
session_direct_degradation: SessionDirectDegradation,
recent_requests: RecentDiscoveryRequests,
path_mtu_lookup: Arc<std::sync::RwLock<HashMap<crate::FipsAddress, u16>>>,
transports: HashMap<TransportId, TransportHandle>,
udp_transport_resolution_cache: lifecycle::UdpTransportResolutionCache,
transport_drops: TransportDropTracker,
transport_socket_drops: TransportDropTracker,
transport_namespace_drops: TransportDropTracker,
links: LinkRegistry,
packet_tx: Option<PacketTx>,
packet_rx: Option<PacketRx>,
peers: PeerLifecycleRegistry,
sessions: SessionRegistry,
identity_cache: IdentityCache,
pending_session_traffic: PendingSessionTrafficQueues,
pending_lookups: handlers::discovery::PendingDiscoveryLookups,
max_connections: usize,
max_peers: usize,
max_links: usize,
next_link_id: u64,
next_transport_id: u32,
stats: stats::NodeStats,
stats_history: stats_history::StatsHistory,
tun_state: TunState,
tun_name: Option<String>,
tun_tx: Option<TunTx>,
tun_outbound_rx: Option<TunOutboundRx>,
external_packet_tx: Option<tokio::sync::mpsc::Sender<NodeDeliveredPacket>>,
endpoint_priority_command_rx: Option<tokio::sync::mpsc::Receiver<NodeEndpointCommand>>,
endpoint_command_rx: Option<tokio::sync::mpsc::Receiver<NodeEndpointCommand>>,
endpoint_events: EndpointEventRuntime,
endpoint_bulk_feedback_rx: Option<tokio::sync::mpsc::Receiver<EndpointBulkSendFeedback>>,
#[cfg(unix)]
endpoint_bulk_send_runtime: Option<EndpointBulkSendRuntime>,
encrypt_workers: Option<encrypt_worker::EncryptWorkerPool>,
decrypt_workers: Option<decrypt_worker::DecryptWorkerPool>,
decrypt_fallback_rx: Option<decrypt_worker::DecryptWorkerFallbackReceivers>,
decrypt_fallback_tx: decrypt_worker::DecryptWorkerFallbackSender,
tun_reader_handle: Option<JoinHandle<()>>,
tun_writer_handle: Option<JoinHandle<()>>,
#[cfg(target_os = "macos")]
tun_shutdown_fd: Option<std::os::unix::io::RawFd>,
dns_identity_rx: Option<crate::upper::dns::DnsIdentityRx>,
dns_task: Option<tokio::task::JoinHandle<()>>,
index_allocator: IndexAllocator,
pending_outbound: PendingOutboundHandshakes,
msg1_rate_limiter: HandshakeRateLimiter,
icmp_rate_limiter: IcmpRateLimiter,
routing_error_rate_limiter: RoutingErrorRateLimiter,
coords_response_rate_limiter: RoutingErrorRateLimiter,
discovery_backoff: DiscoveryBackoff,
discovery_forward_limiter: DiscoveryForwardRateLimiter,
pending_connects: Vec<PendingConnect>,
retry_pending: retry::PendingRouteRetries,
nostr_discovery: Option<Arc<crate::discovery::nostr::NostrDiscovery>>,
lan_discovery: Option<Arc<crate::discovery::lan::LanDiscovery>>,
local_instance_registry: Option<crate::discovery::local::LocalInstanceRegistry>,
local_instance_started_at_ms: Option<u64>,
last_local_instance_publish_ms: Option<u64>,
last_local_instance_scan_ms: Option<u64>,
nostr_discovery_started_at_ms: Option<u64>,
startup_open_discovery_sweep_done: bool,
bootstrap_transports: BootstrapTransports,
discovery_fallback_transit: DiscoveryFallbackTransit,
last_parent_reeval: Option<crate::time::Instant>,
last_congestion_log: Option<std::time::Instant>,
estimated_mesh_size: Option<u64>,
last_mesh_size_log: Option<std::time::Instant>,
last_self_warn: Option<std::time::Instant>,
local_send_failures: LocalSendFailures,
last_rx_loop_maintenance_timeout_at: Option<std::time::Instant>,
peer_aliases: HashMap<NodeAddr, String>,
configured_peer_send_weights: ConfiguredPeerSendWeights,
peer_acl: acl::PeerAclReloader,
host_map: Arc<HostMap>,
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Node")
.field("node_addr", self.node_addr())
.field("state", &self.state)
.field("is_leaf_only", &self.is_leaf_only)
.field("connections", &self.connection_count())
.field("peers", &self.peer_count())
.field("links", &self.link_count())
.field("transports", &self.transport_count())
.finish()
}
}