mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-10 00:26:59 +00:00
node: embed the handshake leg in the peer machine, drop the connections map
The pending-handshake PeerConnection map and the per-peer control machine map were parallel LinkId-keyed structures whose keysets must stay coherent by hand. With every leg now born with a machine, the leg becomes storage inside its machine (leg: Option<PeerConnection>, pure storage the machine never reads or drives) and Node loses the connections field; every access routes through the machine. The non-mechanical lowerings, each argued at the site: the rekey-vs-establish gate in handle_msg2 tests leg-absence (an established peer's machine stays keyed by its link, so machine-presence would misclassify every rekey msg2 as a fresh establish); the connecting-predicates, peering observation, and handshake-slot budget iterate machines-with-legs so connect-window machines (leg not yet born) are excluded exactly as before and never double-counted against their pending-connect slot; the cross-connection extract takes the leg before disposing the machine; the stale reaper takes the leg and leaves the machine untouched when none is present, matching the old early return. The map-coherence debug check keeps its machine-has-carrier direction with the embedded leg as a carrier; the leg-to-machine direction is now true by construction and its gate const is gone. connection_count() counts machines with legs; the connections() iterator, the test seams, and the control-socket connection rows are re-implemented over the embedded legs with unchanged output.
This commit is contained in:
+38
-31
@@ -372,7 +372,7 @@ impl Node {
|
||||
}
|
||||
|
||||
fn is_connecting_to_peer(&self, peer_node_addr: &NodeAddr) -> bool {
|
||||
self.connections.values().any(|conn| {
|
||||
self.connections().any(|conn| {
|
||||
conn.expected_identity()
|
||||
.map(|id| id.node_addr() == peer_node_addr)
|
||||
.unwrap_or(false)
|
||||
@@ -385,7 +385,7 @@ impl Node {
|
||||
transport_id: TransportId,
|
||||
remote_addr: &TransportAddr,
|
||||
) -> bool {
|
||||
self.connections.values().any(|conn| {
|
||||
self.connections().any(|conn| {
|
||||
conn.expected_identity()
|
||||
.map(|id| id.node_addr() == peer_node_addr)
|
||||
.unwrap_or(false)
|
||||
@@ -559,14 +559,14 @@ impl Node {
|
||||
|
||||
/// Prepare an outbound Noise msg1 at dial: allocate the session index, run
|
||||
/// the Noise leaf, frame the wire, arm the shell-side resend, track
|
||||
/// `pending_outbound`, and persist the connection. Returns `Err` on
|
||||
/// index-allocation or Noise failure (cleaning the partial leg, including
|
||||
/// the dial-time control machine), leaving the armed wire on the connection
|
||||
/// for `send_stored_msg1` to transmit. Does NOT send — so the fallible setup
|
||||
/// can propagate its error synchronously before any machine drive. The
|
||||
/// control machine itself is persisted at dial in `initiate_connection`;
|
||||
/// this function no longer touches `peer_machines` except to clean it up on
|
||||
/// the failure paths.
|
||||
/// `pending_outbound`, and embed the prepared connection on the dial-time
|
||||
/// control machine. Returns `Err` on index-allocation or Noise failure
|
||||
/// (cleaning the partial leg, including the dial-time control machine),
|
||||
/// leaving the armed wire on the connection for `send_stored_msg1` to
|
||||
/// transmit. Does NOT send — so the fallible setup can propagate its error
|
||||
/// synchronously before any machine drive. The control machine itself is
|
||||
/// persisted at dial in `initiate_connection`; this function hands it the
|
||||
/// connection on success and cleans it up on the failure paths.
|
||||
pub(in crate::node) fn prepare_outbound_msg1(
|
||||
&mut self,
|
||||
link_id: LinkId,
|
||||
@@ -633,7 +633,19 @@ impl Node {
|
||||
// Track in pending_outbound for msg2 dispatch
|
||||
self.pending_outbound
|
||||
.insert((transport_id, our_index.as_u32()), link_id);
|
||||
self.connections.insert(link_id, connection);
|
||||
|
||||
// The dial-born machine (persisted in `initiate_connection`) carries
|
||||
// the prepared connection from here. Every live caller dialed first,
|
||||
// so the machine exists; recover with a fresh one if a direct caller
|
||||
// ever skips the dial.
|
||||
debug_assert!(
|
||||
self.peer_machines.contains_key(&link_id),
|
||||
"outbound msg1 prepared for link {link_id} with no dial-time machine"
|
||||
);
|
||||
self.peer_machines
|
||||
.entry(link_id)
|
||||
.or_insert_with(|| PeerMachine::new_outbound(link_id, peer_identity, current_time_ms))
|
||||
.set_leg(connection);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -650,15 +662,11 @@ impl Node {
|
||||
transport_id: TransportId,
|
||||
remote_addr: &TransportAddr,
|
||||
) {
|
||||
let wire_msg1 = match self
|
||||
.connections
|
||||
.get(&link_id)
|
||||
.and_then(|c| c.handshake_msg1())
|
||||
{
|
||||
let wire_msg1 = match self.leg(&link_id).and_then(|c| c.handshake_msg1()) {
|
||||
Some(w) => w.to_vec(),
|
||||
None => return,
|
||||
};
|
||||
let our_index = self.connections.get(&link_id).and_then(|c| c.our_index());
|
||||
let our_index = self.leg(&link_id).and_then(|c| c.our_index());
|
||||
|
||||
// Send the wire format handshake message
|
||||
if let Some(transport) = self.transports.get(&transport_id) {
|
||||
@@ -681,7 +689,7 @@ impl Node {
|
||||
);
|
||||
// Mark connection as failed but don't remove it yet
|
||||
// The event loop can handle retry logic
|
||||
if let Some(conn) = self.connections.get_mut(&link_id) {
|
||||
if let Some(conn) = self.leg_mut(&link_id) {
|
||||
conn.mark_failed();
|
||||
}
|
||||
}
|
||||
@@ -881,14 +889,13 @@ impl Node {
|
||||
);
|
||||
let now_ms = Self::now_ms();
|
||||
let stale: Vec<LinkId> = self
|
||||
.connections
|
||||
.iter()
|
||||
.filter(|(_, conn)| {
|
||||
.connections()
|
||||
.filter(|conn| {
|
||||
conn.expected_identity()
|
||||
.map(|id| id.node_addr() == &peer_addr)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.map(|(link_id, _)| *link_id)
|
||||
.map(|conn| conn.link_id())
|
||||
.collect();
|
||||
for link_id in stale {
|
||||
self.cleanup_stale_connection(link_id, now_ms);
|
||||
@@ -1821,7 +1828,7 @@ impl Node {
|
||||
info!("Node started:");
|
||||
info!(" state: {}", self.supervisor.state);
|
||||
info!(" transports: {}", self.transports.len());
|
||||
info!(" connections: {}", self.connections.len());
|
||||
info!(" connections: {}", self.connection_count());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2665,18 +2672,17 @@ impl Node {
|
||||
/// The `connected` / `connecting` sets gate the floor, retry-dial, overlay,
|
||||
/// and LAN layers; `in_flight_by_peer` feeds the opportunistic layer's
|
||||
/// per-peer parallel cap, computed exactly as the deleted
|
||||
/// `path_candidate_attempt_budget` did: `connections(expected == addr) +
|
||||
/// `path_candidate_attempt_budget` did: `pending legs(expected == addr) +
|
||||
/// pending_connects(addr)`. The scalar counts stay unpopulated at the
|
||||
/// ceiling-only posture (no layer reads them; see [`Observed`]).
|
||||
pub(in crate::node) fn observe_peering(&self) -> Observed {
|
||||
let connected: HashSet<NodeAddr> = self.peers.keys().copied().collect();
|
||||
let connecting: HashSet<NodeAddr> = self
|
||||
.connections
|
||||
.values()
|
||||
.connections()
|
||||
.filter_map(|conn| conn.expected_identity().map(|id| *id.node_addr()))
|
||||
.collect();
|
||||
let mut in_flight_by_peer: HashMap<NodeAddr, usize> = HashMap::new();
|
||||
for conn in self.connections.values() {
|
||||
for conn in self.connections() {
|
||||
if let Some(id) = conn.expected_identity() {
|
||||
*in_flight_by_peer.entry(*id.node_addr()).or_default() += 1;
|
||||
}
|
||||
@@ -2715,9 +2721,11 @@ impl Node {
|
||||
}
|
||||
|
||||
fn outbound_handshake_slots(&self) -> usize {
|
||||
// Count pending connections (legs), not machines: a dial-born machine
|
||||
// in the connect window has no connection yet but DOES hold a
|
||||
// `pending_connects` slot, so counting machines would tally it twice.
|
||||
let used = self
|
||||
.connections
|
||||
.len()
|
||||
.connection_count()
|
||||
.saturating_add(self.peering.pending_connects.len());
|
||||
if self.max_connections() == 0 {
|
||||
usize::MAX
|
||||
@@ -2743,8 +2751,7 @@ impl Node {
|
||||
}
|
||||
|
||||
let in_flight_for_peer = self
|
||||
.connections
|
||||
.values()
|
||||
.connections()
|
||||
.filter(|conn| {
|
||||
conn.expected_identity()
|
||||
.map(|identity| identity.node_addr() == peer_node_addr)
|
||||
|
||||
Reference in New Issue
Block a user