Merge branch 'refactor-transport' into refactor-next

Brings the canonical per-transport layout normalization (udp/ethernet
byte-layer renamed to io, ethernet addr.rs home, tcp pool.rs extraction)
onto the next line. Clean three-way auto-merge; behavior-neutral.
This commit is contained in:
Johnathan Corgan
2026-07-11 20:32:52 +00:00
10 changed files with 98 additions and 80 deletions
+5 -5
View File
@@ -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,
+21
View File
@@ -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)
}
@@ -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)]
@@ -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-
+5 -20
View File
@@ -5,17 +5,20 @@
//! Works on wired Ethernet and WiFi interfaces (kernel mac80211 abstracts
//! 802.11 transparently on Linux).
pub mod addr;
pub mod discovery;
pub mod socket;
pub mod io;
pub mod stats;
pub use addr::parse_mac_string;
use super::{
DiscoveredPeer, PacketTx, ReceivedPacket, Transport, TransportAddr, TransportError,
TransportId, TransportState, TransportType,
};
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 std::sync::Arc;
@@ -609,24 +612,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
// ============================================================================
+2 -46
View File
@@ -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<Mutex<OwnedWriteHalf>>,
/// 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<Mutex<HashMap<TransportAddr, TcpConnection>>>;
/// 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<Result<(TcpStream, u16), TransportError>>,
}
/// Map of addresses with background connection attempts in progress.
type ConnectingPool = Arc<Mutex<HashMap<TransportAddr, ConnectingEntry>>>;
// ============================================================================
// TCP Transport
// ============================================================================
+56
View File
@@ -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<Mutex<OwnedWriteHalf>>,
/// 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<Mutex<HashMap<TransportAddr, TcpConnection>>>;
/// 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<Result<(TcpStream, u16), TransportError>>,
}
/// Map of addresses with background connection attempts in progress.
pub(crate) type ConnectingPool = Arc<Mutex<HashMap<TransportAddr, ConnectingEntry>>>;
@@ -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
+2 -2
View File
@@ -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;