github.com/xfond/eth-implementation@v1.8.9-0.20180514135602-f6bc65fc6811/p2p/peer.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package p2p 18 19 import ( 20 "fmt" 21 "io" 22 "net" 23 "sort" 24 "sync" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common/mclock" 28 "github.com/ethereum/go-ethereum/event" 29 "github.com/ethereum/go-ethereum/log" 30 "github.com/ethereum/go-ethereum/p2p/discover" 31 "github.com/ethereum/go-ethereum/rlp" 32 ) 33 34 const ( 35 baseProtocolVersion = 5 36 baseProtocolLength = uint64(16) 37 baseProtocolMaxMsgSize = 2 * 1024 38 39 snappyProtocolVersion = 5 40 41 pingInterval = 15 * time.Second 42 ) 43 44 const ( 45 // devp2p message codes 46 handshakeMsg = 0x00 47 discMsg = 0x01 48 pingMsg = 0x02 49 pongMsg = 0x03 50 ) 51 52 // protoHandshake is the RLP structure of the protocol handshake. 53 type protoHandshake struct { 54 Version uint64 55 Name string 56 Caps []Cap 57 ListenPort uint64 58 ID discover.NodeID 59 60 // Ignore additional fields (for forward compatibility). 61 Rest []rlp.RawValue `rlp:"tail"` 62 } 63 64 // PeerEventType is the type of peer events emitted by a p2p.Server 65 type PeerEventType string 66 67 const ( 68 // PeerEventTypeAdd is the type of event emitted when a peer is added 69 // to a p2p.Server 70 PeerEventTypeAdd PeerEventType = "add" 71 72 // PeerEventTypeDrop is the type of event emitted when a peer is 73 // dropped from a p2p.Server 74 PeerEventTypeDrop PeerEventType = "drop" 75 76 // PeerEventTypeMsgSend is the type of event emitted when a 77 // message is successfully sent to a peer 78 PeerEventTypeMsgSend PeerEventType = "msgsend" 79 80 // PeerEventTypeMsgRecv is the type of event emitted when a 81 // message is received from a peer 82 PeerEventTypeMsgRecv PeerEventType = "msgrecv" 83 ) 84 85 // PeerEvent is an event emitted when peers are either added or dropped from 86 // a p2p.Server or when a message is sent or received on a peer connection 87 type PeerEvent struct { 88 Type PeerEventType `json:"type"` 89 Peer discover.NodeID `json:"peer"` 90 Error string `json:"error,omitempty"` 91 Protocol string `json:"protocol,omitempty"` 92 MsgCode *uint64 `json:"msg_code,omitempty"` 93 MsgSize *uint32 `json:"msg_size,omitempty"` 94 } 95 96 // Peer represents a connected remote node. 97 type Peer struct { 98 rw *conn 99 running map[string]*protoRW 100 log log.Logger 101 created mclock.AbsTime 102 103 wg sync.WaitGroup 104 protoErr chan error 105 closed chan struct{} 106 disc chan DiscReason 107 108 // events receives message send / receive events if set 109 events *event.Feed 110 } 111 112 // NewPeer returns a peer for testing purposes. 113 func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer { 114 pipe, _ := net.Pipe() 115 conn := &conn{fd: pipe, transport: nil, id: id, caps: caps, name: name} 116 peer := newPeer(conn, nil) 117 close(peer.closed) // ensures Disconnect doesn't block 118 return peer 119 } 120 121 // ID returns the node's public key. 122 func (p *Peer) ID() discover.NodeID { 123 return p.rw.id 124 } 125 126 // Name returns the node name that the remote node advertised. 127 func (p *Peer) Name() string { 128 return p.rw.name 129 } 130 131 // Caps returns the capabilities (supported subprotocols) of the remote peer. 132 func (p *Peer) Caps() []Cap { 133 // TODO: maybe return copy 134 return p.rw.caps 135 } 136 137 // RemoteAddr returns the remote address of the network connection. 138 func (p *Peer) RemoteAddr() net.Addr { 139 return p.rw.fd.RemoteAddr() 140 } 141 142 // LocalAddr returns the local address of the network connection. 143 func (p *Peer) LocalAddr() net.Addr { 144 return p.rw.fd.LocalAddr() 145 } 146 147 // Disconnect terminates the peer connection with the given reason. 148 // It returns immediately and does not wait until the connection is closed. 149 func (p *Peer) Disconnect(reason DiscReason) { 150 select { 151 case p.disc <- reason: 152 case <-p.closed: 153 } 154 } 155 156 // String implements fmt.Stringer. 157 func (p *Peer) String() string { 158 return fmt.Sprintf("Peer %x %v", p.rw.id[:8], p.RemoteAddr()) 159 } 160 161 // Inbound returns true if the peer is an inbound connection 162 func (p *Peer) Inbound() bool { 163 return p.rw.flags&inboundConn != 0 164 } 165 166 func newPeer(conn *conn, protocols []Protocol) *Peer { 167 protomap := matchProtocols(protocols, conn.caps, conn) 168 p := &Peer{ 169 rw: conn, 170 running: protomap, 171 created: mclock.Now(), 172 disc: make(chan DiscReason), 173 protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop 174 closed: make(chan struct{}), 175 log: log.New("id", conn.id, "conn", conn.flags), 176 } 177 return p 178 } 179 180 func (p *Peer) Log() log.Logger { 181 return p.log 182 } 183 184 func (p *Peer) run() (remoteRequested bool, err error) { 185 var ( 186 writeStart = make(chan struct{}, 1) 187 writeErr = make(chan error, 1) 188 readErr = make(chan error, 1) 189 reason DiscReason // sent to the peer 190 ) 191 p.wg.Add(2) 192 go p.readLoop(readErr) 193 go p.pingLoop() 194 195 // Start all protocol handlers. 196 writeStart <- struct{}{} 197 p.startProtocols(writeStart, writeErr) 198 199 // Wait for an error or disconnect. 200 loop: 201 for { 202 select { 203 case err = <-writeErr: 204 // A write finished. Allow the next write to start if 205 // there was no error. 206 if err != nil { 207 reason = DiscNetworkError 208 break loop 209 } 210 writeStart <- struct{}{} 211 case err = <-readErr: 212 if r, ok := err.(DiscReason); ok { 213 remoteRequested = true 214 reason = r 215 } else { 216 reason = DiscNetworkError 217 } 218 break loop 219 case err = <-p.protoErr: 220 reason = discReasonForError(err) 221 break loop 222 case err = <-p.disc: 223 reason = discReasonForError(err) 224 break loop 225 } 226 } 227 228 close(p.closed) 229 p.rw.close(reason) 230 p.wg.Wait() 231 return remoteRequested, err 232 } 233 234 func (p *Peer) pingLoop() { 235 ping := time.NewTimer(pingInterval) 236 defer p.wg.Done() 237 defer ping.Stop() 238 for { 239 select { 240 case <-ping.C: 241 if err := SendItems(p.rw, pingMsg); err != nil { 242 p.protoErr <- err 243 return 244 } 245 ping.Reset(pingInterval) 246 case <-p.closed: 247 return 248 } 249 } 250 } 251 252 func (p *Peer) readLoop(errc chan<- error) { 253 defer p.wg.Done() 254 for { 255 msg, err := p.rw.ReadMsg() 256 if err != nil { 257 errc <- err 258 return 259 } 260 msg.ReceivedAt = time.Now() 261 if err = p.handle(msg); err != nil { 262 errc <- err 263 return 264 } 265 } 266 } 267 268 func (p *Peer) handle(msg Msg) error { 269 switch { 270 case msg.Code == pingMsg: 271 msg.Discard() 272 go SendItems(p.rw, pongMsg) 273 case msg.Code == discMsg: 274 var reason [1]DiscReason 275 // This is the last message. We don't need to discard or 276 // check errors because, the connection will be closed after it. 277 rlp.Decode(msg.Payload, &reason) 278 return reason[0] 279 case msg.Code < baseProtocolLength: 280 // ignore other base protocol messages 281 return msg.Discard() 282 default: 283 // it's a subprotocol message 284 proto, err := p.getProto(msg.Code) 285 if err != nil { 286 return fmt.Errorf("msg code out of range: %v", msg.Code) 287 } 288 select { 289 case proto.in <- msg: 290 return nil 291 case <-p.closed: 292 return io.EOF 293 } 294 } 295 return nil 296 } 297 298 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 299 n := 0 300 for _, cap := range caps { 301 for _, proto := range protocols { 302 if proto.Name == cap.Name && proto.Version == cap.Version { 303 n++ 304 } 305 } 306 } 307 return n 308 } 309 310 // matchProtocols creates structures for matching named subprotocols. 311 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 312 sort.Sort(capsByNameAndVersion(caps)) 313 offset := baseProtocolLength 314 result := make(map[string]*protoRW) 315 316 outer: 317 for _, cap := range caps { 318 for _, proto := range protocols { 319 if proto.Name == cap.Name && proto.Version == cap.Version { 320 // If an old protocol version matched, revert it 321 if old := result[cap.Name]; old != nil { 322 offset -= old.Length 323 } 324 // Assign the new match 325 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 326 offset += proto.Length 327 328 continue outer 329 } 330 } 331 } 332 return result 333 } 334 335 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 336 p.wg.Add(len(p.running)) 337 for _, proto := range p.running { 338 proto := proto 339 proto.closed = p.closed 340 proto.wstart = writeStart 341 proto.werr = writeErr 342 var rw MsgReadWriter = proto 343 if p.events != nil { 344 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 345 } 346 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 347 go func() { 348 err := proto.Run(p, rw) 349 if err == nil { 350 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 351 err = errProtocolReturned 352 } else if err != io.EOF { 353 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 354 } 355 p.protoErr <- err 356 p.wg.Done() 357 }() 358 } 359 } 360 361 // getProto finds the protocol responsible for handling 362 // the given message code. 363 func (p *Peer) getProto(code uint64) (*protoRW, error) { 364 for _, proto := range p.running { 365 if code >= proto.offset && code < proto.offset+proto.Length { 366 return proto, nil 367 } 368 } 369 return nil, newPeerError(errInvalidMsgCode, "%d", code) 370 } 371 372 type protoRW struct { 373 Protocol 374 in chan Msg // receices read messages 375 closed <-chan struct{} // receives when peer is shutting down 376 wstart <-chan struct{} // receives when write may start 377 werr chan<- error // for write results 378 offset uint64 379 w MsgWriter 380 } 381 382 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 383 if msg.Code >= rw.Length { 384 return newPeerError(errInvalidMsgCode, "not handled") 385 } 386 msg.Code += rw.offset 387 select { 388 case <-rw.wstart: 389 err = rw.w.WriteMsg(msg) 390 // Report write status back to Peer.run. It will initiate 391 // shutdown if the error is non-nil and unblock the next write 392 // otherwise. The calling protocol code should exit for errors 393 // as well but we don't want to rely on that. 394 rw.werr <- err 395 case <-rw.closed: 396 err = fmt.Errorf("shutting down") 397 } 398 return err 399 } 400 401 func (rw *protoRW) ReadMsg() (Msg, error) { 402 select { 403 case msg := <-rw.in: 404 msg.Code -= rw.offset 405 return msg, nil 406 case <-rw.closed: 407 return Msg{}, io.EOF 408 } 409 } 410 411 // PeerInfo represents a short summary of the information known about a connected 412 // peer. Sub-protocol independent fields are contained and initialized here, with 413 // protocol specifics delegated to all connected sub-protocols. 414 type PeerInfo struct { 415 ID string `json:"id"` // Unique node identifier (also the encryption key) 416 Name string `json:"name"` // Name of the node, including client type, version, OS, custom data 417 Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer 418 Network struct { 419 LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection 420 RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection 421 Inbound bool `json:"inbound"` 422 Trusted bool `json:"trusted"` 423 Static bool `json:"static"` 424 } `json:"network"` 425 Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields 426 } 427 428 // Info gathers and returns a collection of metadata known about a peer. 429 func (p *Peer) Info() *PeerInfo { 430 // Gather the protocol capabilities 431 var caps []string 432 for _, cap := range p.Caps() { 433 caps = append(caps, cap.String()) 434 } 435 // Assemble the generic peer metadata 436 info := &PeerInfo{ 437 ID: p.ID().String(), 438 Name: p.Name(), 439 Caps: caps, 440 Protocols: make(map[string]interface{}), 441 } 442 info.Network.LocalAddress = p.LocalAddr().String() 443 info.Network.RemoteAddress = p.RemoteAddr().String() 444 info.Network.Inbound = p.rw.is(inboundConn) 445 info.Network.Trusted = p.rw.is(trustedConn) 446 info.Network.Static = p.rw.is(staticDialedConn) 447 448 // Gather all the running protocol infos 449 for _, proto := range p.running { 450 protoInfo := interface{}("unknown") 451 if query := proto.Protocol.PeerInfo; query != nil { 452 if metadata := query(p.ID()); metadata != nil { 453 protoInfo = metadata 454 } else { 455 protoInfo = "handshake" 456 } 457 } 458 info.Protocols[proto.Name] = protoInfo 459 } 460 return info 461 }