fix(hole-punch): connect UDP when STUN mapping differs (#2680)

* fix(hole-punch): connect UDP without reverse probe gating

Start cone UDP handshakes on the same punched socket without waiting
for reverse HolePunch packets. Keep outgoing probes while the existing
session layer retries SYN, allowing a reachable listener to reply to the
actual source when the STUN candidate uses a different mapping.

Register source observers on the listener's existing receive loop for
the active cone RPC. Send bounded batches to the signaled endpoint and
the first matching observed source, deduplicating equal endpoints.
Unregister observers on completion, cancellation, or listener shutdown.

Cover missing reverse probes, dropped SYN, late observed sources,
transaction isolation, and cleanup. Document socket and connectivity
ownership of observation and reply policy.

* fix(hole-punch): prepare source observation during listener selection

Carry an optional transaction ID in SelectPunchListener and echo it only
after registering the listener's existing UDP receive loop. Preserve the
first source arriving before SendPunchPacketCone, then transfer cleanup
ownership to that RPC without clearing the observed address.

Keep prepared and active registrations in the same transaction table.
Expire abandoned preparations after 30 seconds through listener cleanup;
active observers still unregister on completion or cancellation.
Preserve legacy requests without a transaction ID and tolerate older
responses without a registration acknowledgement.

Cover early packets, transaction ID zero, preparation expiry, active RPC
cleanup, legacy protobuf interoperability, and SYN retries against peers
with and without registration confirmation. Document the lifetime and
compatibility contract in the core architecture.

Validation: 820 core tests; workspace fmt and full-feature clippy
passed.
This commit is contained in:
KKRainbow authored and GitHub committed 2026-10-12 23:19:46 +08:00
1 parent 4b4f0c3cb3
commit d31396f04c
11 files changed
+1014 -93

No files matched your search

+15
View File
@@ -179,6 +179,21 @@ wire codecs. It does not own socket I/O or connection policy.
- UDP session multiplexing, classification, and lifecycle;
- in-process Ring sockets.
UDP sessions expose a scoped hole-punch source observer keyed by transaction
ID. Listeners carry a registration handle for their existing receive loop, which
reports the first matching source; dropping the observer removes the registration.
Cone clients optionally prepare that transaction in the listener-selection RPC;
the response echoes its ID only after registration. The registration retains
early UDP sources until the cone-sending RPC claims it. Unclaimed registrations
expire after 30 seconds through the existing listener cleanup loop, covering
local socket and STUN preparation without a separate receive or sending task.
Clients omitting the optional transaction retain registration at the sending RPC;
older servers omit the echoed ID and do not confirm early registration.
Connectivity owns preparation expiry, the active RPC lifetime, candidate selection
and bounded sending to the signaled and observed addresses.
Cone clients start the existing UDP handshake without requiring a reverse
hole-punch packet, and the session layer remains the sole receiver.
`host/` is the single home of Host capability seams:
- DNS and DNS record resolution;