github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/host/basic/basic_host.go (about) 1 package basichost 2 3 import ( 4 "io" 5 6 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 7 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" 8 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 9 metrics "github.com/ipfs/go-ipfs/metrics" 10 mstream "github.com/ipfs/go-ipfs/metrics/stream" 11 eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog" 12 13 inet "github.com/ipfs/go-ipfs/p2p/net" 14 peer "github.com/ipfs/go-ipfs/p2p/peer" 15 protocol "github.com/ipfs/go-ipfs/p2p/protocol" 16 identify "github.com/ipfs/go-ipfs/p2p/protocol/identify" 17 relay "github.com/ipfs/go-ipfs/p2p/protocol/relay" 18 ) 19 20 var log = eventlog.Logger("p2p/host/basic") 21 22 // Option is a type used to pass in options to the host. 23 type Option int 24 25 const ( 26 // NATPortMap makes the host attempt to open port-mapping in NAT devices 27 // for all its listeners. Pass in this option in the constructor to 28 // asynchronously a) find a gateway, b) open port mappings, c) republish 29 // port mappings periodically. The NATed addresses are included in the 30 // Host's Addrs() list. 31 NATPortMap Option = iota 32 ) 33 34 // BasicHost is the basic implementation of the host.Host interface. This 35 // particular host implementation: 36 // * uses a protocol muxer to mux per-protocol streams 37 // * uses an identity service to send + receive node information 38 // * uses a relay service to allow hosts to relay conns for each other 39 // * uses a nat service to establish NAT port mappings 40 type BasicHost struct { 41 network inet.Network 42 mux *protocol.Mux 43 ids *identify.IDService 44 relay *relay.RelayService 45 natmgr *natManager 46 47 proc goprocess.Process 48 49 bwc metrics.Reporter 50 } 51 52 // New constructs and sets up a new *BasicHost with given Network 53 func New(net inet.Network, opts ...interface{}) *BasicHost { 54 h := &BasicHost{ 55 network: net, 56 mux: protocol.NewMux(), 57 bwc: metrics.NewBandwidthCounter(), 58 } 59 60 h.proc = goprocess.WithTeardown(func() error { 61 if h.natmgr != nil { 62 h.natmgr.Close() 63 } 64 65 return h.Network().Close() 66 }) 67 68 // setup host services 69 h.ids = identify.NewIDService(h) 70 h.relay = relay.NewRelayService(h, h.Mux().HandleSync) 71 72 for _, o := range opts { 73 switch o := o.(type) { 74 case Option: 75 switch o { 76 case NATPortMap: 77 h.natmgr = newNatManager(h) 78 } 79 case metrics.Reporter: 80 h.bwc = o 81 } 82 } 83 84 net.SetConnHandler(h.newConnHandler) 85 net.SetStreamHandler(h.newStreamHandler) 86 87 return h 88 } 89 90 // newConnHandler is the remote-opened conn handler for inet.Network 91 func (h *BasicHost) newConnHandler(c inet.Conn) { 92 h.ids.IdentifyConn(c) 93 } 94 95 // newStreamHandler is the remote-opened stream handler for inet.Network 96 // TODO: this feels a bit wonky 97 func (h *BasicHost) newStreamHandler(s inet.Stream) { 98 protoID, handle, err := h.Mux().ReadHeader(s) 99 if err != nil { 100 if err == io.EOF { 101 log.Debugf("protocol EOF: %s", s.Conn().RemotePeer()) 102 } else { 103 log.Warning("protocol mux failed: %s", err) 104 } 105 return 106 } 107 108 logStream := mstream.WrapStream(s, protoID, h.bwc) 109 110 go handle(logStream) 111 } 112 113 // ID returns the (local) peer.ID associated with this Host 114 func (h *BasicHost) ID() peer.ID { 115 return h.Network().LocalPeer() 116 } 117 118 // Peerstore returns the Host's repository of Peer Addresses and Keys. 119 func (h *BasicHost) Peerstore() peer.Peerstore { 120 return h.Network().Peerstore() 121 } 122 123 // Network returns the Network interface of the Host 124 func (h *BasicHost) Network() inet.Network { 125 return h.network 126 } 127 128 // Mux returns the Mux multiplexing incoming streams to protocol handlers 129 func (h *BasicHost) Mux() *protocol.Mux { 130 return h.mux 131 } 132 133 // IDService returns 134 func (h *BasicHost) IDService() *identify.IDService { 135 return h.ids 136 } 137 138 // SetStreamHandler sets the protocol handler on the Host's Mux. 139 // This is equivalent to: 140 // host.Mux().SetHandler(proto, handler) 141 // (Threadsafe) 142 func (h *BasicHost) SetStreamHandler(pid protocol.ID, handler inet.StreamHandler) { 143 h.Mux().SetHandler(pid, handler) 144 } 145 146 // RemoveStreamHandler returns .. 147 func (h *BasicHost) RemoveStreamHandler(pid protocol.ID) { 148 h.Mux().RemoveHandler(pid) 149 } 150 151 // NewStream opens a new stream to given peer p, and writes a p2p/protocol 152 // header with given protocol.ID. If there is no connection to p, attempts 153 // to create one. If ProtocolID is "", writes no header. 154 // (Threadsafe) 155 func (h *BasicHost) NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error) { 156 s, err := h.Network().NewStream(p) 157 if err != nil { 158 return nil, err 159 } 160 161 logStream := mstream.WrapStream(s, pid, h.bwc) 162 163 if err := protocol.WriteHeader(logStream, pid); err != nil { 164 logStream.Close() 165 return nil, err 166 } 167 168 return logStream, nil 169 } 170 171 // Connect ensures there is a connection between this host and the peer with 172 // given peer.ID. Connect will absorb the addresses in pi into its internal 173 // peerstore. If there is not an active connection, Connect will issue a 174 // h.Network.Dial, and block until a connection is open, or an error is 175 // returned. // TODO: Relay + NAT. 176 func (h *BasicHost) Connect(ctx context.Context, pi peer.PeerInfo) error { 177 178 // absorb addresses into peerstore 179 h.Peerstore().AddAddrs(pi.ID, pi.Addrs, peer.TempAddrTTL) 180 181 cs := h.Network().ConnsToPeer(pi.ID) 182 if len(cs) > 0 { 183 return nil 184 } 185 186 return h.dialPeer(ctx, pi.ID) 187 } 188 189 // dialPeer opens a connection to peer, and makes sure to identify 190 // the connection once it has been opened. 191 func (h *BasicHost) dialPeer(ctx context.Context, p peer.ID) error { 192 log.Debugf("host %s dialing %s", h.ID, p) 193 c, err := h.Network().DialPeer(ctx, p) 194 if err != nil { 195 return err 196 } 197 198 // identify the connection before returning. 199 done := make(chan struct{}) 200 go func() { 201 h.ids.IdentifyConn(c) 202 close(done) 203 }() 204 205 // respect don contexteone 206 select { 207 case <-done: 208 case <-ctx.Done(): 209 return ctx.Err() 210 } 211 212 log.Debugf("host %s finished dialing %s", h.ID, p) 213 return nil 214 } 215 216 // Addrs returns all the addresses of BasicHost at this moment in time. 217 // It's ok to not include addresses if they're not available to be used now. 218 func (h *BasicHost) Addrs() []ma.Multiaddr { 219 addrs, err := h.Network().InterfaceListenAddresses() 220 if err != nil { 221 log.Debug("error retrieving network interface addrs") 222 } 223 224 if h.ids != nil { // add external observed addresses 225 addrs = append(addrs, h.ids.OwnObservedAddrs()...) 226 } 227 228 if h.natmgr != nil { // natmgr is nil if we do not use nat option. 229 nat := h.natmgr.NAT() 230 if nat != nil { // nat is nil if not ready, or no nat is available. 231 addrs = append(addrs, nat.ExternalAddrs()...) 232 } 233 } 234 235 return addrs 236 } 237 238 // Close shuts down the Host's services (network, etc). 239 func (h *BasicHost) Close() error { 240 return h.proc.Close() 241 } 242 243 // GetBandwidthReporter exposes the Host's bandiwth metrics reporter 244 func (h *BasicHost) GetBandwidthReporter() metrics.Reporter { 245 return h.bwc 246 }