mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 08:14:42 +00:00
Implement non-blocking transport connect for connection-oriented transports
TCP (and future Tor) transports previously established connections synchronously inside send(), blocking the node's RX event loop during TCP handshake. This is particularly problematic for Tor where SOCKS5 circuit establishment can take 30-120 seconds. Add a non-blocking connect path: - ConnectionState enum in transport layer (None/Connecting/Connected/Failed) - connect_async() on TcpTransport spawns background TCP connect task - connection_state_sync() polls task completion, promotes to pool - TransportHandle gains connect() and connection_state() dispatch methods - Node tracks PendingConnect entries for connection-oriented transports - initiate_connection() defers handshake for connection-oriented transports - start_handshake() extracted as separate method for deferred invocation - poll_pending_connects() in tick handler polls and completes handshakes - Failed connects trigger retry via schedule_retry() Connectionless transports (UDP, Ethernet) are unchanged — connect() is a no-op and connection_state() always returns Connected. The existing connect-on-send path in send_async() is preserved as fallback for reconnection after connection drops. 811 tests pass (6 new), clippy clean.
This commit is contained in:
@@ -119,6 +119,9 @@ pub enum NodeError {
|
||||
|
||||
#[error("handshake failed: {0}")]
|
||||
HandshakeFailed(String),
|
||||
|
||||
#[error("transport error: {0}")]
|
||||
TransportError(String),
|
||||
}
|
||||
|
||||
/// Node operational state.
|
||||
@@ -208,6 +211,22 @@ struct TransportDropState {
|
||||
dropping: bool,
|
||||
}
|
||||
|
||||
/// State for a link waiting for transport-level connection establishment.
|
||||
///
|
||||
/// For connection-oriented transports (TCP, Tor), the transport connect runs
|
||||
/// asynchronously. This struct holds the data needed to complete the handshake
|
||||
/// once the connection is ready.
|
||||
struct PendingConnect {
|
||||
/// The link that was created for this connection.
|
||||
link_id: LinkId,
|
||||
/// Which transport is being used.
|
||||
transport_id: TransportId,
|
||||
/// The remote address being connected to.
|
||||
remote_addr: TransportAddr,
|
||||
/// The peer identity (for handshake initiation).
|
||||
peer_identity: PeerIdentity,
|
||||
}
|
||||
|
||||
/// A running FIPS node instance.
|
||||
///
|
||||
/// This is the top-level container holding all node state.
|
||||
@@ -363,6 +382,13 @@ pub struct Node {
|
||||
/// Rate limiter for source-side CoordsRequired/PathBroken responses.
|
||||
coords_response_rate_limiter: RoutingErrorRateLimiter,
|
||||
|
||||
// === Pending Transport Connects ===
|
||||
/// Links waiting for transport-level connection establishment before
|
||||
/// sending handshake msg1. For connection-oriented transports (TCP, Tor),
|
||||
/// the transport connect runs in the background; the tick handler polls
|
||||
/// connection_state() and initiates the handshake when connected.
|
||||
pending_connects: Vec<PendingConnect>,
|
||||
|
||||
// === Connection Retry ===
|
||||
/// Retry state for peers whose outbound connections have failed.
|
||||
/// Keyed by NodeAddr. Entries are created when a handshake times out
|
||||
@@ -499,6 +525,7 @@ impl Node {
|
||||
coords_response_rate_limiter: RoutingErrorRateLimiter::with_interval(
|
||||
std::time::Duration::from_millis(coords_response_interval_ms),
|
||||
),
|
||||
pending_connects: Vec::new(),
|
||||
retry_pending: HashMap::new(),
|
||||
last_parent_reeval: None,
|
||||
last_congestion_log: None,
|
||||
@@ -601,6 +628,7 @@ impl Node {
|
||||
coords_response_rate_limiter: RoutingErrorRateLimiter::with_interval(
|
||||
std::time::Duration::from_millis(coords_response_interval_ms),
|
||||
),
|
||||
pending_connects: Vec::new(),
|
||||
retry_pending: HashMap::new(),
|
||||
last_parent_reeval: None,
|
||||
last_congestion_log: None,
|
||||
|
||||
Reference in New Issue
Block a user