github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/net/conn/conn.go (about) 1 package conn 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 8 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" 9 msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio" 10 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 11 manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net" 12 13 peer "github.com/jbenet/go-ipfs/peer" 14 u "github.com/jbenet/go-ipfs/util" 15 ctxc "github.com/jbenet/go-ipfs/util/ctxcloser" 16 ) 17 18 var log = u.Logger("conn") 19 20 const ( 21 // ChanBuffer is the size of the buffer in the Conn Chan 22 ChanBuffer = 10 23 24 // MaxMessageSize is the size of the largest single message 25 MaxMessageSize = 1 << 20 26 27 // HandshakeTimeout for when nodes first connect 28 HandshakeTimeout = time.Second * 5 29 ) 30 31 // global static buffer pool for byte arrays of size MaxMessageSize 32 var BufferPool *sync.Pool 33 34 func init() { 35 BufferPool = new(sync.Pool) 36 BufferPool.New = func() interface{} { 37 log.Warning("Pool returning new object") 38 return make([]byte, MaxMessageSize) 39 } 40 } 41 42 // ReleaseBuffer puts the given byte array back into the buffer pool, 43 // first verifying that it is the correct size 44 func ReleaseBuffer(b []byte) { 45 log.Warningf("Releasing buffer! (cap,size = %d, %d)", cap(b), len(b)) 46 if cap(b) != MaxMessageSize { 47 log.Warning("Release buffer failed (cap, size = %d, %d)", cap(b), len(b)) 48 return 49 } 50 BufferPool.Put(b[:cap(b)]) 51 } 52 53 // msgioPipe is a pipe using msgio channels. 54 type msgioPipe struct { 55 outgoing *msgio.Chan 56 incoming *msgio.Chan 57 } 58 59 func newMsgioPipe(size int, pool *sync.Pool) *msgioPipe { 60 return &msgioPipe{ 61 outgoing: msgio.NewChan(size), 62 incoming: msgio.NewChanWithPool(size, pool), 63 } 64 } 65 66 // singleConn represents a single connection to another Peer (IPFS Node). 67 type singleConn struct { 68 local peer.Peer 69 remote peer.Peer 70 maconn manet.Conn 71 msgio *msgioPipe 72 73 ctxc.ContextCloser 74 } 75 76 // newConn constructs a new connection 77 func newSingleConn(ctx context.Context, local, remote peer.Peer, 78 maconn manet.Conn) (Conn, error) { 79 80 conn := &singleConn{ 81 local: local, 82 remote: remote, 83 maconn: maconn, 84 msgio: newMsgioPipe(10, BufferPool), 85 } 86 87 conn.ContextCloser = ctxc.NewContextCloser(ctx, conn.close) 88 89 log.Info("newSingleConn: %v to %v", local, remote) 90 91 // setup the various io goroutines 92 conn.Children().Add(1) 93 go func() { 94 conn.msgio.outgoing.WriteTo(maconn) 95 conn.Children().Done() 96 }() 97 conn.Children().Add(1) 98 go func() { 99 conn.msgio.incoming.ReadFrom(maconn, MaxMessageSize) 100 conn.Children().Done() 101 }() 102 103 // version handshake 104 ctxT, _ := context.WithTimeout(ctx, HandshakeTimeout) 105 if err := Handshake1(ctxT, conn); err != nil { 106 conn.Close() 107 return nil, fmt.Errorf("Handshake1 failed: %s", err) 108 } 109 110 return conn, nil 111 } 112 113 // close is the internal close function, called by ContextCloser.Close 114 func (c *singleConn) close() error { 115 log.Debugf("%s closing Conn with %s", c.local, c.remote) 116 117 // close underlying connection 118 err := c.maconn.Close() 119 c.msgio.outgoing.Close() 120 return err 121 } 122 123 func (c *singleConn) GetError() error { 124 select { 125 case err := <-c.msgio.incoming.ErrChan: 126 return err 127 case err := <-c.msgio.outgoing.ErrChan: 128 return err 129 default: 130 return nil 131 } 132 } 133 134 // ID is an identifier unique to this connection. 135 func (c *singleConn) ID() string { 136 return ID(c) 137 } 138 139 func (c *singleConn) String() string { 140 return String(c, "singleConn") 141 } 142 143 // LocalMultiaddr is the Multiaddr on this side 144 func (c *singleConn) LocalMultiaddr() ma.Multiaddr { 145 return c.maconn.LocalMultiaddr() 146 } 147 148 // RemoteMultiaddr is the Multiaddr on the remote side 149 func (c *singleConn) RemoteMultiaddr() ma.Multiaddr { 150 return c.maconn.RemoteMultiaddr() 151 } 152 153 // LocalPeer is the Peer on this side 154 func (c *singleConn) LocalPeer() peer.Peer { 155 return c.local 156 } 157 158 // RemotePeer is the Peer on the remote side 159 func (c *singleConn) RemotePeer() peer.Peer { 160 return c.remote 161 } 162 163 // In returns a readable message channel 164 func (c *singleConn) In() <-chan []byte { 165 return c.msgio.incoming.MsgChan 166 } 167 168 // Out returns a writable message channel 169 func (c *singleConn) Out() chan<- []byte { 170 return c.msgio.outgoing.MsgChan 171 } 172 173 // ID returns the ID of a given Conn. 174 func ID(c Conn) string { 175 l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().ID()) 176 r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().ID()) 177 lh := u.Hash([]byte(l)) 178 rh := u.Hash([]byte(r)) 179 ch := u.XOR(lh, rh) 180 return u.Key(ch).Pretty() 181 } 182 183 // String returns the user-friendly String representation of a conn 184 func String(c Conn, typ string) string { 185 return fmt.Sprintf("%s (%s) <-- %s --> (%s) %s", 186 c.LocalPeer(), c.LocalMultiaddr(), typ, c.RemoteMultiaddr(), c.RemotePeer()) 187 }