Changes from Build 13
Detect silent VK TURN degradation
Adds a third watchdog condition to runWatchdog. It catches the "silent partial death" scenario where VK starts rejecting 8 of 10 pion clients with 400 Bad Request on CreatePermission refresh: the surviving 2 clients keep lastRecvTime fresh, so condition 1 never fires, while throughput quietly collapses to 1/5 of normal. UI shows conns 10/10 and 0 reconnects but nothing actually works.
The new condition counts pion Errorf/Warnf messages that match the whitelist "error response" — which is the substring pion includes in real STUN error response stringifications (CreatePermission error response (error N: ...), unexpected response type ChannelBind error response). When the counter ≥ 10 AND the first error is at least 90 seconds old, the watchdog forces a full reconnect.
The whitelist cleanly excludes local-side noise that would false-positive:
- transaction closed — from client.Close() during our own ForceReconnect
- all retransmissions failed — network-level STUN drops
- use of closed network connection — teardown writes after socket close
Fix lastRecvTime stale-after-reconnect bug
ForceReconnect now resets lastRecvTime to now() so the new session gets a fair 2-minute window before watchdog condition 1 can fire again. Previously the stale lastRecv from before the reconnect (which is exactly why condition 1 had triggered) would re-fire the watchdog on the very next 30-second tick and kill the new session before it had a chance to deliver packets.
Log source-interface address in TURN allocation
The "TURN relay allocated" log now includes the local address of the underlying UDP socket (local=IP:port), which tells us which iOS Network Extension interface was picked — cellular CGNAT 10.x.x.x vs WiFi LAN 192.168.x.x. Used this to rule out a "mixed interface" hypothesis: in practice all 10 sockets always pick the same interface per allocation batch.
Keep diagnostic logging from Build 13
Goroutine exit paths in runDTLSSession and runTURN, plus pion Failed to read / Exiting loop debug messages. Costs nothing in steady state and has helped identify multiple bugs already.
Test results
- 72 min LTE sleep: 2 reconnects, no false-positive condition 3 pairs (vs ~50% false positives in build 14)
- 40 min WiFi-only: 0 reconnects, 0 errors, 1 lost ping out of 1794
- LTE + WiFi auto-join + 30 min sleep: 0 errors, nonce rotation handled cleanly
- Home WiFi today: no 400 Bad Request cascades (the degradation seen in earlier tests appears to have been transient VK anti-abuse state)