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