mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 08:14:42 +00:00
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:
@@ -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,
|
||||
|
||||
@@ -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,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
|
||||
// ============================================================================
|
||||
|
||||
@@ -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
|
||||
// ============================================================================
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user