mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-08 07:51:28 +02:00
[client] Fix two concurrency bugs in the Android session binding
Status() read the run loop's label outside any synchronization and then stored it, so a login or extend completing in that window was undone by the stale observation, stranding the UI on "login required" over a healthy session. Guard the latch with a mutex and a generation counter, and route both clears through the same helper, so a clear that lands mid-observation wins. The watch goroutines kept delivering to removed and replaced listeners: both subscriptions are buffered (one pending tick, ten pending events), and unsubscribing only stops new items while the loops drain what is already queued. On Android those callbacks cross into Java, so a delivery after teardown can reach a listener whose collaborators are gone. Give each registration a done signal, close it before unsubscribing, and check it immediately before every callback.
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
||||
"os"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
@@ -80,10 +79,17 @@ type Client struct {
|
||||
stateChangeMu sync.Mutex
|
||||
stateChangeSubID string
|
||||
eventSub *peer.EventSubscription
|
||||
// Closed to stop the watch goroutines from delivering buffered items to a
|
||||
// listener that has been removed or replaced. See stopStateChangeWatchLocked.
|
||||
stateChangeDone chan struct{}
|
||||
|
||||
// Latched "the server wants an interactive login": survives the engine
|
||||
// restarts that replace the run loop's context state. See Client.Status.
|
||||
loginRequired atomic.Bool
|
||||
// Guarded by loginRequiredMu together with loginCleared, which counts
|
||||
// clears so a stale observation cannot re-latch over one.
|
||||
loginRequiredMu sync.Mutex
|
||||
loginRequired bool
|
||||
loginCleared uint64
|
||||
|
||||
extendMu sync.Mutex
|
||||
extendCancel context.CancelFunc
|
||||
@@ -162,7 +168,7 @@ func (c *Client) Run(platformFiles PlatformFiles, urlOpener URLOpener, isAndroid
|
||||
}
|
||||
// This path runs the interactive SSO flow, so reaching here means the peer
|
||||
// is authenticated again — release the latch Status() reports from.
|
||||
c.loginRequired.Store(false)
|
||||
c.clearLoginRequired()
|
||||
|
||||
// todo do not throw error in case of cancelled context
|
||||
ctx = internal.CtxInitState(ctx)
|
||||
|
||||
Reference in New Issue
Block a user