Skip to content

fix(iroh): Always update the best addr after changes #3422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions iroh-relay/src/protos/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
//! [RFC 5705]: https://datatracker.ietf.org/doc/html/rfc5705
use bytes::{BufMut, Bytes, BytesMut};
use data_encoding::BASE32HEX_NOPAD as HEX;
#[cfg(not(wasm_browser))]
use http::HeaderValue;
#[cfg(feature = "server")]
use iroh_base::Signature;
Expand All @@ -47,6 +48,7 @@ use crate::ExportKeyingMaterial;
const DOMAIN_SEP_CHALLENGE: &str = "iroh-relay handshake v1 challenge signature";

/// Domain separation label for [`KeyMaterialClientAuth`]'s use of [`ExportKeyingMaterial`]
#[cfg(not(wasm_browser))]
const DOMAIN_SEP_TLS_EXPORT_LABEL: &[u8] = b"iroh-relay handshake v1";

/// Authentication message from the client.
Expand Down
23 changes: 16 additions & 7 deletions iroh/src/magicsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,9 @@ impl MagicSock {
}
}
if !addr.is_empty() {
let have_ipv6 = self.ipv6_reported.load(Ordering::Relaxed);
self.node_map
.add_node_addr(addr, source, &self.metrics.magicsock);
.add_node_addr(addr, source, have_ipv6, &self.metrics.magicsock);
Ok(())
} else if pruned != 0 {
Err(EmptyPrunedSnafu { pruned }.build())
Expand Down Expand Up @@ -1254,15 +1255,20 @@ impl Handle {

let (actor_sender, actor_receiver) = mpsc::channel(256);

let ipv6_reported = false;

// load the node data
let node_map = node_map.unwrap_or_default();
#[cfg(any(test, feature = "test-utils"))]
let node_map = NodeMap::load_from_vec(node_map, path_selection, &metrics.magicsock);
#[cfg(not(any(test, feature = "test-utils")))]
let node_map = NodeMap::load_from_vec(node_map, &metrics.magicsock);
let node_map = NodeMap::load_from_vec(
node_map,
#[cfg(any(test, feature = "test-utils"))]
path_selection,
ipv6_reported,
&metrics.magicsock,
);

let my_relay = Watchable::new(None);
let ipv6_reported = Arc::new(AtomicBool::new(false));
let ipv6_reported = Arc::new(AtomicBool::new(ipv6_reported));
let max_receive_segments = Arc::new(AtomicUsize::new(1));

let relay_transport = RelayTransport::new(RelayActorConfig {
Expand Down Expand Up @@ -1861,7 +1867,8 @@ impl Actor {
// TODO: this might trigger too many packets at once, pace this

self.msock.node_map.prune_inactive();
let msgs = self.msock.node_map.nodes_stayin_alive();
let have_v6 = self.netmon_watcher.clone().get().have_v6;
let msgs = self.msock.node_map.nodes_stayin_alive(have_v6);
self.handle_ping_actions(&sender, msgs).await;
}
}
Expand Down Expand Up @@ -3183,6 +3190,7 @@ mod tests {
Source::NamedApp {
name: "test".into(),
},
true,
&msock_1.metrics.magicsock,
);
let addr_2 = msock_1.get_mapping_addr(node_id_2).unwrap();
Expand Down Expand Up @@ -3226,6 +3234,7 @@ mod tests {
Source::NamedApp {
name: "test".into(),
},
true,
&msock_1.metrics.magicsock,
);

Expand Down
67 changes: 38 additions & 29 deletions iroh/src/magicsock/node_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,20 +118,20 @@ pub enum Source {
}

impl NodeMap {
#[cfg(not(any(test, feature = "test-utils")))]
/// Create a new [`NodeMap`] from a list of [`NodeAddr`]s.
pub(super) fn load_from_vec(nodes: Vec<NodeAddr>, metrics: &Metrics) -> Self {
Self::from_inner(NodeMapInner::load_from_vec(nodes, metrics))
}

#[cfg(any(test, feature = "test-utils"))]
/// Create a new [`NodeMap`] from a list of [`NodeAddr`]s.
pub(super) fn load_from_vec(
nodes: Vec<NodeAddr>,
path_selection: PathSelection,
#[cfg(any(test, feature = "test-utils"))] path_selection: PathSelection,
have_ipv6: bool,
metrics: &Metrics,
) -> Self {
Self::from_inner(NodeMapInner::load_from_vec(nodes, path_selection, metrics))
Self::from_inner(NodeMapInner::load_from_vec(
nodes,
#[cfg(any(test, feature = "test-utils"))]
path_selection,
have_ipv6,
metrics,
))
}

fn from_inner(inner: NodeMapInner) -> Self {
Expand All @@ -141,11 +141,17 @@ impl NodeMap {
}

/// Add the contact information for a node.
pub(super) fn add_node_addr(&self, node_addr: NodeAddr, source: Source, metrics: &Metrics) {
pub(super) fn add_node_addr(
&self,
node_addr: NodeAddr,
source: Source,
have_v6: bool,
metrics: &Metrics,
) {
self.inner
.lock()
.expect("poisoned")
.add_node_addr(node_addr, source, metrics)
.add_node_addr(node_addr, source, have_v6, metrics)
}

/// Number of nodes currently listed.
Expand Down Expand Up @@ -270,11 +276,11 @@ impl NodeMap {
}
}

pub(super) fn nodes_stayin_alive(&self) -> Vec<PingAction> {
pub(super) fn nodes_stayin_alive(&self, have_ipv6: bool) -> Vec<PingAction> {
let mut inner = self.inner.lock().expect("poisoned");
inner
.node_states_mut()
.flat_map(|(_idx, node_state)| node_state.stayin_alive())
.flat_map(|(_idx, node_state)| node_state.stayin_alive(have_ipv6))
.collect()
}

Expand Down Expand Up @@ -320,36 +326,33 @@ impl NodeMap {
}

impl NodeMapInner {
#[cfg(not(any(test, feature = "test-utils")))]
/// Create a new [`NodeMap`] from a list of [`NodeAddr`]s.
fn load_from_vec(nodes: Vec<NodeAddr>, metrics: &Metrics) -> Self {
let mut me = Self::default();
for node_addr in nodes {
me.add_node_addr(node_addr, Source::Saved, metrics);
}
me
}

#[cfg(any(test, feature = "test-utils"))]
/// Create a new [`NodeMap`] from a list of [`NodeAddr`]s.
fn load_from_vec(
nodes: Vec<NodeAddr>,
path_selection: PathSelection,
#[cfg(any(test, feature = "test-utils"))] path_selection: PathSelection,
have_ipv6: bool,
metrics: &Metrics,
) -> Self {
let mut me = Self {
#[cfg(any(test, feature = "test-utils"))]
path_selection,
..Default::default()
};
for node_addr in nodes {
me.add_node_addr(node_addr, Source::Saved, metrics);
me.add_node_addr(node_addr, Source::Saved, have_ipv6, metrics);
}
me
}

/// Add the contact information for a node.
#[instrument(skip_all, fields(node = %node_addr.node_id.fmt_short()))]
fn add_node_addr(&mut self, node_addr: NodeAddr, source: Source, metrics: &Metrics) {
fn add_node_addr(
&mut self,
node_addr: NodeAddr,
source: Source,
have_ipv6: bool,
metrics: &Metrics,
) {
let source0 = source.clone();
let node_id = node_addr.node_id;
let relay_url = node_addr.relay_url.clone();
Expand All @@ -367,6 +370,7 @@ impl NodeMapInner {
node_addr.relay_url.as_ref(),
&node_addr.direct_addresses,
source0,
have_ipv6,
metrics,
);
let id = node_state.id();
Expand Down Expand Up @@ -715,6 +719,7 @@ mod tests {
Source::NamedApp {
name: "test".into(),
},
true,
&Default::default(),
)
}
Expand Down Expand Up @@ -761,8 +766,12 @@ mod tests {
Some(addr)
})
.collect();
let loaded_node_map =
NodeMap::load_from_vec(addrs.clone(), PathSelection::default(), &Default::default());
let loaded_node_map = NodeMap::load_from_vec(
addrs.clone(),
PathSelection::default(),
true,
&Default::default(),
);

let mut loaded: Vec<NodeAddr> = loaded_node_map
.list_remote_infos(Instant::now())
Expand Down
Loading
Loading