From 45dc3fe46c411899769fbd794e8d7d417fc78767 Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Thu, 2 Nov 2023 14:23:54 +0200 Subject: [PATCH] Use IPv4 fallback in `reserve_listener()` --- node/actors/network/src/consensus/tests.rs | 4 +- node/actors/network/src/gossip/tests.rs | 4 +- node/actors/network/src/testonly.rs | 40 +++++++++---------- node/actors/network/src/tests.rs | 4 +- node/libs/concurrency/src/net/tcp/testonly.rs | 14 ++++++- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/node/actors/network/src/consensus/tests.rs b/node/actors/network/src/consensus/tests.rs index faf83064..089e47ec 100644 --- a/node/actors/network/src/consensus/tests.rs +++ b/node/actors/network/src/consensus/tests.rs @@ -16,12 +16,12 @@ async fn test_one_connection_per_validator() { let mut nodes = testonly::Instance::new(rng, 3, 1); scope::run!(ctx, |ctx,s| async { - for (i,n) in nodes.iter().enumerate() { + for (i, node) in nodes.iter().enumerate() { let (network_pipe, _) = pipe::new(); s.spawn_bg(run_network( ctx, - n.state.clone(), + node.state.clone(), network_pipe ).instrument(tracing::info_span!("node", i))); } diff --git a/node/actors/network/src/gossip/tests.rs b/node/actors/network/src/gossip/tests.rs index a5156284..3637efc5 100644 --- a/node/actors/network/src/gossip/tests.rs +++ b/node/actors/network/src/gossip/tests.rs @@ -29,12 +29,12 @@ async fn test_one_connection_per_node() { let mut nodes: Vec<_> = testonly::Instance::new(rng, 5, 2); scope::run!(ctx, |ctx,s| async { - for n in &nodes { + for node in &nodes { let (network_pipe, _) = pipe::new(); s.spawn_bg(run_network( ctx, - n.state.clone(), + node.state.clone(), network_pipe )); } diff --git a/node/actors/network/src/testonly.rs b/node/actors/network/src/testonly.rs index fd047daf..72007f28 100644 --- a/node/actors/network/src/testonly.rs +++ b/node/actors/network/src/testonly.rs @@ -53,26 +53,26 @@ impl Instance { pub fn new_configs(rng: &mut R, n: usize, gossip_peers: usize) -> Vec { let keys: Vec = (0..n).map(|_| rng.gen()).collect(); let validators = validator::ValidatorSet::new(keys.iter().map(|k| k.public())).unwrap(); - let mut cfgs: Vec<_> = (0..n) - .map(|i| { - let addr = net::tcp::testonly::reserve_listener(); - Config { - server_addr: addr, - validators: validators.clone(), - consensus: Some(consensus::Config { - key: keys[i].clone(), - public_addr: *addr, - }), - gossip: gossip::Config { - key: rng.gen(), - dynamic_inbound_limit: n as u64, - static_inbound: HashSet::default(), - static_outbound: HashMap::default(), - enable_pings: true, - }, - } - }) - .collect(); + let configs = keys.iter().map(|key| { + let addr = net::tcp::testonly::reserve_listener(); + Config { + server_addr: addr, + validators: validators.clone(), + consensus: Some(consensus::Config { + key: key.clone(), + public_addr: *addr, + }), + gossip: gossip::Config { + key: rng.gen(), + dynamic_inbound_limit: n as u64, + static_inbound: HashSet::default(), + static_outbound: HashMap::default(), + enable_pings: true, + }, + } + }); + let mut cfgs: Vec<_> = configs.collect(); + for i in 0..cfgs.len() { for j in 0..gossip_peers { let j = (i + j + 1) % n; diff --git a/node/actors/network/src/tests.rs b/node/actors/network/src/tests.rs index fda4675c..ce42f70b 100644 --- a/node/actors/network/src/tests.rs +++ b/node/actors/network/src/tests.rs @@ -12,10 +12,10 @@ async fn test_metrics() { let rng = &mut ctx.rng(); let nodes = testonly::Instance::new(rng, 3, 1); scope::run!(ctx, |ctx, s| async { - for (i, n) in nodes.iter().enumerate() { + for (i, node) in nodes.iter().enumerate() { let (network_pipe, _) = pipe::new(); s.spawn_bg( - run_network(ctx, n.state.clone(), network_pipe) + run_network(ctx, node.state.clone(), network_pipe) .instrument(tracing::info_span!("node", i)), ); } diff --git a/node/libs/concurrency/src/net/tcp/testonly.rs b/node/libs/concurrency/src/net/tcp/testonly.rs index 08ace50b..7406f691 100644 --- a/node/libs/concurrency/src/net/tcp/testonly.rs +++ b/node/libs/concurrency/src/net/tcp/testonly.rs @@ -1,13 +1,23 @@ //! Test-only TCP utilities. use super::{accept, connect, ListenerAddr, Stream, RESERVED_LISTENER_ADDRS}; use crate::{ctx, scope}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; /// Reserves a random port on localhost for a TCP listener. pub fn reserve_listener() -> ListenerAddr { - let guard = tokio::net::TcpSocket::new_v6().unwrap(); + // Try to bind to an Ipv6 address, then fall back to Ipv4 if Ipv6 is not available. + let localhost_addr = SocketAddr::from((Ipv6Addr::LOCALHOST, 0)); + let mut guard = tokio::net::TcpSocket::new_v6().unwrap(); guard.set_reuseaddr(true).unwrap(); guard.set_reuseport(true).unwrap(); - guard.bind("[::1]:0".parse().unwrap()).unwrap(); + + if guard.bind(localhost_addr).is_err() { + let localhost_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 0)); + guard = tokio::net::TcpSocket::new_v4().unwrap(); + guard.set_reuseaddr(true).unwrap(); + guard.set_reuseport(true).unwrap(); + guard.bind(localhost_addr).unwrap(); + } let addr = guard.local_addr().unwrap(); RESERVED_LISTENER_ADDRS.lock().unwrap().insert(addr, guard); ListenerAddr(addr)