From 0f2e91b479f4218a61c0b36b4e4120d9eae5ff83 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sat, 11 Jul 2026 20:10:19 +0000 Subject: [PATCH 1/4] transport: rename udp byte-layer module from socket to io Normalizes the udp transport onto the canonical per-transport module layout (ble is the reference: io/pool/addr/stats). Pure file rename plus module-path updates at the use sites; no logic, wire, config, metric, or log change. Behavior identical. --- src/node/encrypt_worker.rs | 10 +++++----- src/transport/udp/{socket.rs => io.rs} | 2 +- src/transport/udp/mod.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) rename src/transport/udp/{socket.rs => io.rs} (99%) diff --git a/src/node/encrypt_worker.rs b/src/node/encrypt_worker.rs index 28b232b..80219da 100644 --- a/src/node/encrypt_worker.rs +++ b/src/node/encrypt_worker.rs @@ -52,7 +52,7 @@ use crate::proto::fmp::wire::ESTABLISHED_HEADER_SIZE; use crate::proto::fsp::wire::FSP_HEADER_SIZE; -use crate::transport::udp::socket::AsyncUdpSocket; +use crate::transport::udp::io::AsyncUdpSocket; #[cfg(not(target_os = "macos"))] use crossbeam_channel::{Receiver, SendError, Sender, TrySendError, bounded}; use ring::aead::{Aad, LessSafeKey, Nonce}; @@ -1710,7 +1710,7 @@ fn send_batch_gso( } /// Direct `sendmmsg(2)` wrapper for the sync worker. The -/// `transport::udp::socket` module's existing `send_batch` is +/// `transport::udp::io` module's existing `send_batch` is /// pub(crate) on `UdpRawSocket`, but we don't have a handle to the /// raw socket from here — we just have the FD. Re-implementing /// inline is ~15 lines and avoids tunnelling the inner socket @@ -1780,7 +1780,7 @@ fn send_batch_raw( #[cfg(all(test, unix))] mod unix_tests { use super::*; - use crate::transport::udp::socket::UdpRawSocket; + use crate::transport::udp::io::UdpRawSocket; use ring::aead::{LessSafeKey, UnboundKey}; use std::net::UdpSocket; @@ -2220,7 +2220,7 @@ mod tests { /// AsRawFd impl. #[test] fn flush_batch_routes_each_target_separately() { - use crate::transport::udp::socket::UdpRawSocket; + use crate::transport::udp::io::UdpRawSocket; use ring::aead::{LessSafeKey, UnboundKey}; use std::net::UdpSocket; @@ -2266,7 +2266,7 @@ mod tests { const B_WIRE: usize = 16 + B_PLAINTEXT + 16; // 96 fn make_job( - socket: crate::transport::udp::socket::AsyncUdpSocket, + socket: crate::transport::udp::io::AsyncUdpSocket, cipher: &LessSafeKey, counter: u64, dest: SocketAddr, diff --git a/src/transport/udp/socket.rs b/src/transport/udp/io.rs similarity index 99% rename from src/transport/udp/socket.rs rename to src/transport/udp/io.rs index 6ba77f9..a4e6460 100644 --- a/src/transport/udp/socket.rs +++ b/src/transport/udp/io.rs @@ -844,7 +844,7 @@ mod tests { /// drained over a fixed wall-clock window per mode. /// /// Run with: - /// cargo test --release -p fips --lib transport::udp::socket::tests::bench_udp_recv_amortization -- --ignored --nocapture + /// cargo test --release -p fips --lib transport::udp::io::tests::bench_udp_recv_amortization -- --ignored --nocapture /// /// Sender runs on a dedicated *blocking* OS thread (std::net::UdpSocket /// in default blocking mode) so it always saturates the kernel rx queue diff --git a/src/transport/udp/mod.rs b/src/transport/udp/mod.rs index 780af5a..a8ad380 100644 --- a/src/transport/udp/mod.rs +++ b/src/transport/udp/mod.rs @@ -10,14 +10,14 @@ use super::{ pub(crate) mod connected_peer; #[cfg(target_os = "macos")] pub(crate) mod darwin_sockopts; +pub(crate) mod io; #[cfg(unix)] pub(crate) mod peer_drain; -pub(crate) mod socket; mod stats; use super::resolve_socket_addr; use crate::config::UdpConfig; use crate::nostr::is_punch_packet; -use socket::{AsyncUdpSocket, UdpRawSocket}; +use io::{AsyncUdpSocket, UdpRawSocket}; use stats::UdpStats; use std::collections::HashMap; use std::net::SocketAddr; From 196d9492dac1ee0621fb7f981b408ebbaf431561 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sat, 11 Jul 2026 20:14:37 +0000 Subject: [PATCH 2/4] transport: rename ethernet byte-layer module from socket to io Normalizes the ethernet transport onto the canonical byte-layer name (io.rs), including the per-OS files io_linux.rs/io_macos.rs and their #[path] wiring. Pure file rename plus module-path and doc-comment updates; no logic, wire, config, metric, or log change. --- src/transport/ethernet/{socket.rs => io.rs} | 8 ++++---- src/transport/ethernet/{socket_linux.rs => io_linux.rs} | 0 src/transport/ethernet/{socket_macos.rs => io_macos.rs} | 4 ++-- src/transport/ethernet/mod.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) rename src/transport/ethernet/{socket.rs => io.rs} (98%) rename src/transport/ethernet/{socket_linux.rs => io_linux.rs} (100%) rename src/transport/ethernet/{socket_macos.rs => io_macos.rs} (99%) diff --git a/src/transport/ethernet/socket.rs b/src/transport/ethernet/io.rs similarity index 98% rename from src/transport/ethernet/socket.rs rename to src/transport/ethernet/io.rs index 622d7f6..392a3b8 100644 --- a/src/transport/ethernet/socket.rs +++ b/src/transport/ethernet/io.rs @@ -1,7 +1,7 @@ //! Raw Ethernet socket abstraction. //! -//! Platform-specific implementations live in `socket_linux.rs` (AF_PACKET) -//! and `socket_macos.rs` (BPF). This module re-exports `PacketSocket` and +//! Platform-specific implementations live in `io_linux.rs` (AF_PACKET) +//! and `io_macos.rs` (BPF). This module re-exports `PacketSocket` and //! provides `AsyncPacketSocket`. use crate::transport::TransportError; @@ -11,11 +11,11 @@ pub const ETHERNET_BROADCAST: [u8; 6] = [0xff; 6]; // Platform-specific PacketSocket implementation. #[cfg(target_os = "linux")] -#[path = "socket_linux.rs"] +#[path = "io_linux.rs"] mod platform; #[cfg(target_os = "macos")] -#[path = "socket_macos.rs"] +#[path = "io_macos.rs"] mod platform; #[cfg(unix)] diff --git a/src/transport/ethernet/socket_linux.rs b/src/transport/ethernet/io_linux.rs similarity index 100% rename from src/transport/ethernet/socket_linux.rs rename to src/transport/ethernet/io_linux.rs diff --git a/src/transport/ethernet/socket_macos.rs b/src/transport/ethernet/io_macos.rs similarity index 99% rename from src/transport/ethernet/socket_macos.rs rename to src/transport/ethernet/io_macos.rs index 2ddb187..3c8cab1 100644 --- a/src/transport/ethernet/socket_macos.rs +++ b/src/transport/ethernet/io_macos.rs @@ -555,8 +555,8 @@ fn get_mac_addr(interface: &str) -> Result<[u8; 6], TransportError> { // ============================================================================ // Unit tests // -// The whole `socket_macos.rs` file is `#[cfg(target_os = "macos")]`-included -// by `socket.rs`, so this `#[cfg(test)]` mod naturally only compiles on macOS. +// The whole `io_macos.rs` file is `#[cfg(target_os = "macos")]`-included +// by `io.rs`, so this `#[cfg(test)]` mod naturally only compiles on macOS. // The redundant `#[cfg(target_os = "macos")]` below is belt-and-suspenders: // it makes the macOS-only intent explicit so that any future refactor that // includes this file on additional targets won't silently activate macOS- diff --git a/src/transport/ethernet/mod.rs b/src/transport/ethernet/mod.rs index 60b0dbf..1856669 100644 --- a/src/transport/ethernet/mod.rs +++ b/src/transport/ethernet/mod.rs @@ -6,7 +6,7 @@ //! 802.11 transparently on Linux). pub mod discovery; -pub mod socket; +pub mod io; pub mod stats; use super::{ @@ -15,7 +15,7 @@ use super::{ }; use crate::config::EthernetConfig; use discovery::{DiscoveryBuffer, FRAME_TYPE_BEACON, FRAME_TYPE_DATA, build_beacon, parse_beacon}; -use socket::{AsyncPacketSocket, ETHERNET_BROADCAST, PacketSocket}; +use io::{AsyncPacketSocket, ETHERNET_BROADCAST, PacketSocket}; use stats::EthernetStats; use secp256k1::XOnlyPublicKey; From 6d6889d0f6dad1ecf0d0606f8638fedb3617ba59 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sat, 11 Jul 2026 20:19:08 +0000 Subject: [PATCH 3/4] transport: give ethernet a canonical addr.rs home for MAC parsing Moves parse_mac_string into ethernet/addr.rs and re-exports it at the ethernet module root so the ethernet::parse_mac_string path stays byte-identical for its one external consumer (zero churn there). Its unit tests stay in mod.rs, calling through the re-export. Pure relocation; no logic change. --- src/transport/ethernet/addr.rs | 21 +++++++++++++++++++++ src/transport/ethernet/mod.rs | 21 +++------------------ 2 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 src/transport/ethernet/addr.rs diff --git a/src/transport/ethernet/addr.rs b/src/transport/ethernet/addr.rs new file mode 100644 index 0000000..677fe68 --- /dev/null +++ b/src/transport/ethernet/addr.rs @@ -0,0 +1,21 @@ +//! Ethernet address parsing. + +use crate::transport::TransportError; + +/// Parse a colon-separated MAC string (e.g., "aa:bb:cc:dd:ee:ff") into bytes. +pub fn parse_mac_string(s: &str) -> Result<[u8; 6], TransportError> { + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 6 { + return Err(TransportError::InvalidAddress(format!( + "invalid MAC format: expected 6 colon-separated hex bytes, got '{}'", + s + ))); + } + let mut mac = [0u8; 6]; + for (i, part) in parts.iter().enumerate() { + mac[i] = u8::from_str_radix(part, 16).map_err(|_| { + TransportError::InvalidAddress(format!("invalid hex byte '{}' in MAC address", part)) + })?; + } + Ok(mac) +} diff --git a/src/transport/ethernet/mod.rs b/src/transport/ethernet/mod.rs index 1856669..b5862a2 100644 --- a/src/transport/ethernet/mod.rs +++ b/src/transport/ethernet/mod.rs @@ -5,10 +5,13 @@ //! Works on wired Ethernet and WiFi interfaces (kernel mac80211 abstracts //! 802.11 transparently on Linux). +pub mod addr; pub mod discovery; pub mod io; pub mod stats; +pub use addr::parse_mac_string; + use super::{ DiscoveredPeer, PacketTx, ReceivedPacket, Transport, TransportAddr, TransportError, TransportId, TransportState, TransportType, @@ -632,24 +635,6 @@ pub fn format_mac(mac: &[u8; 6]) -> String { ) } -/// Parse a colon-separated MAC string (e.g., "aa:bb:cc:dd:ee:ff") into bytes. -pub fn parse_mac_string(s: &str) -> Result<[u8; 6], TransportError> { - let parts: Vec<&str> = s.split(':').collect(); - if parts.len() != 6 { - return Err(TransportError::InvalidAddress(format!( - "invalid MAC format: expected 6 colon-separated hex bytes, got '{}'", - s - ))); - } - let mut mac = [0u8; 6]; - for (i, part) in parts.iter().enumerate() { - mac[i] = u8::from_str_radix(part, 16).map_err(|_| { - TransportError::InvalidAddress(format!("invalid hex byte '{}' in MAC address", part)) - })?; - } - Ok(mac) -} - // ============================================================================ // Tests // ============================================================================ From e839aead7a6707181808630cd7352f66abe6b23b Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sat, 11 Jul 2026 20:26:42 +0000 Subject: [PATCH 4/4] transport: extract tcp connection-pool types into pool.rs Moves the inline TcpConnection/ConnectingEntry structs, the Direction enum, and the ConnectionPool/ConnectingPool type aliases out of the 1147-line tcp/mod.rs into a dedicated pool.rs, matching the canonical per-transport layout. Struct fields are pub(crate) so mod.rs can still construct and read them across the module boundary. Pure relocation; no logic change. --- src/transport/tcp/mod.rs | 48 ++------------------------------- src/transport/tcp/pool.rs | 56 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 46 deletions(-) create mode 100644 src/transport/tcp/pool.rs diff --git a/src/transport/tcp/mod.rs b/src/transport/tcp/mod.rs index b1975b8..23e95bd 100644 --- a/src/transport/tcp/mod.rs +++ b/src/transport/tcp/mod.rs @@ -22,6 +22,7 @@ //! No additional framing overhead — packets are written directly to the //! TCP stream and the receiver uses phase-dependent size computation. +mod pool; pub mod stats; use super::resolve_socket_addr; @@ -31,6 +32,7 @@ use super::{ }; use crate::config::TcpConfig; use crate::transport::framing::read_fmp_packet; +use pool::{ConnectingEntry, ConnectingPool, ConnectionPool, Direction, TcpConnection}; use stats::TcpStats; use futures::FutureExt; @@ -47,52 +49,6 @@ use tokio::task::JoinHandle; use tokio::time::Instant; use tracing::{debug, info, trace, warn}; -// ============================================================================ -// Connection Pool -// ============================================================================ - -/// Direction of a pooled connection, used to drive separate -/// `pool_inbound` / `pool_outbound` accounting for the -/// `max_inbound_connections` admission cap. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum Direction { - /// Inbound — accepted by the listener. - Inbound, - /// Outbound — initiated by connect-on-send or background connect. - Outbound, -} - -/// State for a single TCP connection to a peer. -struct TcpConnection { - /// Write half of the split stream. - writer: Arc>, - /// Receive task for this connection. - recv_task: JoinHandle<()>, - /// MSS-derived MTU for this connection (used for dynamic MTU re-reading). - #[allow(dead_code)] - mtu: u16, - /// When the connection was established. - #[allow(dead_code)] - established_at: Instant, - /// Direction of the connection — drives pool-inbound/outbound accounting. - direction: Direction, -} - -/// Shared connection pool. -type ConnectionPool = Arc>>; - -/// A pending background connection attempt. -/// -/// Holds the JoinHandle for a spawned TCP connect task. The task -/// produces a configured `TcpStream` and MSS-derived MTU on success. -struct ConnectingEntry { - /// Background task performing TCP connect + socket configuration. - task: JoinHandle>, -} - -/// Map of addresses with background connection attempts in progress. -type ConnectingPool = Arc>>; - // ============================================================================ // TCP Transport // ============================================================================ diff --git a/src/transport/tcp/pool.rs b/src/transport/tcp/pool.rs new file mode 100644 index 0000000..8777c37 --- /dev/null +++ b/src/transport/tcp/pool.rs @@ -0,0 +1,56 @@ +//! TCP connection pool types. +//! +//! Holds the per-connection state and the pooled/connecting maps used by the +//! TCP transport. + +use std::collections::HashMap; +use std::sync::Arc; +use tokio::net::TcpStream; +use tokio::net::tcp::OwnedWriteHalf; +use tokio::sync::Mutex; +use tokio::task::JoinHandle; +use tokio::time::Instant; + +use crate::transport::{TransportAddr, TransportError}; + +/// Direction of a pooled connection, used to drive separate +/// `pool_inbound` / `pool_outbound` accounting for the +/// `max_inbound_connections` admission cap. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Direction { + /// Inbound — accepted by the listener. + Inbound, + /// Outbound — initiated by connect-on-send or background connect. + Outbound, +} + +/// State for a single TCP connection to a peer. +pub(crate) struct TcpConnection { + /// Write half of the split stream. + pub(crate) writer: Arc>, + /// Receive task for this connection. + pub(crate) recv_task: JoinHandle<()>, + /// MSS-derived MTU for this connection (used for dynamic MTU re-reading). + #[allow(dead_code)] + pub(crate) mtu: u16, + /// When the connection was established. + #[allow(dead_code)] + pub(crate) established_at: Instant, + /// Direction of the connection — drives pool-inbound/outbound accounting. + pub(crate) direction: Direction, +} + +/// Shared connection pool. +pub(crate) type ConnectionPool = Arc>>; + +/// A pending background connection attempt. +/// +/// Holds the JoinHandle for a spawned TCP connect task. The task +/// produces a configured `TcpStream` and MSS-derived MTU on success. +pub(crate) struct ConnectingEntry { + /// Background task performing TCP connect + socket configuration. + pub(crate) task: JoinHandle>, +} + +/// Map of addresses with background connection attempts in progress. +pub(crate) type ConnectingPool = Arc>>;