ICE (native client): relay-only connections time out against a real TURN server; host-socket checks starve the relay pairs

Aperta Adatta ai principianti
#452 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

@Mr444-dev ci sta già lavorando.

Dal 3/11/2026.

  • #470 di @Mr444-dev — aperta

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
79/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
cpp

Direzione di ricerca

Inizia in src/steamnetworkingsockets/clientlib/steamnetworkingsockets_ice_client.cpp, in Think_TestPeerConnectivity(), e segui come i tipi di candidati consentiti determinano i candidati locali. Riproduci il problema con la configurazione relay-only descritta e confronta il comportamento della connessione con e senza la condizione proposta per i candidati host. Il lavoro è completato quando peer relay-only su macchine diverse si connettono tramite TURN senza che i controlli degli host-socket ritardino le coppie relay.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Version: master at d534c19 (1.6.x), native ICE client (steamnetworkingsockets_ice_client.cpp, ENABLE_ICE=ON, USE_STEAMWEBRTC=OFF), custom signaling.

Setup: k_ESteamNetworkingConfig_P2P_Transport_ICE_Enable = k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Relay, no STUN servers, one TURN server (coturn 4.6.3, use-auth-secret) with P2P_TURN_ServerList/UserList/PassList set. Both peers relay-only, on different machines, both allocate on the same TURN server.

What happens: allocations and CreatePermission succeed on both sides, the relay candidates are exchanged, and then the connection fails after the initial timeout with 5008: Timed out attempting to negotiate rendezvous ("Guessed ICE failure to be 5009: NAT traversal failed"). Verbose logging shows only ICE: STUN request 0x1 to <peer relay addr> timed out for every remote candidate. A packet capture on the TURN server shows no Send indications at all after CreatePermission: only binding requests sent directly from each peer's own socket to the other peer's relayed address, which the TURN server (correctly) drops, as it has no permission for the sender's address.

Why (as far as I can tell):

  1. Think_TestPeerConnectivity() always adds the interface's host socket as a local candidate (// Host candidate -- always present.), even when m_nPermittedCandidateTypes permits only relay candidates. So every remote relay candidate gets a host-socket pair, besides the relay pair. In relay-only mode those host pairs can't succeed: they send straight to a relayed address.
  2. Pairs are unfrozen one per remote foundation at a time (vecFoundationsUsed, keyed on m_remoteCandidate.m_sFoundation only), and host pairs sort first. So the relay pair for a remote candidate waits until every host pair for it (one per local interface) has timed out, which takes longer than the connection's initial timeout. (RFC 8445 6.1.2.6 makes a pair's foundation from both the local and the remote candidate's foundations, so host and relay pairs to the same remote candidate wouldn't share one.)

Why it's easy to miss: with both peers (or a peer and the TURN server) on one machine, the relayed address is a local address, so a "direct" host-socket check can be sent from that address and passes the TURN server's permission check as if it were relayed. Everything works until the peers are on different machines.

Repro on one machine: run coturn with its relays on an address that's also local (e.g. ip addr add 5.5.5.5/32 dev lo, --relay-ip=5.5.5.5), and drop packets that arrive on lo for the relay ports from anything but the relay ports (nft ... iifname "lo" ip daddr 5.5.5.5 udp dport 49160-49659 udp sport != 49160-49659 drop), as a real network would. Two relay-only peers then never connect; with the patch below they connect at once.

Patch (what we ship): don't add the host local candidate when only relay candidates are permitted.

--- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_ice_client.cpp
+++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_ice_client.cpp
@@ -2385,8 +2385,12 @@ void CSteamNetworkingICESession::Think_TestPeerConnectivity()
             ICELocalCandidate localCandidates[2];
             int nLocalCandidates = 0;
 
-            // Host candidate -- always present.
-            localCandidates[nLocalCandidates++] = { pIntf.get(), {} };
+            // Host candidate -- unless only relay candidates are permitted.  Then checks from the
+            // host socket would go straight to the peer's relay candidates, whose TURN server drops
+            // them (no permission for this address), and they'd hold up the relay pairs to the same
+            // remote candidates (one pair per foundation at a time) until the connection times out.
+            if ( m_nPermittedCandidateTypes & ~k_EICECandidate_Any_Relay )
+                localCandidates[nLocalCandidates++] = { pIntf.get(), {} };

The foundation point (2) probably deserves a fix of its own: in "all" mode it still delays the relay fallback behind every host pair to the same remote candidate.

Happy to open a PR with the patch if that's useful.

Lingua principale
C++
Stelle
10k
Fork
767
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di ValveSoftware/GameNetworkingSockets

Tutte le issue di ValveSoftware/GameNetworkingSockets

Issue simili

Altre issue su C++

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.