Repository navigation
Conversation
iroh starts a holepunching round when a connection comes up, when an address changes, or once a minute, and only from the side holding a client connection. A failed first round left a pair on the relay for up to a minute, and guest-to-guest pairs had no connection until the race started. - punch: hold a PUNCH_ALPN connection to every lobby member (and the race roster). Reopening it while the peer is relayed starts a new round from our side: every 6 s for a minute, then every 30 s. A direct path found on any connection to a peer is used by all of them. - Resend Nat to the host when the net report changes the hard-NAT flag: guests sent it before the first report, so it was nearly always false. - Accept incoming handshakes off the session loop, so they no longer stall it (and the pads) for a relayed round trip. - Bump the lobby ALPN to ctr-rust/lobby/14 so old and new builds do not share lobbies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- punch: a direct peer is held on one connection (no new ones on every `set`, ourselves and repeats left out); a peer left out of the set is let go; an endpoint without sockets punches nothing. - loopback: the host holds a punch connection and does not take it for a guest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jmiettine
force-pushed
the
feature/optimize_p2p_connections
branch
from
November 5, 2026 20:10
a1bdfcb to
46aa090
Compare
- punch: each peer added or dropped, each attempt and how it ended (direct and by which path, still relayed, unreachable), and a direct path that is lost. - session: our NAT as iroh's net report says it (or that it is not known yet), what a guest told the host and when it told it again, and the roster's hard NATs at the start of a race. - peers: which links each player dials, next to the roster's flags. Shown with RUST_LOG=net=debug (with iroh::_events=debug for iroh's side). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why connections stayed on the relay
From iroh 1.4.1's source:
Start, so they only got the loading time before Go to punch.Nat { hard }right after joining, before the first net report, so it was nearly alwaysfalse. That broke the "hard NAT dials" rule into_dial.Changes
crates/net/src/punch.rs. Each peer holds a short-livedPUNCH_ALPNconnection to every lobby member and the race roster. Opening one starts a round from our side. While the peer is still relayed, it is reopened every 6 s for a minute, then every 30 s. Once direct, it is just watched, and punching starts again if the path falls back to the relay. A direct path found on any connection to a peer is used by all of them, so the lobby connection and mesh links get it too. Disabled in the browser and in relay-only mode.Natis resent to the host when the net report changes the hard-NAT flag. Old hosts already accepted repeatedNat, so the wire format is unchanged.ctr-rust/lobby/14. Old builds would refuse the punch connections only partway through the handshake, so each attempt would stall an old peer's loop. The bump keeps the two builds apart, and the realm listing greys out the other build's lobbies.Testing
New tests:
punch.rsunit tests, on two local endpoints found through an in-memory address lookup (no relay or DNS):a_direct_peer_is_held_on_one_connection: one punch connection is opened and held past the first retry window, though the peer set is given again every 100 ms, as the session does. Ourselves and repeated peers are left out.a_peer_left_out_of_the_set_is_let_go: removing a peer closes its punch connection.without_sockets_of_our_own_nothing_is_punched: relay-only mode punches nothing.loopback.rs:a_punch_connection_to_the_host_is_held_and_is_no_guest: the host keeps a bare endpoint's punch connection open, doesn't count it as a guest, and a real guest still joins.The first and last of these were checked by breaking the code on purpose (reopening while direct; the host treating punch connections as guests). Each failed as it should.
Results:
cargo test -p net --lib: 30 passed. The held-connection test adds about 8 s.cargo test -p net --test loopback: 16 passed on two runs in a row. One run before handshakes moved off the loop had a single timeout ina_guest_with_another_build_is_turned_away. It didn't recur.Not covered by tests: resending
Nat(needs iroh's net report to change its answer), relay→direct upgrades (local endpoints are direct from the start), and handshakes not blocking the loop (covered only by the existing suite passing).Not yet tried on real NATs. Loopback involves no relay or NAT. To check: the
relayflag inEvent::Rtt/net_info(), andRUST_LOG=iroh::_events=debug(qnt::initlines, one per round).Symmetric ↔ port-restricted and symmetric ↔ symmetric pairs mostly still can't be punched (iroh does no port prediction), so those stay on the relay.
🤖 Generated with Claude Code