package mocknet import ( "container/list" "context" "strconv" "sync" "sync/atomic" ic "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" ) var connCounter atomic.Int64 // conn represents one side's perspective of a // live connection between two peers. // it goes over a particular link. type conn struct { notifLk sync.Mutex id int64 local peer.ID remote peer.ID localAddr ma.Multiaddr remoteAddr ma.Multiaddr localPrivKey ic.PrivKey remotePubKey ic.PubKey net *peernet link *link rconn *conn // counterpart streams list.List stat network.ConnStats closeOnce sync.Once isClosed atomic.Bool sync.RWMutex } func newConn(ln, rn *peernet, l *link, dir network.Direction) *conn { c := &conn{net: ln, link: l} c.local = ln.peer c.remote = rn.peer c.stat.Direction = dir c.id = connCounter.Add(1) c.localAddr = ln.ps.Addrs(ln.peer)[0] for _, a := range rn.ps.Addrs(rn.peer) { if !manet.IsIPUnspecified(a) { c.remoteAddr = a break } } if c.remoteAddr == nil { c.remoteAddr = rn.ps.Addrs(rn.peer)[0] } c.localPrivKey = ln.ps.PrivKey(ln.peer) c.remotePubKey = rn.ps.PubKey(rn.peer) return c } func (c *conn) IsClosed() bool { return c.isClosed.Load() } func (c *conn) ID() string { return strconv.FormatInt(c.id, 10) } func (c *conn) Close() error { c.closeOnce.Do(func() { c.isClosed.Store(true) go c.rconn.Close() c.teardown() }) return nil } func (c *conn) teardown() { for _, s := range c.allStreams() { s.Reset() } c.net.removeConn(c) } func (c *conn) addStream(s *stream) { c.Lock() defer c.Unlock() s.conn = c c.streams.PushBack(s) } func (c *conn) removeStream(s *stream) { c.Lock() defer c.Unlock() for e := c.streams.Front(); e != nil; e = e.Next() { if s == e.Value { c.streams.Remove(e) return } } } func (c *conn) allStreams() []network.Stream { c.RLock() defer c.RUnlock() strs := make([]network.Stream, 0, c.streams.Len()) for e := c.streams.Front(); e != nil; e = e.Next() { s := e.Value.(*stream) strs = append(strs, s) } return strs } func (c *conn) remoteOpenedStream(s *stream) { c.addStream(s) c.net.handleNewStream(s) } func (c *conn) openStream() *stream { sl, sr := newStreamPair() go c.rconn.remoteOpenedStream(sr) c.addStream(sl) return sl } func (c *conn) NewStream(context.Context) (network.Stream, error) { log.Debugf("Conn.NewStreamWithProtocol: %s --> %s", c.local, c.remote) s := c.openStream() return s, nil } func (c *conn) GetStreams() []network.Stream { return c.allStreams() } // LocalMultiaddr is the Multiaddr on this side func (c *conn) LocalMultiaddr() ma.Multiaddr { return c.localAddr } // LocalPeer is the Peer on our side of the connection func (c *conn) LocalPeer() peer.ID { return c.local } // RemoteMultiaddr is the Multiaddr on the remote side func (c *conn) RemoteMultiaddr() ma.Multiaddr { return c.remoteAddr } // RemotePeer is the Peer on the remote side func (c *conn) RemotePeer() peer.ID { return c.remote } // RemotePublicKey is the private key of the peer on our side. func (c *conn) RemotePublicKey() ic.PubKey { return c.remotePubKey } // ConnState of security connection. Empty if not supported. func (c *conn) ConnState() network.ConnectionState { return network.ConnectionState{} } // Stat returns metadata about the connection func (c *conn) Stat() network.ConnStats { return c.stat } func (c *conn) Scope() network.ConnScope { return &network.NullScope{} }