Commit Graph

7 Commits

Author SHA1 Message Date
Zoltán Papp
cfd3a231e2 [client] Reconnect management and signal promptly after a network change
Three pieces, each verified on Android across WiFi/cellular switches:

- A sweep-aware backoff wrapper: the first retry after a disconnect
  that follows a recent network-change mark comes after 200ms instead
  of the randomized [0..1.6s] interval. Any other failure keeps the
  unchanged spread, so the clients of a restarted server still scatter
  their reconnects.
- The retry sleep wakes on OS network availability transitions
  (nbgrpc.Retry): a disconnect that precedes the offline flag by a few
  milliseconds no longer sleeps blindly through the recovery - the
  loop parks on the netstate gate and resumes the moment the network
  returns.
- The connection state is re-checked after WaitForStateChange: a dial
  settling in Ready proceeds immediately instead of burning another
  backoff round on an already-usable channel.

Measured after a network switch: management and signal recover in
270-470ms deterministically, down from a 312-1593ms lottery.
2026-08-13 15:49:44 +02:00
Zoltán Papp
31e558a64d [client] Sweep only stale connections after a network change
Stamp every registered connection and in-flight dial with a network
generation, bumped by MarkNetworkChange, which replaces the immediate
full sweep with one delayed by a configurable 500ms. The sweep then
cuts only registrations older than the last change: subsystems that
redialed on their own hold fresh-generation connections and survive,
so the callers no longer need cancellation logic around the sweep.
A connection inherits its dial's generation, because the socket was
bound to the network that was default when the dial started.

This fixes the sweep being cancelled by the engine's management-level
reconnect while the relay was still down, and lets the mobile
notifiers shrink to plain forwarders.
2026-08-13 14:54:19 +02:00
Zoltán Papp
ecce1aa2a1 [client] Give the netsweep registry a named id type
The connection and dial registries keyed on a bare uint64, which says
nothing about what the number identifies. Introduce sweepID so the maps,
the counter and the id fields state their intent. No behavior change.
2026-08-12 10:14:51 +02:00
Zoltán Papp
71a4276426 [client] Group the netsweep dial API and the Android network hooks
Move the Dial type and its Ctx/Release methods above the Sweeper in
netsweep.go, and relocate SetNetworkAvailable / NotifyNetworkChange below
GetTunSettings in the Android binding. Pure code moves, no behavior change.
2026-08-12 09:39:18 +02:00
Zoltán Papp
71bfc73cd1 [client] Hand off dialed connections to the sweeper atomically
WrapDialContext and WrapConn registered the dial and the connection
independently, so a sweep landing between the dial finishing and WrapConn
cancelled only the dial registration: the connection dialed on the old
network entered the fresh registry and survived the network change.

Replace the pair with a Dial handle. Sweep marks pending dials under the
sweeper mutex, and WrapConn decides under the same mutex: a swept dial's
connection is closed and ErrSwept returned, so the caller redials on the
new network; otherwise the connection transfers to the registry with no
window in between.
2026-08-11 18:09:37 +02:00
Zoltán Papp
77e7d82d5a [client] Keep the peer endpoint open in the sweep test
connPair closed the accepted connection right after the handshake, so the
reads in TestSweepClosesRegisteredConns failed on the peer's own close
rather than on the sweep. The test passed even with Sweep's close loop
removed. Hold the peer until cleanup so the read errors come from Sweep.
2026-08-11 17:59:48 +02:00
Zoltan Papp
8fb3e707af [client] Keep the iOS ConnectionListener source-compatible
Adding OnStateChanged to the gomobile interface forces every Swift
implementation to grow the method before the app builds again. Drop it
from the iOS binding for now — the adapter satisfies the internal
listener with a no-op and the legacy per-state callbacks keep firing —
so the app upgrades on its own schedule. The state constants stay
exported for that follow-up.
2026-08-11 00:58:50 +02:00