github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/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/intfoundation/intchain/common/mclock" 28 "github.com/intfoundation/intchain/event" 29 "github.com/intfoundation/intchain/log" 30 "github.com/intfoundation/intchain/p2p/discover" 31 "github.com/intfoundation/intchain/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 // IntChain message belonging to intchain/64 52 BroadcastNewChildChainMsg = 0x04 53 ConfirmNewChildChainMsg = 0x05 54 55 RefreshValidatorNodeInfoMsg = 0x06 56 RemoveValidatorNodeInfoMsg = 0x07 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 discover.NodeID 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 // PeerEventTypeMsgSend is the type of event emitted when a 92 // message is successfully sent to a peer 93 PeerEventTypeRefreshValidator PeerEventType = "refreshvalidator" 94 95 // PeerEventTypeMsgRecv is the type of event emitted when a 96 // message is received from a peer 97 PeerEventTypeRemoveValidator PeerEventType = "removevalidator" 98 ) 99 100 // PeerEvent is an event emitted when peers are either added or dropped from 101 // a p2p.Server or when a message is sent or received on a peer connection 102 type PeerEvent struct { 103 Type PeerEventType `json:"type"` 104 Peer discover.NodeID `json:"peer"` 105 Error string `json:"error,omitempty"` 106 Protocol string `json:"protocol,omitempty"` 107 MsgCode *uint64 `json:"msg_code,omitempty"` 108 MsgSize *uint32 `json:"msg_size,omitempty"` 109 } 110 111 // Peer represents a connected remote node. 112 type Peer struct { 113 rw *conn 114 running map[string]*protoRW 115 log log.Logger 116 created mclock.AbsTime 117 118 wg sync.WaitGroup 119 protoErr chan error 120 closed chan struct{} 121 disc chan DiscReason 122 123 // events receives message send / receive events if set 124 events *event.Feed 125 126 // srvProtocols must link with Server Protocols 127 srvProtocols *[]Protocol 128 } 129 130 // NewPeer returns a peer for testing purposes. 131 func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer { 132 pipe, _ := net.Pipe() 133 conn := &conn{fd: pipe, transport: nil, id: id, caps: caps, name: name} 134 peer := newPeer(conn, nil) 135 close(peer.closed) // ensures Disconnect doesn't block 136 return peer 137 } 138 139 // ID returns the node's public key. 140 func (p *Peer) ID() discover.NodeID { 141 return p.rw.id 142 } 143 144 // Name returns the node name that the remote node advertised. 145 func (p *Peer) Name() string { 146 return p.rw.name 147 } 148 149 // Caps returns the capabilities (supported subprotocols) of the remote peer. 150 func (p *Peer) Caps() []Cap { 151 // TODO: maybe return copy 152 return p.rw.caps 153 } 154 155 // RemoteAddr returns the remote address of the network connection. 156 func (p *Peer) RemoteAddr() net.Addr { 157 return p.rw.fd.RemoteAddr() 158 } 159 160 // LocalAddr returns the local address of the network connection. 161 func (p *Peer) LocalAddr() net.Addr { 162 return p.rw.fd.LocalAddr() 163 } 164 165 // Disconnect terminates the peer connection with the given reason. 166 // It returns immediately and does not wait until the connection is closed. 167 func (p *Peer) Disconnect(reason DiscReason) { 168 select { 169 case p.disc <- reason: 170 case <-p.closed: 171 } 172 } 173 174 // String implements fmt.Stringer. 175 func (p *Peer) String() string { 176 return fmt.Sprintf("Peer %x %v", p.rw.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.flags&inboundConn != 0 182 } 183 184 func newPeer(conn *conn, protocols []Protocol) *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.id, "conn", conn.flags), 194 } 195 return p 196 } 197 198 func (p *Peer) Log() log.Logger { 199 return p.log 200 } 201 202 func (p *Peer) run() (remoteRequested bool, err error) { 203 var ( 204 writeStart = make(chan struct{}, 1) 205 writeErr = make(chan error, 1) 206 readErr = make(chan error, 1) 207 reason DiscReason // sent to the peer 208 ) 209 p.wg.Add(2) 210 go p.readLoop(readErr) 211 go p.pingLoop() 212 213 // Start all protocol handlers. 214 writeStart <- struct{}{} 215 p.startProtocols(writeStart, writeErr) 216 217 // Wait for an error or disconnect. 218 loop: 219 for { 220 select { 221 case err = <-writeErr: 222 // A write finished. Allow the next write to start if 223 // there was no error. 224 if err != nil { 225 reason = DiscNetworkError 226 break loop 227 } 228 writeStart <- struct{}{} 229 case err = <-readErr: 230 if r, ok := err.(DiscReason); ok { 231 remoteRequested = true 232 reason = r 233 } else { 234 reason = DiscNetworkError 235 } 236 break loop 237 case err = <-p.protoErr: 238 reason = discReasonForError(err) 239 break loop 240 case err = <-p.disc: 241 break loop 242 } 243 } 244 245 close(p.closed) 246 p.rw.close(reason) 247 p.wg.Wait() 248 return remoteRequested, err 249 } 250 251 func (p *Peer) pingLoop() { 252 ping := time.NewTimer(pingInterval) 253 defer p.wg.Done() 254 defer ping.Stop() 255 for { 256 select { 257 case <-ping.C: 258 if err := SendItems(p.rw, pingMsg); err != nil { 259 p.protoErr <- err 260 return 261 } 262 ping.Reset(pingInterval) 263 case <-p.closed: 264 return 265 } 266 } 267 } 268 269 func (p *Peer) readLoop(errc chan<- error) { 270 defer p.wg.Done() 271 for { 272 msg, err := p.rw.ReadMsg() 273 if err != nil { 274 errc <- err 275 return 276 } 277 msg.ReceivedAt = time.Now() 278 if err = p.handle(msg); err != nil { 279 errc <- err 280 return 281 } 282 } 283 } 284 285 func (p *Peer) handle(msg Msg) error { 286 switch { 287 case msg.Code == pingMsg: 288 msg.Discard() 289 go SendItems(p.rw, pongMsg) 290 case msg.Code == discMsg: 291 var reason [1]DiscReason 292 // This is the last message. We don't need to discard or 293 // check errors because, the connection will be closed after it. 294 rlp.Decode(msg.Payload, &reason) 295 return reason[0] 296 case msg.Code == BroadcastNewChildChainMsg: 297 // Got New Child Chain message from peer 298 var chainId string 299 if err := msg.Decode(&chainId); err != nil { 300 return err 301 } 302 303 p.log.Infof("Got new child chain msg from Peer %v, Before add protocol. Caps %v, Running Proto %+v", p.String(), p.Caps(), p.Info().Protocols) 304 305 newRunning := p.checkAndUpdateProtocol(chainId) 306 if newRunning { 307 // Add new protocol to peer, tell back to the peer 308 go Send(p.rw, ConfirmNewChildChainMsg, chainId) 309 } 310 311 // Add the cap to the peer, start the protocol 312 p.log.Infof("Got new child chain msg After add protocol. Caps %v, Running Proto %+v", p.Caps(), p.Info().Protocols) 313 314 case msg.Code == ConfirmNewChildChainMsg: 315 // Got New Child Chain message from peer 316 var chainId string 317 if err := msg.Decode(&chainId); err != nil { 318 return err 319 } 320 p.log.Infof("Got confirm msg from Peer %v, Before add protocol. Caps %v, Running Proto %+v", p.String(), p.Caps(), p.Info().Protocols) 321 p.checkAndUpdateProtocol(chainId) 322 p.log.Infof("Got confirm msg After add protocol. Caps %v, Running Proto %+v", p.Caps(), p.Info().Protocols) 323 324 case msg.Code == RefreshValidatorNodeInfoMsg: 325 p.log.Debug("Got refresh validation node information") 326 var valNodeInfo P2PValidatorNodeInfo 327 if err := msg.Decode(&valNodeInfo); err != nil { 328 p.log.Debugf("decode error: %v", err) 329 return err 330 } 331 p.log.Debugf("validation node address: %x", valNodeInfo.Validator.Address) 332 333 if valNodeInfo.Original && p.Info().ID == valNodeInfo.Node.ID.String() { 334 valNodeInfo.Node.IP = p.RemoteAddr().(*net.TCPAddr).IP 335 } 336 valNodeInfo.Original = false 337 338 p.log.Debugf("validator node info: %v", valNodeInfo) 339 340 data, err := rlp.EncodeToBytes(valNodeInfo) 341 if err != nil { 342 p.log.Debugf("encode error: %v", err) 343 return err 344 } 345 p.events.Send(&PeerEvent{ 346 Type: PeerEventTypeRefreshValidator, 347 Peer: p.ID(), 348 Protocol: string(data), 349 }) 350 351 p.log.Debugf("RefreshValidatorNodeInfoMsg handled") 352 353 case msg.Code == RemoveValidatorNodeInfoMsg: 354 p.log.Debug("Got remove validation node infomation") 355 var valNodeInfo P2PValidatorNodeInfo 356 if err := msg.Decode(&valNodeInfo); err != nil { 357 p.log.Debugf("decode error: %v", err) 358 return err 359 } 360 p.log.Debugf("validation node address: %x", valNodeInfo.Validator.Address) 361 362 if valNodeInfo.Original { 363 valNodeInfo.Node.IP = p.RemoteAddr().(*net.TCPAddr).IP 364 valNodeInfo.Original = false 365 } 366 p.log.Debugf("validator node info: %v", valNodeInfo) 367 368 data, err := rlp.EncodeToBytes(valNodeInfo) 369 if err != nil { 370 p.log.Debugf("encode error: %v", err) 371 return err 372 } 373 p.events.Send(&PeerEvent{ 374 Type: PeerEventTypeRemoveValidator, 375 Peer: p.ID(), 376 Protocol: string(data), 377 }) 378 379 p.log.Debug("RemoveValidatorNodeInfoMsg handled") 380 381 case msg.Code < baseProtocolLength: 382 // ignore other base protocol messages 383 return msg.Discard() 384 default: 385 // it's a subprotocol message 386 proto, err := p.getProto(msg.Code) 387 if err != nil { 388 return fmt.Errorf("msg code out of range: %v", msg.Code) 389 } 390 select { 391 case proto.in <- msg: 392 return nil 393 case <-p.closed: 394 return io.EOF 395 } 396 } 397 return nil 398 } 399 400 func (p *Peer) checkAndUpdateProtocol(chainId string) bool { 401 402 childProtocolName := "intchain_" + chainId 403 404 // Check childChainId already added 405 // TODO Protoect the changing of running under multi-thread env 406 if _, exist := p.running[childProtocolName]; exist { 407 p.log.Infof("Child Chain %v is already running on peer", childProtocolName) 408 return false 409 } 410 411 // Check we are support the same child chain or not 412 childProtocolOffset := getLargestOffset(p.running) 413 if match, protoRW := matchServerProtocol(*p.srvProtocols, childProtocolName, childProtocolOffset, p.rw); match { 414 // Start the ProtoRW and add it to running protoRW 415 p.startChildChainProtocol(protoRW) 416 // Add the protoRW to peer 417 p.running[childProtocolName] = protoRW 418 419 protoCap := protoRW.cap() 420 capExist := false 421 for _, cap := range p.rw.caps { 422 if cap.Name == protoCap.Name && cap.Version == protoCap.Version { 423 capExist = true 424 } 425 } 426 if !capExist { 427 p.rw.caps = append(p.rw.caps, protoCap) 428 } 429 return true 430 } 431 432 p.log.Infof("No Local Server Protocol matched, perhaps local server has not start the child chain %v yet.", childProtocolName) 433 return false 434 } 435 436 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 437 n := 0 438 for _, cap := range caps { 439 for _, proto := range protocols { 440 if proto.Name == cap.Name && proto.Version == cap.Version { 441 n++ 442 } 443 } 444 } 445 return n 446 } 447 448 // matchProtocols creates structures for matching named subprotocols. 449 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 450 sort.Sort(capsByNameAndVersion(caps)) 451 offset := baseProtocolLength 452 result := make(map[string]*protoRW) 453 454 outer: 455 for _, cap := range caps { 456 for _, proto := range protocols { 457 if proto.Name == cap.Name && proto.Version == cap.Version { 458 // If an old protocol version matched, revert it 459 if old := result[cap.Name]; old != nil { 460 offset -= old.Length 461 } 462 // Assign the new match 463 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 464 offset += proto.Length 465 466 continue outer 467 } 468 } 469 } 470 return result 471 } 472 473 // matchServerProtocol creates structures for matching named subprotocols. 474 func matchServerProtocol(protocols []Protocol, name string, offset uint64, rw MsgReadWriter) (bool, *protoRW) { 475 for _, proto := range protocols { 476 if proto.Name == name { 477 // return the new protoRW 478 return true, &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 479 } 480 } 481 return false, nil 482 } 483 484 func getLargestOffset(running map[string]*protoRW) uint64 { 485 var largestOffset uint64 = 0 486 for _, proto := range running { 487 offsetEnd := proto.offset + proto.Length 488 if offsetEnd > largestOffset { 489 largestOffset = offsetEnd 490 } 491 } 492 return largestOffset 493 } 494 495 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 496 p.wg.Add(len(p.running)) 497 for _, proto := range p.running { 498 proto := proto 499 proto.closed = p.closed 500 proto.wstart = writeStart 501 proto.werr = writeErr 502 var rw MsgReadWriter = proto 503 if p.events != nil { 504 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 505 } 506 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 507 go func() { 508 err := proto.Run(p, rw) 509 if err == nil { 510 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 511 err = errProtocolReturned 512 } else if err != io.EOF { 513 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 514 } 515 p.protoErr <- err 516 p.wg.Done() 517 }() 518 } 519 } 520 521 func (p *Peer) startChildChainProtocol(proto *protoRW) { 522 p.wg.Add(1) 523 524 proto.closed = p.closed 525 proto.wstart = p.running["intchain"].wstart 526 proto.werr = p.running["intchain"].werr 527 528 var rw MsgReadWriter = proto 529 if p.events != nil { 530 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 531 } 532 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 533 go func() { 534 err := proto.Run(p, rw) 535 if err == nil { 536 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 537 err = errProtocolReturned 538 } else if err != io.EOF { 539 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 540 } 541 p.protoErr <- err 542 p.wg.Done() 543 }() 544 } 545 546 // getProto finds the protocol responsible for handling 547 // the given message code. 548 func (p *Peer) getProto(code uint64) (*protoRW, error) { 549 for _, proto := range p.running { 550 if code >= proto.offset && code < proto.offset+proto.Length { 551 return proto, nil 552 } 553 } 554 return nil, newPeerError(errInvalidMsgCode, "%d", code) 555 } 556 557 type protoRW struct { 558 Protocol 559 in chan Msg // receices read messages 560 closed <-chan struct{} // receives when peer is shutting down 561 wstart <-chan struct{} // receives when write may start 562 werr chan<- error // for write results 563 offset uint64 564 w MsgWriter 565 } 566 567 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 568 if msg.Code >= rw.Length { 569 return newPeerError(errInvalidMsgCode, "not handled") 570 } 571 msg.Code += rw.offset 572 select { 573 case <-rw.wstart: 574 err = rw.w.WriteMsg(msg) 575 // Report write status back to Peer.run. It will initiate 576 // shutdown if the error is non-nil and unblock the next write 577 // otherwise. The calling protocol code should exit for errors 578 // as well but we don't want to rely on that. 579 rw.werr <- err 580 case <-rw.closed: 581 err = fmt.Errorf("shutting down") 582 } 583 return err 584 } 585 586 func (rw *protoRW) ReadMsg() (Msg, error) { 587 select { 588 case msg := <-rw.in: 589 msg.Code -= rw.offset 590 return msg, nil 591 case <-rw.closed: 592 return Msg{}, io.EOF 593 } 594 } 595 596 // PeerInfo represents a short summary of the information known about a connected 597 // peer. Sub-protocol independent fields are contained and initialized here, with 598 // protocol specifics delegated to all connected sub-protocols. 599 type PeerInfo struct { 600 ID string `json:"id"` // Unique node identifier (also the encryption key) 601 Name string `json:"name"` // Name of the node, including client type, version, OS, custom data 602 Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer 603 Network struct { 604 LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection 605 RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection 606 Inbound bool `json:"inbound"` 607 Trusted bool `json:"trusted"` 608 Static bool `json:"static"` 609 } `json:"network"` 610 Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields 611 } 612 613 // Info gathers and returns a collection of metadata known about a peer. 614 func (p *Peer) Info() *PeerInfo { 615 // Gather the protocol capabilities 616 var caps []string 617 for _, cap := range p.Caps() { 618 caps = append(caps, cap.String()) 619 } 620 // Assemble the generic peer metadata 621 info := &PeerInfo{ 622 ID: p.ID().String(), 623 Name: p.Name(), 624 Caps: caps, 625 Protocols: make(map[string]interface{}), 626 } 627 info.Network.LocalAddress = p.LocalAddr().String() 628 info.Network.RemoteAddress = p.RemoteAddr().String() 629 info.Network.Inbound = p.rw.is(inboundConn) 630 info.Network.Trusted = p.rw.is(trustedConn) 631 info.Network.Static = p.rw.is(staticDialedConn) 632 633 // Gather all the running protocol infos 634 for _, proto := range p.running { 635 protoInfo := interface{}("unknown") 636 if query := proto.Protocol.PeerInfo; query != nil { 637 if metadata := query(p.ID()); metadata != nil { 638 protoInfo = metadata 639 } else { 640 protoInfo = "handshake" 641 } 642 } 643 info.Protocols[proto.Name] = protoInfo 644 } 645 return info 646 }