diff options
| author | tv <tv@krebsco.de> | 2026-11-03 01:54:10 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-03 01:54:10 +0100 |
| commit | 5c96698de2c1d239985f3c0672b41f29a95ca13c (patch) | |
| tree | 14989564181022dca9cb484544e4c9b5420d2dd0 /src/swarm | |
| parent | c12ce1a67e387474d17419bb252211bf04b2e443 (diff) | |
swarm: links by whom we reach
Diffstat (limited to 'src/swarm')
| -rw-r--r-- | src/swarm/links.rs | 11 | ||||
| -rw-r--r-- | src/swarm/topology/mod.rs | 26 |
2 files changed, 25 insertions, 12 deletions
diff --git a/src/swarm/links.rs b/src/swarm/links.rs index 7f8f0b0..14c5cf6 100644 --- a/src/swarm/links.rs +++ b/src/swarm/links.rs @@ -17,7 +17,9 @@ //! renewing) or a LINKS with 0 ends it. //! //! A member the asker can't reach (on none of its transports: one on Tor alone, asked -//! from one on libp2p alone) is asked through a peer that can (`relay_for`): a LINKS +//! from one on libp2p alone; or one that doesn't answer it, as behind NAT: as choosing +//! neighbours judges it, `topology::reaches`) is asked through a peer that can +//! (`relay_for`): a LINKS //! naming the members (`of`) asks the receiver to ask them on the sender's behalf, and //! to pass their links on (`relayed`). The receiver asks each itself, or through a peer //! of its own while hops are left (`hops`), for as long as the sender asked, and holds @@ -362,7 +364,7 @@ async fn split( if member == state.local_id() || Some(member.as_str()) == exclude { continue; } - if state.transport.can_reach(&member) { + if topology::reaches(state, &member).await { direct.push(member); } else if let Some(relay) = relay_for(state, &member, exclude).await { through.entry(relay).or_default().push(member); @@ -372,7 +374,7 @@ async fn split( } /// The peer to ask `member` through, which we can't reach: an active member we reach -/// that, by the member list, is on a transport `member` is on; else one on a transport +/// (that answers us) that, by the member list, is on a transport `member` is on; else one on a transport /// we aren't on (it may know one that is). Of several, the one with the lowest pair score /// with `member` (`topology::pair_score`), so askers pick alike. Not `exclude`. async fn relay_for(state: &AppState, member: &str, exclude: Option<&str>) -> Option<String> { @@ -385,7 +387,8 @@ async fn relay_for(state: &AppState, member: &str, exclude: Option<&str>) -> Opt } { let peer_state = peer_state.lock().await; - if peer_state.liveness.is_dormant() + if peer_state.is_unreachable() + || peer_state.liveness.is_dormant() || !matches!(peer_state.standing, crate::state::Standing::Member { .. }) { continue; diff --git a/src/swarm/topology/mod.rs b/src/swarm/topology/mod.rs index e3479e3..992c448 100644 --- a/src/swarm/topology/mod.rs +++ b/src/swarm/topology/mod.rs @@ -142,6 +142,19 @@ pub(crate) fn intended_graph(state: &AppState) -> Option<BTreeMap<String, BTreeS Some(graph) } +/// Whether we reach `peer` ourselves, as choosing neighbours judges it: on one of our +/// transports, and not unanswered (three HELLOs, or dormant: `PeerState::is_unreachable`). +/// One we have no word of yet counts as reached until it fails to answer. +pub(crate) async fn reaches(state: &AppState, peer: &str) -> bool { + if !state.transport.can_reach(peer) { + return false; + } + match state.get_peer_state(peer).await { + Some(peer_state) => !peer_state.lock().await.is_unreachable(), + None => true, + } +} + /// The transports `member` is on, by the member list (the schemes of its addresses); /// ours as we are on them. None known: empty. pub(crate) fn transports_of(state: &AppState, member: &str) -> BTreeSet<String> { @@ -251,18 +264,15 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { if member == state.local_id() { continue; } - if !state.transport.can_reach(member) { + if !reaches(state, member).await { unreachable.insert(member.clone()); continue; } - let (gone, heard) = match state.get_peer_state(member).await { - Some(peer_state) => { - let peer_state = peer_state.lock().await; - (peer_state.is_unreachable(), peer_state.last_seen.is_some()) - } - None => (false, false), + let heard = match state.get_peer_state(member).await { + Some(peer_state) => peer_state.lock().await.last_seen.is_some(), + None => false, }; - if gone || (!heard && !alive.contains(member)) { + if !heard && !alive.contains(member) { unreachable.insert(member.clone()); } } |
