Skip to content

Commit

Permalink
refactor(iroh-net): remove random choice of direct addr (#2509)
Browse files Browse the repository at this point in the history
## Description

When we had any direct addresses but not yet a best address we would
randomly try to pick one and send to it on the off chance it worked.
This required to always pick the same direct addr to send to which was
not happening and a bug.

However the scenarios in which this would speed up holepunching were
very unlikely: only really if a single direct addr known to work was
added manually would this improve things.

Simply removing this feature is rather nice:

- The direct connection still happens very quickly in the best-case
  scenario: a single ping-pong roundtrip is all it costs.  No relay
  server or discovery mechanism needed so no functionality change.

- In all other scenarios there is no change.  Connection establishment
  behaves exactly the same as before.

- There are no more confusing connection type changes at startup.
  This would go relay -> mixed (-> mixed a few times more due to the
  bug) -> direct.  Now it just goes relay -> direct which is intuitively
  what people would expect.

The simplest way to test this is by running doctor accept and connect
with direct addrs only and observe the holepunching events emitted.


## Breaking Changes

none

## Notes & open questions

This is an alternative to #2487.  And my preferred solution.

Fixes #2480.

See #2512 for the flaky test.

test_two_devices_roundtrip_network_change managed to hit a timeout on
cross CI.  Give it some more time.

## Change checklist

- [x] Self-review.
- [x] Documentation updates following the [style
guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text),
if relevant.
- [x] Tests if relevant.
- [x] All breaking changes documented.
  • Loading branch information
flub committed Jul 18, 2024
1 parent 0c03f6e commit c1c3539
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 30 deletions.
7 changes: 2 additions & 5 deletions iroh-net/src/magicsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,10 +503,7 @@ impl MagicSock {
let dest = QuicMappedAddr(dest);

let mut transmits_sent = 0;
match self
.node_map
.get_send_addrs(dest, self.ipv6_reported.load(Ordering::Relaxed))
{
match self.node_map.get_send_addrs(dest) {
Some((public_key, udp_addr, relay_url, mut msgs)) => {
let mut pings_sent = false;
// If we have pings to send, we *have* to send them out first.
Expand Down Expand Up @@ -3064,7 +3061,7 @@ mod tests {
#[tokio::test(flavor = "multi_thread")]
async fn test_two_devices_roundtrip_network_change() -> Result<()> {
time::timeout(
Duration::from_secs(50),
Duration::from_secs(90),
test_two_devices_roundtrip_network_change_impl(),
)
.await?
Expand Down
3 changes: 1 addition & 2 deletions iroh-net/src/magicsock/node_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ impl NodeMap {
pub(super) fn get_send_addrs(
&self,
addr: QuicMappedAddr,
have_ipv6: bool,
) -> Option<(
PublicKey,
Option<SocketAddr>,
Expand All @@ -204,7 +203,7 @@ impl NodeMap {
let mut inner = self.inner.lock();
let ep = inner.get_mut(NodeStateKey::QuicMappedAddr(addr))?;
let public_key = *ep.public_key();
let (udp_addr, relay_url, msgs) = ep.get_send_addrs(have_ipv6);
let (udp_addr, relay_url, msgs) = ep.get_send_addrs();
Some((public_key, udp_addr, relay_url, msgs))
}

Expand Down
28 changes: 5 additions & 23 deletions iroh-net/src/magicsock/node_map/node_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::{
};

use iroh_metrics::inc;
use rand::seq::IteratorRandom;
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;
use tracing::{debug, event, info, instrument, trace, warn, Level};
Expand Down Expand Up @@ -258,12 +257,8 @@ impl NodeState {

/// Returns the address(es) that should be used for sending the next packet.
///
/// Any or all of the UDP and relay addrs may be non-zero.
fn addr_for_send(
&mut self,
now: &Instant,
have_ipv6: bool,
) -> (Option<SocketAddr>, Option<RelayUrl>) {
/// This may return to send on one, both or no paths.
fn addr_for_send(&mut self, now: &Instant) -> (Option<SocketAddr>, Option<RelayUrl>) {
if relay_only_mode() {
debug!("in `DEV_relay_ONLY` mode, giving the relay address as the only viable address for this endpoint");
return (None, self.relay_url());
Expand All @@ -287,20 +282,8 @@ impl NodeState {
(Some(best_addr.addr), self.relay_url())
}
best_addr::State::Empty => {
// No direct connection has been used before. If we know of any possible
// candidate addresses, randomly try to use one while also sending via relay
// at the same time.
let addr = self
.direct_addr_state
.keys()
.filter(|ipp| match ipp.ip() {
IpAddr::V4(_) => true,
IpAddr::V6(_) => have_ipv6,
})
.choose_stable(&mut rand::thread_rng())
.map(|ipp| SocketAddr::from(*ipp));
trace!(udp_addr = ?addr, "best_addr is unset, use candidate addr and relay");
(addr, self.relay_url())
trace!("best_addr is unset, use relay");
(None, self.relay_url())
}
};
let typ = match (best_addr, relay_url.clone()) {
Expand Down Expand Up @@ -1103,11 +1086,10 @@ impl NodeState {
#[instrument("get_send_addrs", skip_all, fields(node = %self.node_id.fmt_short()))]
pub(crate) fn get_send_addrs(
&mut self,
have_ipv6: bool,
) -> (Option<SocketAddr>, Option<RelayUrl>, Vec<PingAction>) {
let now = Instant::now();
self.last_used.replace(now);
let (udp_addr, relay_url) = self.addr_for_send(&now, have_ipv6);
let (udp_addr, relay_url) = self.addr_for_send(&now);
let mut ping_msgs = Vec::new();

if self.want_call_me_maybe(&now) {
Expand Down
1 change: 1 addition & 0 deletions iroh/tests/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ async fn sync_gossip_bulk() -> Result<()> {

/// This tests basic sync and gossip with 3 peers.
#[tokio::test]
#[ignore = "flaky"]
async fn sync_full_basic() -> Result<()> {
let mut rng = test_rng(b"sync_full_basic");
setup_logging();
Expand Down

0 comments on commit c1c3539

Please sign in to comment.