From 0b13e180c4dcd38e3ea8ffeecc9e5ebefa023212 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 05:54:53 +0100 Subject: number handshakes This prevents late hellos from resetting the session. --- src/swarm/peer/handshake.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src/swarm/peer/handshake.rs') diff --git a/src/swarm/peer/handshake.rs b/src/swarm/peer/handshake.rs index 038dac6..f89e371 100644 --- a/src/swarm/peer/handshake.rs +++ b/src/swarm/peer/handshake.rs @@ -1,6 +1,7 @@ //! Discovering peers, the handshake (HELLO / HELLO_REPLY), and membership. use std::sync::Arc; +use std::sync::atomic::Ordering; use std::time::Duration; use anyhow::{Context, Result, anyhow, bail}; @@ -67,6 +68,9 @@ pub(crate) async fn send_hello_once(state: &AppState, peer: &str) -> Result<()> let mut peer_state = peer_state_mutex.lock().await; if peer_state.hello_state == HelloState::NotSent { // A new handshake: retries start over. + // Numbered across all peers, so a peer we forgot and meet again still + // sees a higher number than any it had from this run. + peer_state.handshake = state.handshakes.fetch_add(1, Ordering::Relaxed) + 1; peer_state.hello_state = HelloState::Sending; peer_state.hello_backoff.reset(); peer_state.hello_attempts = 0; @@ -115,6 +119,11 @@ async fn transmit_hello(state: &AppState, peer: &str) -> Result<()> { .map(|key| key.hello_tag(swarm_id.as_deref().unwrap_or(""), state.local_id(), peer)) .unwrap_or_default(); let (epoch, epoch_seq) = state.epoch_stamp().await; + // Retries repeat the handshake's number. + let handshake = match state.get_peer_state(peer).await { + Some(peer_state) => peer_state.lock().await.handshake, + None => 0, + }; state.lock_rtt().hello_sent(peer, Instant::now()); let result = state .transport @@ -127,6 +136,7 @@ async fn transmit_hello(state: &AppState, peer: &str) -> Result<()> { auth, ready: state.is_ready().await, run_id: state.run_id, + handshake, }), ) .await; @@ -293,10 +303,11 @@ pub(crate) async fn apply_neighbour_change(state: &AppState, change: topology::N // --- peer membership --------------------------------------------------------- -/// Makes `peer` a member of `swarm_id`, after its valid HELLO (`from_hello`) or -/// HELLO_REPLY. Either completes the handshake: one round trip proves both sides to -/// each other (the HELLO the sender's key, the reply the swarm ID and the responder's -/// key), so neither side needs a HELLO of its own. `ready` is what the message said. +/// Makes `peer` a member of `swarm_id`, after its valid HELLO or HELLO_REPLY. Either +/// completes the handshake: one round trip proves both sides to each other (the HELLO +/// the sender's key, the reply the swarm ID and the responder's key), so neither side +/// needs a HELLO of its own. `from_hello`: a HELLO that starts a new handshake (a resent +/// or late one doesn't). `ready` is what the message said. pub(super) async fn establish_peer( state: &AppState, peer: &str, @@ -340,8 +351,9 @@ pub(super) async fn establish_peer( }; } - // Stop our retries and sync from a clean slate. A HELLO always resets: the peer - // starts over with us. Duplicate replies (caused by our own retries) don't. + // Stop our retries and sync from a clean slate. A new handshake from the peer always + // resets: it starts over with us. Its resent HELLOs and duplicate replies (caused by + // our own retries) don't. peer_state.reports_ready = Some(ready); if from_hello || peer_state.hello_state != HelloState::Established { peer_state.hello_state = HelloState::Established; -- cgit v1.3.1