fix: start UDP socket before connection handshake to avoid race

CryptSetup can arrive during the initial sync (before handleServerSync
completes). Previously startUDP() was called after the sync finished,
so if CryptSetup arrived first, crypto was initialized but the UDP
socket didn't exist yet — causing a permanent fallback to TCP.

Move startUDP() to immediately after writing the Version/Authenticate
packets and before waiting for the sync to complete. The UDP socket
is now ready when CryptSetup arrives.
This commit is contained in:
Brandon McGinty (deepseek)
2026-08-08 22:37:53 -04:00
committed by Brandon McGinty
parent 53918788f7
commit 0ecdbf988f
+8 -8
View File
@@ -140,6 +140,14 @@ func DialWithDialer(dialer *net.Dialer, config *Config, tlsConfig *tls.Config) (
client.Conn.WriteProto(&versionPacket)
client.Conn.WriteProto(&authenticationPacket)
// Start UDP transport immediately so it's ready when CryptSetup
// arrives during the sync handshake.
if err := client.startUDP(); err != nil {
log.Warn("UDP setup failed, audio will use TCP tunnel: %v", err)
} else if client.udpConn != nil {
log.Info("UDP socket opened to %s, waiting for CryptSetup", client.udpConn.RemoteAddr())
}
go client.pingRoutine()
var timeout <-chan time.Time
@@ -171,14 +179,6 @@ func DialWithDialer(dialer *net.Dialer, config *Config, tlsConfig *tls.Config) (
return nil, err
}
// Start UDP transport for lower-latency audio. This is best-effort;
// if UDP fails, audio falls back to TCP tunneling.
if err := client.startUDP(); err != nil {
log.Warn("UDP setup failed, audio will use TCP tunnel: %v", err)
} else if client.udpConn != nil {
log.Info("UDP socket opened to %s, waiting for CryptSetup", client.udpConn.RemoteAddr())
}
return client, nil
}
}