github.com/ethersphere/bee/v2@v2.2.0/pkg/p2p/libp2p/peer.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package libp2p 6 7 import ( 8 "bytes" 9 "context" 10 "sort" 11 "sync" 12 13 "github.com/ethersphere/bee/v2/pkg/p2p" 14 "github.com/ethersphere/bee/v2/pkg/swarm" 15 "github.com/libp2p/go-libp2p/core/network" 16 libp2ppeer "github.com/libp2p/go-libp2p/core/peer" 17 ma "github.com/multiformats/go-multiaddr" 18 ) 19 20 type peerRegistry struct { 21 underlays map[string]libp2ppeer.ID // map overlay address to underlay peer id 22 overlays map[libp2ppeer.ID]swarm.Address // map underlay peer id to overlay address 23 full map[libp2ppeer.ID]bool // map to track whether a node is full or light node (true=full) 24 connections map[libp2ppeer.ID]map[network.Conn]struct{} // list of connections for safe removal on Disconnect notification 25 streams map[libp2ppeer.ID]map[network.Stream]context.CancelFunc 26 mu sync.RWMutex 27 28 //nolint:misspell 29 disconnecter disconnecter // peerRegistry notifies libp2p on peer disconnection 30 network.Notifiee // peerRegistry can be the receiver for network.Notify 31 } 32 33 type disconnecter interface { 34 disconnected(swarm.Address) 35 } 36 37 func newPeerRegistry() *peerRegistry { 38 return &peerRegistry{ 39 underlays: make(map[string]libp2ppeer.ID), 40 overlays: make(map[libp2ppeer.ID]swarm.Address), 41 full: make(map[libp2ppeer.ID]bool), 42 connections: make(map[libp2ppeer.ID]map[network.Conn]struct{}), 43 streams: make(map[libp2ppeer.ID]map[network.Stream]context.CancelFunc), 44 45 Notifiee: new(network.NoopNotifiee), 46 } 47 } 48 49 func (r *peerRegistry) Exists(overlay swarm.Address) (found bool) { 50 _, found = r.peerID(overlay) 51 return found 52 } 53 54 // Disconnect removes the peer from registry in disconnect. 55 // peerRegistry has to be set by network.Network.Notify(). 56 func (r *peerRegistry) Disconnected(_ network.Network, c network.Conn) { 57 peerID := c.RemotePeer() 58 59 r.mu.Lock() 60 61 // remove only the related connection, 62 // not eventusally newly created one for the same peer 63 if _, ok := r.connections[peerID][c]; !ok { 64 r.mu.Unlock() 65 return 66 } 67 68 // if there are multiple libp2p connections, consider the node disconnected only when the last connection is disconnected 69 delete(r.connections[peerID], c) 70 if len(r.connections[peerID]) > 0 { 71 r.mu.Unlock() 72 return 73 } 74 75 delete(r.connections, peerID) 76 overlay := r.overlays[peerID] 77 delete(r.overlays, peerID) 78 delete(r.underlays, overlay.ByteString()) 79 for _, cancel := range r.streams[peerID] { 80 cancel() 81 } 82 delete(r.streams, peerID) 83 delete(r.full, peerID) 84 r.mu.Unlock() 85 r.disconnecter.disconnected(overlay) 86 87 } 88 89 func (r *peerRegistry) addStream(peerID libp2ppeer.ID, stream network.Stream, cancel context.CancelFunc) { 90 r.mu.Lock() 91 defer r.mu.Unlock() 92 if _, ok := r.streams[peerID]; !ok { 93 // it is possible that an addStream will be called after a disconnect 94 return 95 } 96 r.streams[peerID][stream] = cancel 97 } 98 99 func (r *peerRegistry) removeStream(peerID libp2ppeer.ID, stream network.Stream) { 100 r.mu.Lock() 101 defer r.mu.Unlock() 102 103 peer, ok := r.streams[peerID] 104 if !ok { 105 return 106 } 107 108 cancel, ok := peer[stream] 109 if !ok { 110 return 111 } 112 113 cancel() 114 115 delete(r.streams[peerID], stream) 116 } 117 118 func (r *peerRegistry) peers() []p2p.Peer { 119 r.mu.RLock() 120 peers := make([]p2p.Peer, 0, len(r.overlays)) 121 for p, a := range r.overlays { 122 peers = append(peers, p2p.Peer{ 123 Address: a, 124 FullNode: r.full[p], 125 }) 126 } 127 r.mu.RUnlock() 128 sort.Slice(peers, func(i, j int) bool { 129 return bytes.Compare(peers[i].Address.Bytes(), peers[j].Address.Bytes()) == -1 130 }) 131 return peers 132 } 133 134 func (r *peerRegistry) addIfNotExists(c network.Conn, overlay swarm.Address, full bool) (exists bool) { 135 peerID := c.RemotePeer() 136 r.mu.Lock() 137 defer r.mu.Unlock() 138 139 if _, ok := r.connections[peerID]; !ok { 140 r.connections[peerID] = make(map[network.Conn]struct{}) 141 } 142 // the connection is added even if the peer already exists in peer registry 143 // this is solving a case of multiple underlying libp2p connections for the same peer 144 r.connections[peerID][c] = struct{}{} 145 146 if _, exists := r.underlays[overlay.ByteString()]; exists { 147 return true 148 } 149 150 r.streams[peerID] = make(map[network.Stream]context.CancelFunc) 151 r.underlays[overlay.ByteString()] = peerID 152 r.overlays[peerID] = overlay 153 r.full[peerID] = full 154 return false 155 156 } 157 158 func (r *peerRegistry) peerID(overlay swarm.Address) (peerID libp2ppeer.ID, found bool) { 159 r.mu.RLock() 160 peerID, found = r.underlays[overlay.ByteString()] 161 r.mu.RUnlock() 162 return peerID, found 163 } 164 165 func (r *peerRegistry) overlay(peerID libp2ppeer.ID) (swarm.Address, bool) { 166 r.mu.RLock() 167 overlay, found := r.overlays[peerID] 168 r.mu.RUnlock() 169 return overlay, found 170 } 171 172 func (r *peerRegistry) fullnode(peerID libp2ppeer.ID) (bool, bool) { 173 r.mu.RLock() 174 full, found := r.full[peerID] 175 r.mu.RUnlock() 176 return full, found 177 } 178 179 func (r *peerRegistry) isConnected(peerID libp2ppeer.ID, remoteAddr ma.Multiaddr) (swarm.Address, bool) { 180 if remoteAddr == nil { 181 return swarm.ZeroAddress, false 182 } 183 184 r.mu.RLock() 185 defer r.mu.RUnlock() 186 187 overlay, found := r.overlays[peerID] 188 if !found { 189 return swarm.ZeroAddress, false 190 } 191 192 // check connection remote address 193 conns, ok := r.connections[peerID] 194 if !ok { 195 return swarm.ZeroAddress, false 196 } 197 198 for c := range conns { 199 if c.RemoteMultiaddr().Equal(remoteAddr) { 200 // we ARE connected to the peer on expected address 201 return overlay, true 202 } 203 } 204 205 return swarm.ZeroAddress, false 206 } 207 208 func (r *peerRegistry) remove(overlay swarm.Address) (found, full bool, peerID libp2ppeer.ID) { 209 r.mu.Lock() 210 peerID, found = r.underlays[overlay.ByteString()] 211 delete(r.overlays, peerID) 212 delete(r.underlays, overlay.ByteString()) 213 delete(r.connections, peerID) 214 for _, cancel := range r.streams[peerID] { 215 cancel() 216 } 217 delete(r.streams, peerID) 218 full = r.full[peerID] 219 delete(r.full, peerID) 220 r.mu.Unlock() 221 222 return found, full, peerID 223 } 224 225 func (r *peerRegistry) setDisconnecter(d disconnecter) { 226 r.disconnecter = d 227 }