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