github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/net/mock/mock_peernet.go (about) 1 package mocknet 2 3 import ( 4 "fmt" 5 "math/rand" 6 "sync" 7 8 inet "github.com/ipfs/go-ipfs/p2p/net" 9 peer "github.com/ipfs/go-ipfs/p2p/peer" 10 11 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 12 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" 13 goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" 14 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 15 ) 16 17 // peernet implements inet.Network 18 type peernet struct { 19 mocknet *mocknet // parent 20 21 peer peer.ID 22 ps peer.Peerstore 23 24 // conns are actual live connections between peers. 25 // many conns could run over each link. 26 // **conns are NOT shared between peers** 27 connsByPeer map[peer.ID]map[*conn]struct{} 28 connsByLink map[*link]map[*conn]struct{} 29 30 // implement inet.Network 31 streamHandler inet.StreamHandler 32 connHandler inet.ConnHandler 33 34 notifmu sync.RWMutex 35 notifs map[inet.Notifiee]struct{} 36 37 proc goprocess.Process 38 sync.RWMutex 39 } 40 41 // newPeernet constructs a new peernet 42 func newPeernet(ctx context.Context, m *mocknet, p peer.ID, ps peer.Peerstore) (*peernet, error) { 43 44 n := &peernet{ 45 mocknet: m, 46 peer: p, 47 ps: ps, 48 49 connsByPeer: map[peer.ID]map[*conn]struct{}{}, 50 connsByLink: map[*link]map[*conn]struct{}{}, 51 52 notifs: make(map[inet.Notifiee]struct{}), 53 } 54 55 n.proc = goprocessctx.WithContextAndTeardown(ctx, n.teardown) 56 return n, nil 57 } 58 59 func (pn *peernet) teardown() error { 60 61 // close the connections 62 for _, c := range pn.allConns() { 63 c.Close() 64 } 65 return nil 66 } 67 68 // allConns returns all the connections between this peer and others 69 func (pn *peernet) allConns() []*conn { 70 pn.RLock() 71 var cs []*conn 72 for _, csl := range pn.connsByPeer { 73 for c := range csl { 74 cs = append(cs, c) 75 } 76 } 77 pn.RUnlock() 78 return cs 79 } 80 81 // Close calls the ContextCloser func 82 func (pn *peernet) Close() error { 83 return pn.proc.Close() 84 } 85 86 func (pn *peernet) Peerstore() peer.Peerstore { 87 return pn.ps 88 } 89 90 func (pn *peernet) String() string { 91 return fmt.Sprintf("<mock.peernet %s - %d conns>", pn.peer, len(pn.allConns())) 92 } 93 94 // handleNewStream is an internal function to trigger the client's handler 95 func (pn *peernet) handleNewStream(s inet.Stream) { 96 pn.RLock() 97 handler := pn.streamHandler 98 pn.RUnlock() 99 if handler != nil { 100 go handler(s) 101 } 102 } 103 104 // handleNewConn is an internal function to trigger the client's handler 105 func (pn *peernet) handleNewConn(c inet.Conn) { 106 pn.RLock() 107 handler := pn.connHandler 108 pn.RUnlock() 109 if handler != nil { 110 go handler(c) 111 } 112 } 113 114 // DialPeer attempts to establish a connection to a given peer. 115 // Respects the context. 116 func (pn *peernet) DialPeer(ctx context.Context, p peer.ID) (inet.Conn, error) { 117 return pn.connect(p) 118 } 119 120 func (pn *peernet) connect(p peer.ID) (*conn, error) { 121 // first, check if we already have live connections 122 pn.RLock() 123 cs, found := pn.connsByPeer[p] 124 if found && len(cs) > 0 { 125 var chosen *conn 126 for c := range cs { // because cs is a map 127 chosen = c // select first 128 break 129 } 130 pn.RUnlock() 131 return chosen, nil 132 } 133 pn.RUnlock() 134 135 log.Debugf("%s (newly) dialing %s", pn.peer, p) 136 137 // ok, must create a new connection. we need a link 138 links := pn.mocknet.LinksBetweenPeers(pn.peer, p) 139 if len(links) < 1 { 140 return nil, fmt.Errorf("%s cannot connect to %s", pn.peer, p) 141 } 142 143 // if many links found, how do we select? for now, randomly... 144 // this would be an interesting place to test logic that can measure 145 // links (network interfaces) and select properly 146 l := links[rand.Intn(len(links))] 147 148 log.Debugf("%s dialing %s openingConn", pn.peer, p) 149 // create a new connection with link 150 c := pn.openConn(p, l.(*link)) 151 return c, nil 152 } 153 154 func (pn *peernet) openConn(r peer.ID, l *link) *conn { 155 lc, rc := l.newConnPair(pn) 156 log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer()) 157 pn.addConn(lc) 158 pn.notifyAll(func(n inet.Notifiee) { 159 n.Connected(pn, lc) 160 }) 161 rc.net.remoteOpenedConn(rc) 162 return lc 163 } 164 165 func (pn *peernet) remoteOpenedConn(c *conn) { 166 log.Debugf("%s accepting connection from %s", pn.LocalPeer(), c.RemotePeer()) 167 pn.addConn(c) 168 pn.handleNewConn(c) 169 pn.notifyAll(func(n inet.Notifiee) { 170 n.Connected(pn, c) 171 }) 172 } 173 174 // addConn constructs and adds a connection 175 // to given remote peer over given link 176 func (pn *peernet) addConn(c *conn) { 177 pn.Lock() 178 defer pn.Unlock() 179 180 cs, found := pn.connsByPeer[c.RemotePeer()] 181 if !found { 182 cs = map[*conn]struct{}{} 183 pn.connsByPeer[c.RemotePeer()] = cs 184 } 185 pn.connsByPeer[c.RemotePeer()][c] = struct{}{} 186 187 cs, found = pn.connsByLink[c.link] 188 if !found { 189 cs = map[*conn]struct{}{} 190 pn.connsByLink[c.link] = cs 191 } 192 pn.connsByLink[c.link][c] = struct{}{} 193 } 194 195 // removeConn removes a given conn 196 func (pn *peernet) removeConn(c *conn) { 197 pn.Lock() 198 defer pn.Unlock() 199 200 cs, found := pn.connsByLink[c.link] 201 if !found || len(cs) < 1 { 202 panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.link)) 203 } 204 delete(cs, c) 205 206 cs, found = pn.connsByPeer[c.remote] 207 if !found { 208 panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.remote)) 209 } 210 delete(cs, c) 211 } 212 213 // Process returns the network's Process 214 func (pn *peernet) Process() goprocess.Process { 215 return pn.proc 216 } 217 218 // LocalPeer the network's LocalPeer 219 func (pn *peernet) LocalPeer() peer.ID { 220 return pn.peer 221 } 222 223 // Peers returns the connected peers 224 func (pn *peernet) Peers() []peer.ID { 225 pn.RLock() 226 defer pn.RUnlock() 227 228 peers := make([]peer.ID, 0, len(pn.connsByPeer)) 229 for _, cs := range pn.connsByPeer { 230 for c := range cs { 231 peers = append(peers, c.remote) 232 break 233 } 234 } 235 return peers 236 } 237 238 // Conns returns all the connections of this peer 239 func (pn *peernet) Conns() []inet.Conn { 240 pn.RLock() 241 defer pn.RUnlock() 242 243 out := make([]inet.Conn, 0, len(pn.connsByPeer)) 244 for _, cs := range pn.connsByPeer { 245 for c := range cs { 246 out = append(out, c) 247 } 248 } 249 return out 250 } 251 252 func (pn *peernet) ConnsToPeer(p peer.ID) []inet.Conn { 253 pn.RLock() 254 defer pn.RUnlock() 255 256 cs, found := pn.connsByPeer[p] 257 if !found || len(cs) == 0 { 258 return nil 259 } 260 261 var cs2 []inet.Conn 262 for c := range cs { 263 cs2 = append(cs2, c) 264 } 265 return cs2 266 } 267 268 // ClosePeer connections to peer 269 func (pn *peernet) ClosePeer(p peer.ID) error { 270 pn.RLock() 271 cs, found := pn.connsByPeer[p] 272 if !found { 273 pn.RUnlock() 274 return nil 275 } 276 277 var conns []*conn 278 for c := range cs { 279 conns = append(conns, c) 280 } 281 pn.RUnlock() 282 for _, c := range conns { 283 c.Close() 284 } 285 return nil 286 } 287 288 // BandwidthTotals returns the total amount of bandwidth transferred 289 func (pn *peernet) BandwidthTotals() (in uint64, out uint64) { 290 // need to implement this. probably best to do it in swarm this time. 291 // need a "metrics" object 292 return 0, 0 293 } 294 295 // Listen tells the network to start listening on given multiaddrs. 296 func (pn *peernet) Listen(addrs ...ma.Multiaddr) error { 297 pn.Peerstore().AddAddrs(pn.LocalPeer(), addrs, peer.PermanentAddrTTL) 298 return nil 299 } 300 301 // ListenAddresses returns a list of addresses at which this network listens. 302 func (pn *peernet) ListenAddresses() []ma.Multiaddr { 303 return pn.Peerstore().Addrs(pn.LocalPeer()) 304 } 305 306 // InterfaceListenAddresses returns a list of addresses at which this network 307 // listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to 308 // use the known local interfaces. 309 func (pn *peernet) InterfaceListenAddresses() ([]ma.Multiaddr, error) { 310 return pn.ListenAddresses(), nil 311 } 312 313 // Connectedness returns a state signaling connection capabilities 314 // For now only returns Connecter || NotConnected. Expand into more later. 315 func (pn *peernet) Connectedness(p peer.ID) inet.Connectedness { 316 pn.Lock() 317 defer pn.Unlock() 318 319 cs, found := pn.connsByPeer[p] 320 if found && len(cs) > 0 { 321 return inet.Connected 322 } 323 return inet.NotConnected 324 } 325 326 // NewStream returns a new stream to given peer p. 327 // If there is no connection to p, attempts to create one. 328 func (pn *peernet) NewStream(p peer.ID) (inet.Stream, error) { 329 pn.Lock() 330 cs, found := pn.connsByPeer[p] 331 if !found || len(cs) < 1 { 332 pn.Unlock() 333 return nil, fmt.Errorf("no connection to peer") 334 } 335 336 // if many conns are found, how do we select? for now, randomly... 337 // this would be an interesting place to test logic that can measure 338 // links (network interfaces) and select properly 339 n := rand.Intn(len(cs)) 340 var c *conn 341 for c = range cs { 342 if n == 0 { 343 break 344 } 345 n-- 346 } 347 pn.Unlock() 348 349 return c.NewStream() 350 } 351 352 // SetStreamHandler sets the new stream handler on the Network. 353 // This operation is threadsafe. 354 func (pn *peernet) SetStreamHandler(h inet.StreamHandler) { 355 pn.Lock() 356 pn.streamHandler = h 357 pn.Unlock() 358 } 359 360 // SetConnHandler sets the new conn handler on the Network. 361 // This operation is threadsafe. 362 func (pn *peernet) SetConnHandler(h inet.ConnHandler) { 363 pn.Lock() 364 pn.connHandler = h 365 pn.Unlock() 366 } 367 368 // Notify signs up Notifiee to receive signals when events happen 369 func (pn *peernet) Notify(f inet.Notifiee) { 370 pn.notifmu.Lock() 371 pn.notifs[f] = struct{}{} 372 pn.notifmu.Unlock() 373 } 374 375 // StopNotify unregisters Notifiee fromr receiving signals 376 func (pn *peernet) StopNotify(f inet.Notifiee) { 377 pn.notifmu.Lock() 378 delete(pn.notifs, f) 379 pn.notifmu.Unlock() 380 } 381 382 // notifyAll runs the notification function on all Notifiees 383 func (pn *peernet) notifyAll(notification func(f inet.Notifiee)) { 384 pn.notifmu.RLock() 385 for n := range pn.notifs { 386 // make sure we dont block 387 // and they dont block each other. 388 go notification(n) 389 } 390 pn.notifmu.RUnlock() 391 }