@ -1463,15 +1463,30 @@ func (b *LocalBackend) PeerCaps(src netip.Addr) tailcfg.PeerCapMap {
return b . currentNode ( ) . PeerCaps ( src )
return b . currentNode ( ) . PeerCaps ( src )
}
}
// AppendMatchingPeers returns base with all peers that match pred appended.
//
// It acquires b.mu to read the netmap but releases it before calling pred.
func ( b * localNodeContext ) AppendMatchingPeers ( base [ ] tailcfg . NodeView , pred func ( tailcfg . NodeView ) bool ) [ ] tailcfg . NodeView {
func ( b * localNodeContext ) AppendMatchingPeers ( base [ ] tailcfg . NodeView , pred func ( tailcfg . NodeView ) bool ) [ ] tailcfg . NodeView {
var peers [ ] tailcfg . NodeView
b . mu . Lock ( )
b . mu . Lock ( )
defer b . mu . Unlock ( )
if b . netMap != nil {
ret := base
// All fields on b.netMap are immutable, so this is
if b . netMap == nil {
// safe to copy and use outside the lock.
return ret
peers = b . netMap . Peers
}
}
for _ , peer := range b . netMap . Peers {
b . mu . Unlock ( )
if pred ( peer ) {
ret := base
for _ , peer := range peers {
// The peers in b.netMap don't contain updates made via
// UpdateNetmapDelta. So only use PeerView in b.netMap for its NodeID,
// and then look up the latest copy in b.peers which is updated in
// response to UpdateNetmapDelta edits.
b . mu . Lock ( )
peer , ok := b . peers [ peer . ID ( ) ]
b . mu . Unlock ( )
if ok && pred ( peer ) {
ret = append ( ret , peer )
ret = append ( ret , peer )
}
}
}
}