github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/net/conn/listen.go (about) 1 package conn 2 3 import ( 4 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" 5 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 6 manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net" 7 8 peer "github.com/jbenet/go-ipfs/peer" 9 ctxc "github.com/jbenet/go-ipfs/util/ctxcloser" 10 ) 11 12 // listener is an object that can accept connections. It implements Listener 13 type listener struct { 14 manet.Listener 15 16 // chansize is the size of the internal channels for concurrency 17 chansize int 18 19 // channel of incoming conections 20 conns chan Conn 21 22 // Local multiaddr to listen on 23 maddr ma.Multiaddr 24 25 // LocalPeer is the identity of the local Peer. 26 local peer.Peer 27 28 // Peerstore is the set of peers we know about locally 29 peers peer.Peerstore 30 31 // Context for children Conn 32 ctx context.Context 33 34 // embedded ContextCloser 35 ctxc.ContextCloser 36 } 37 38 // disambiguate 39 func (l *listener) Close() error { 40 return l.ContextCloser.Close() 41 } 42 43 // close called by ContextCloser.Close 44 func (l *listener) close() error { 45 log.Info("listener closing: %s %s", l.local, l.maddr) 46 return l.Listener.Close() 47 } 48 49 func (l *listener) listen() { 50 defer l.Children().Done() 51 52 // handle at most chansize concurrent handshakes 53 sem := make(chan struct{}, l.chansize) 54 55 // handle is a goroutine work function that handles the handshake. 56 // it's here only so that accepting new connections can happen quickly. 57 handle := func(maconn manet.Conn) { 58 defer func() { <-sem }() // release 59 60 c, err := newSingleConn(l.ctx, l.local, nil, maconn) 61 if err != nil { 62 log.Errorf("Error accepting connection: %v", err) 63 return 64 } 65 66 sc, err := newSecureConn(l.ctx, c, l.peers) 67 if err != nil { 68 log.Errorf("Error securing connection: %v", err) 69 return 70 } 71 72 l.conns <- sc 73 } 74 75 for { 76 maconn, err := l.Listener.Accept() 77 if err != nil { 78 79 // if closing, we should exit. 80 select { 81 case <-l.Closing(): 82 return // done. 83 default: 84 } 85 86 log.Errorf("Failed to accept connection: %v", err) 87 continue 88 } 89 90 sem <- struct{}{} // acquire 91 go handle(maconn) 92 } 93 } 94 95 // Accept waits for and returns the next connection to the listener. 96 // Note that unfortunately this 97 func (l *listener) Accept() <-chan Conn { 98 return l.conns 99 } 100 101 // Multiaddr is the identity of the local Peer. 102 func (l *listener) Multiaddr() ma.Multiaddr { 103 return l.maddr 104 } 105 106 // LocalPeer is the identity of the local Peer. 107 func (l *listener) LocalPeer() peer.Peer { 108 return l.local 109 } 110 111 // Peerstore is the set of peers we know about locally. The Listener needs it 112 // because when an incoming connection is identified, we should reuse the 113 // same peer objects (otherwise things get inconsistent). 114 func (l *listener) Peerstore() peer.Peerstore { 115 return l.peers 116 } 117 118 // Listen listens on the particular multiaddr, with given peer and peerstore. 119 func Listen(ctx context.Context, addr ma.Multiaddr, local peer.Peer, peers peer.Peerstore) (Listener, error) { 120 121 ml, err := manet.Listen(addr) 122 if err != nil { 123 return nil, err 124 } 125 126 // todo make this a variable 127 chansize := 10 128 129 l := &listener{ 130 Listener: ml, 131 maddr: addr, 132 peers: peers, 133 local: local, 134 conns: make(chan Conn, chansize), 135 chansize: chansize, 136 ctx: ctx, 137 } 138 139 // need a separate context to use for the context closer. 140 // This is because the parent context will be given to all connections too, 141 // and if we close the listener, the connections shouldn't share the fate. 142 ctx2, _ := context.WithCancel(ctx) 143 l.ContextCloser = ctxc.NewContextCloser(ctx2, l.close) 144 145 l.Children().Add(1) 146 go l.listen() 147 148 return l, nil 149 }