fix(relay): rebuild sockets opened on the wrong transport

connectAndSyncFiltersIfDisconnected() bailed whenever a socket already
existed, so a still-connecting socket built for the wrong transport (e.g.
a relay whose Tor classification changed since the dial started) could
never be preempted — it blocked until the hung dial timed out. The
connected-relay path in RelayPool.reconnectIfNeedsTo already rebuilds
ready sockets via needsToReconnect(); this covers the connecting state it
cannot see (isConnectionStarted() true but isConnected() false).

Now: if a socket exists but reports needsReconnect() (transport/proxy
mismatch against the current builder decision), drop it and redial on the
correct transport; otherwise leave it. Disconnected relays still honor
their reconnect backoff.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vitor Pamplona
2026-06-11 13:34:49 -04:00
co-authored by Claude Opus 4.8
parent f2cce3dc87
commit d1bd5734cd
@@ -212,12 +212,27 @@ open class BasicRelayClient(
}
override fun connectAndSyncFiltersIfDisconnected(ignoreRetryDelays: Boolean) {
if (!isConnectionStarted() && !connectingMutex.load()) {
// waits 60 seconds to reconnect after disconnected.
if (ignoreRetryDelays || TimeUtils.now() > lastConnectTentativeInSeconds + delayToConnectInSeconds) {
upRelayDelayToConnect()
if (connectingMutex.load()) return
if (isConnectionStarted()) {
// A socket already exists. Normally leave it alone, but if it was opened for the wrong
// transport — e.g. the relay's Tor classification changed since (a clearnet relay now routed
// through the Tor proxy, or vice-versa) — tear it down and rebuild on the current transport.
// Without this an in-flight dial on the wrong transport can never be preempted: a still-
// connecting socket leaves isConnectionStarted() true (so the old guard skipped it) yet
// isConnected() false (so RelayPool.reconnectIfNeedsTo's connected-relay branch never runs),
// and the request blocks until that hung dial finally times out.
if (socket?.needsReconnect() == true) {
disconnect()
connect()
}
return
}
// waits 60 seconds to reconnect after disconnected.
if (ignoreRetryDelays || TimeUtils.now() > lastConnectTentativeInSeconds + delayToConnectInSeconds) {
upRelayDelayToConnect()
connect()
}
}