github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/net/conn/listen.go (about) 1 package conn 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 8 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 9 manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" 10 reuseport "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport" 11 tec "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher" 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 ic "github.com/ipfs/go-ipfs/p2p/crypto" 17 filter "github.com/ipfs/go-ipfs/p2p/net/filter" 18 peer "github.com/ipfs/go-ipfs/p2p/peer" 19 ) 20 21 // ConnWrapper is any function that wraps a raw multiaddr connection 22 type ConnWrapper func(manet.Conn) manet.Conn 23 24 // listener is an object that can accept connections. It implements Listener 25 type listener struct { 26 manet.Listener 27 28 local peer.ID // LocalPeer is the identity of the local Peer 29 privk ic.PrivKey // private key to use to initialize secure conns 30 31 filters *filter.Filters 32 33 wrapper ConnWrapper 34 35 proc goprocess.Process 36 } 37 38 func (l *listener) teardown() error { 39 defer log.Debugf("listener closed: %s %s", l.local, l.Multiaddr()) 40 return l.Listener.Close() 41 } 42 43 func (l *listener) Close() error { 44 log.Debugf("listener closing: %s %s", l.local, l.Multiaddr()) 45 return l.proc.Close() 46 } 47 48 func (l *listener) String() string { 49 return fmt.Sprintf("<Listener %s %s>", l.local, l.Multiaddr()) 50 } 51 52 func (l *listener) SetAddrFilters(fs *filter.Filters) { 53 l.filters = fs 54 } 55 56 // Accept waits for and returns the next connection to the listener. 57 // Note that unfortunately this 58 func (l *listener) Accept() (net.Conn, error) { 59 60 // listeners dont have contexts. given changes dont make sense here anymore 61 // note that the parent of listener will Close, which will interrupt all io. 62 // Contexts and io don't mix. 63 ctx := context.Background() 64 65 var catcher tec.TempErrCatcher 66 67 catcher.IsTemp = func(e error) bool { 68 // ignore connection breakages up to this point. but log them 69 if e == io.EOF { 70 log.Debugf("listener ignoring conn with EOF: %s", e) 71 return true 72 } 73 74 te, ok := e.(tec.Temporary) 75 if ok { 76 log.Debugf("listener ignoring conn with temporary err: %s", e) 77 return te.Temporary() 78 } 79 return false 80 } 81 82 for { 83 maconn, err := l.Listener.Accept() 84 if err != nil { 85 if catcher.IsTemporary(err) { 86 continue 87 } 88 return nil, err 89 } 90 91 log.Debugf("listener %s got connection: %s <---> %s", l, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr()) 92 93 if l.filters != nil && l.filters.AddrBlocked(maconn.RemoteMultiaddr()) { 94 log.Debugf("blocked connection from %s", maconn.RemoteMultiaddr()) 95 maconn.Close() 96 continue 97 } 98 // If we have a wrapper func, wrap this conn 99 if l.wrapper != nil { 100 maconn = l.wrapper(maconn) 101 } 102 103 c, err := newSingleConn(ctx, l.local, "", maconn) 104 if err != nil { 105 if catcher.IsTemporary(err) { 106 continue 107 } 108 return nil, err 109 } 110 111 if l.privk == nil || EncryptConnections == false { 112 log.Warning("listener %s listening INSECURELY!", l) 113 return c, nil 114 } 115 sc, err := newSecureConn(ctx, l.privk, c) 116 if err != nil { 117 log.Infof("ignoring conn we failed to secure: %s %s", err, c) 118 continue 119 } 120 return sc, nil 121 } 122 } 123 124 func (l *listener) Addr() net.Addr { 125 return l.Listener.Addr() 126 } 127 128 // Multiaddr is the identity of the local Peer. 129 // If there is an error converting from net.Addr to ma.Multiaddr, 130 // the return value will be nil. 131 func (l *listener) Multiaddr() ma.Multiaddr { 132 return l.Listener.Multiaddr() 133 } 134 135 // LocalPeer is the identity of the local Peer. 136 func (l *listener) LocalPeer() peer.ID { 137 return l.local 138 } 139 140 func (l *listener) Loggable() map[string]interface{} { 141 return map[string]interface{}{ 142 "listener": map[string]interface{}{ 143 "peer": l.LocalPeer(), 144 "address": l.Multiaddr(), 145 "secure": (l.privk != nil), 146 }, 147 } 148 } 149 150 // Listen listens on the particular multiaddr, with given peer and peerstore. 151 func Listen(ctx context.Context, addr ma.Multiaddr, local peer.ID, sk ic.PrivKey) (Listener, error) { 152 ml, err := manetListen(addr) 153 if err != nil { 154 return nil, err 155 } 156 157 l := &listener{ 158 Listener: ml, 159 local: local, 160 privk: sk, 161 } 162 l.proc = goprocessctx.WithContextAndTeardown(ctx, l.teardown) 163 164 log.Debugf("Conn Listener on %s", l.Multiaddr()) 165 log.Event(ctx, "swarmListen", l) 166 return l, nil 167 } 168 169 type ListenerConnWrapper interface { 170 SetConnWrapper(ConnWrapper) 171 } 172 173 // SetConnWrapper assigns a maconn ConnWrapper to wrap all incoming 174 // connections with. MUST be set _before_ calling `Accept()` 175 func (l *listener) SetConnWrapper(cw ConnWrapper) { 176 l.wrapper = cw 177 } 178 179 func manetListen(addr ma.Multiaddr) (manet.Listener, error) { 180 network, naddr, err := manet.DialArgs(addr) 181 if err != nil { 182 return nil, err 183 } 184 185 if reuseportIsAvailable() { 186 nl, err := reuseport.Listen(network, naddr) 187 if err == nil { 188 // hey, it worked! 189 return manet.WrapNetListener(nl) 190 } 191 // reuseport is available, but we failed to listen. log debug, and retry normally. 192 log.Debugf("reuseport available, but failed to listen: %s %s, %s", network, naddr, err) 193 } 194 195 // either reuseport not available, or it failed. try normally. 196 return manet.Listen(addr) 197 }