ipn/ipnlocal: add missing bus notify of peers on full netmap
The prior aa5da2e5f2 ("process node adds/removes in constant
time") commit missed a bus notification case, where new-style
subscribers set NotifyNoNetmap and then the controlclient map routing
sends a full update (rather than a delta). Those profiles + peers
need to be put on the bus too.
I noticed this only when porting the Android app over to use the
new bus stuff.
Updates #19607
Updates #12542
Change-Id: I82c35011d2c532222ca27f7d4e790522c31bd156
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
0e2b3f31af
commit
a8f40a2ca5
@@ -1998,6 +1998,13 @@ func (b *LocalBackend) setControlClientStatusLocked(c controlclient.Client, st c
|
|||||||
selfChange = st.NetMap.SelfNode.AsStruct()
|
selfChange = st.NetMap.SelfNode.AsStruct()
|
||||||
}
|
}
|
||||||
notify := ipn.Notify{SelfChange: selfChange}
|
notify := ipn.Notify{SelfChange: selfChange}
|
||||||
|
if b.hasPeerChangeWatcherLocked() {
|
||||||
|
notify.UserProfiles = st.NetMap.UserProfiles
|
||||||
|
notify.PeersChanged = make([]*tailcfg.Node, 0, len(st.NetMap.Peers))
|
||||||
|
for _, p := range st.NetMap.Peers {
|
||||||
|
notify.PeersChanged = append(notify.PeersChanged, p.AsStruct())
|
||||||
|
}
|
||||||
|
}
|
||||||
if goosGetsLegacyNetmapNotify {
|
if goosGetsLegacyNetmapNotify {
|
||||||
notify.NetMap = st.NetMap
|
notify.NetMap = st.NetMap
|
||||||
}
|
}
|
||||||
@@ -3887,6 +3894,18 @@ func (b *LocalBackend) notifyForSessionLocked(sess *watchSession, n *ipn.Notify)
|
|||||||
return &nCopy
|
return &nCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hasPeerChangeWatcherLocked reports whether any active watcher wants peer-set
|
||||||
|
// notifications. b.mu must be held.
|
||||||
|
func (b *LocalBackend) hasPeerChangeWatcherLocked() bool {
|
||||||
|
syncs.AssertLocked(&b.mu)
|
||||||
|
for _, sess := range b.notifyWatchers {
|
||||||
|
if sess.mask&(ipn.NotifyPeerChanges|ipn.NotifyPeerPatches) != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// setAuthURLLocked sets the authURL and triggers [LocalBackend.popBrowserAuthNow] if the URL has changed.
|
// setAuthURLLocked sets the authURL and triggers [LocalBackend.popBrowserAuthNow] if the URL has changed.
|
||||||
// This method is called when a new authURL is received from the control plane, meaning that either a user
|
// This method is called when a new authURL is received from the control plane, meaning that either a user
|
||||||
// has started a new interactive login (e.g., by running `tailscale login` or clicking Login in the GUI),
|
// has started a new interactive login (e.g., by running `tailscale login` or clicking Login in the GUI),
|
||||||
|
|||||||
@@ -2184,6 +2184,55 @@ func TestNotifyForSessionPeerVisibility(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetControlClientStatusSendsFullNetmapAsPeerChanges(t *testing.T) {
|
||||||
|
b := newTestLocalBackend(t)
|
||||||
|
nw := newNotificationWatcher(t, b, ipnauth.Self)
|
||||||
|
nw.watch(ipn.NotifyPeerChanges|ipn.NotifyNoNetMap, []wantedNotification{{
|
||||||
|
name: "full netmap as peer changes",
|
||||||
|
cond: func(t testing.TB, _ ipnauth.Actor, n *ipn.Notify) bool {
|
||||||
|
if n.SelfChange == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if n.NetMap != nil {
|
||||||
|
t.Errorf("NetMap was delivered to NotifyNoNetMap watcher")
|
||||||
|
}
|
||||||
|
if got, want := len(n.PeersChanged), 2; got != want {
|
||||||
|
t.Errorf("PeersChanged len = %d; want %d", got, want)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if got, want := len(n.UserProfiles), 3; got != want {
|
||||||
|
t.Errorf("UserProfiles len = %d; want %d", got, want)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
gotPeers := set.Of(n.PeersChanged[0].ID, n.PeersChanged[1].ID)
|
||||||
|
wantPeers := set.Of(tailcfg.NodeID(10), tailcfg.NodeID(20))
|
||||||
|
if !gotPeers.Equal(wantPeers) {
|
||||||
|
t.Errorf("PeersChanged IDs = %v; want %v", gotPeers, wantPeers)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}})
|
||||||
|
|
||||||
|
nm := &netmap.NetworkMap{
|
||||||
|
SelfNode: (&tailcfg.Node{
|
||||||
|
ID: 1,
|
||||||
|
User: 1,
|
||||||
|
Key: makeNodeKeyFromID(1),
|
||||||
|
}).View(),
|
||||||
|
Peers: []tailcfg.NodeView{
|
||||||
|
(&tailcfg.Node{ID: 10, User: 2, Key: makeNodeKeyFromID(10)}).View(),
|
||||||
|
(&tailcfg.Node{ID: 20, User: 3, Key: makeNodeKeyFromID(20)}).View(),
|
||||||
|
},
|
||||||
|
UserProfiles: map[tailcfg.UserID]tailcfg.UserProfileView{
|
||||||
|
1: (&tailcfg.UserProfile{ID: 1, LoginName: "self@example.com"}).View(),
|
||||||
|
2: (&tailcfg.UserProfile{ID: 2, LoginName: "peer1@example.com"}).View(),
|
||||||
|
3: (&tailcfg.UserProfile{ID: 3, LoginName: "peer2@example.com"}).View(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
b.SetControlClientStatus(b.cc, controlclient.Status{NetMap: nm, LoggedIn: true})
|
||||||
|
nw.check()
|
||||||
|
}
|
||||||
|
|
||||||
// TestNotifyForSessionUserProfilesGating verifies that
|
// TestNotifyForSessionUserProfilesGating verifies that
|
||||||
// [Notify.UserProfiles] is only delivered to sessions opted in to
|
// [Notify.UserProfiles] is only delivered to sessions opted in to
|
||||||
// NotifyPeerChanges/NotifyPeerPatches, and is deduped per-UserID
|
// NotifyPeerChanges/NotifyPeerPatches, and is deduped per-UserID
|
||||||
|
|||||||
Reference in New Issue
Block a user