github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/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 "container/list" 21 "errors" 22 "fmt" 23 "io" 24 "net" 25 "sort" 26 "strconv" 27 "sync" 28 "time" 29 30 "github.com/PlatONnetwork/PlatON-Go/common/mclock" 31 "github.com/PlatONnetwork/PlatON-Go/event" 32 "github.com/PlatONnetwork/PlatON-Go/log" 33 "github.com/PlatONnetwork/PlatON-Go/p2p/discover" 34 "github.com/PlatONnetwork/PlatON-Go/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 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 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 discover.NodeID `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 } 102 103 // Peer represents a connected remote node. 104 type Peer struct { 105 rw *conn 106 running map[string]*protoRW 107 log log.Logger 108 created mclock.AbsTime 109 110 wg sync.WaitGroup 111 protoErr chan error 112 closed chan struct{} 113 disc chan DiscReason 114 115 // events receives message send / receive events if set 116 events *event.Feed 117 118 PingList *list.List 119 } 120 121 // NewPeer returns a peer for testing purposes. 122 func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer { 123 pipe, _ := net.Pipe() 124 conn := &conn{fd: pipe, transport: nil, id: id, caps: caps, name: name} 125 peer := newPeer(conn, nil) 126 close(peer.closed) // ensures Disconnect doesn't block 127 return peer 128 } 129 130 // ID returns the node's public key. 131 func (p *Peer) ID() discover.NodeID { 132 return p.rw.id 133 } 134 135 // Name returns the node name that the remote node advertised. 136 func (p *Peer) Name() string { 137 return p.rw.name 138 } 139 140 // Caps returns the capabilities (supported subprotocols) of the remote peer. 141 func (p *Peer) Caps() []Cap { 142 // TODO: maybe return copy 143 return p.rw.caps 144 } 145 146 // RemoteAddr returns the remote address of the network connection. 147 func (p *Peer) RemoteAddr() net.Addr { 148 return p.rw.fd.RemoteAddr() 149 } 150 151 // LocalAddr returns the local address of the network connection. 152 func (p *Peer) LocalAddr() net.Addr { 153 return p.rw.fd.LocalAddr() 154 } 155 156 // Disconnect terminates the peer connection with the given reason. 157 // It returns immediately and does not wait until the connection is closed. 158 func (p *Peer) Disconnect(reason DiscReason) { 159 select { 160 case p.disc <- reason: 161 case <-p.closed: 162 } 163 } 164 165 // String implements fmt.Stringer. 166 func (p *Peer) String() string { 167 return fmt.Sprintf("Peer %x %v", p.rw.id[:8], p.RemoteAddr()) 168 } 169 170 // Inbound returns true if the peer is an inbound connection 171 func (p *Peer) Inbound() bool { 172 return p.rw.is(inboundConn) 173 } 174 175 func newPeer(conn *conn, protocols []Protocol) *Peer { 176 protomap := matchProtocols(protocols, conn.caps, conn) 177 p := &Peer{ 178 rw: conn, 179 running: protomap, 180 created: mclock.Now(), 181 disc: make(chan DiscReason), 182 protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop 183 closed: make(chan struct{}), 184 log: log.New("id", conn.id, "conn", conn.flags), 185 PingList: list.New(), 186 } 187 return p 188 } 189 190 func (p *Peer) Log() log.Logger { 191 return p.log 192 } 193 194 func (p *Peer) run() (remoteRequested bool, err error) { 195 var ( 196 writeStart = make(chan struct{}, 1) 197 writeErr = make(chan error, 1) 198 readErr = make(chan error, 1) 199 reason DiscReason // sent to the peer 200 ) 201 p.wg.Add(2) 202 go p.readLoop(readErr) 203 go p.pingLoop() 204 205 // Start all protocol handlers. 206 writeStart <- struct{}{} 207 p.startProtocols(writeStart, writeErr) 208 209 // Wait for an error or disconnect. 210 loop: 211 for { 212 select { 213 case err = <-writeErr: 214 // A write finished. Allow the next write to start if 215 // there was no error. 216 if err != nil { 217 reason = DiscNetworkError 218 log.Debug("network error while sending message to peer", "err", err) 219 break loop 220 } 221 writeStart <- struct{}{} 222 case err = <-readErr: 223 if r, ok := err.(DiscReason); ok { 224 remoteRequested = true 225 reason = r 226 } else { 227 reason = DiscNetworkError 228 } 229 log.Debug("network error while reading message from peer", "err", err) 230 break loop 231 case err = <-p.protoErr: 232 reason = discReasonForError(err) 233 log.Debug("protoErr", "err", err) 234 break loop 235 case err = <-p.disc: 236 reason = discReasonForError(err) 237 log.Debug("disconnection", "err", err) 238 break loop 239 } 240 } 241 242 close(p.closed) 243 p.rw.close(reason) 244 p.wg.Wait() 245 return remoteRequested, err 246 } 247 248 func (p *Peer) pingLoop() { 249 ping := time.NewTimer(pingInterval) 250 defer p.wg.Done() 251 defer ping.Stop() 252 for { 253 select { 254 case <-ping.C: 255 pingTime := strconv.FormatInt(time.Now().UnixNano(), 10) 256 257 if p.PingList.Len() > 5 { 258 front := p.PingList.Front() 259 p.PingList.Remove(front) 260 } 261 p.PingList.PushBack(pingTime) 262 263 log.Trace("send a Ping message", "peerID", p.ID(), "pingTimeNano", pingTime, "PingList.Len", p.PingList.Len()) 264 if err := SendItems(p.rw, pingMsg, pingTime); err != nil { 265 p.protoErr <- err 266 return 267 } 268 /*log.Info("send a Ping message") 269 if err := SendItems(p.rw, pingMsg, strconv.FormatInt(time.Now().UnixNano(), 10)); err != nil { 270 p.protoErr <- err 271 return 272 }*/ 273 ping.Reset(pingInterval) 274 case <-p.closed: 275 log.Trace("Ping loop closed", "peerID", p.ID()) 276 return 277 } 278 } 279 } 280 281 func (p *Peer) readLoop(errc chan<- error) { 282 defer p.wg.Done() 283 for { 284 msg, err := p.rw.ReadMsg() 285 if err != nil { 286 errc <- err 287 return 288 } 289 msg.ReceivedAt = time.Now() 290 if err = p.handle(msg); err != nil { 291 errc <- err 292 return 293 } 294 } 295 } 296 297 func (p *Peer) handle(msg Msg) error { 298 switch { 299 case msg.Code == pingMsg: 300 // modify by Joey 301 var pingTime [1]string 302 msg.Decode(&pingTime) 303 //log.Debug("Receive a Ping message, then response a Pong message", "pingTimeNano", pingTime[0]) 304 305 msg.Discard() 306 go SendItems(p.rw, pongMsg, pingTime[0]) 307 308 /*msg.Discard() 309 go SendItems(p.rw, pongMsg)*/ 310 311 case msg.Code == pongMsg: 312 //added by Joey 313 proto := p.running["eth"] 314 if proto == nil { 315 return msg.Discard() 316 } 317 318 msg.Code = 0x0a + proto.offset 319 320 //code := fmt.Sprintf("msg.Code: 0x%x", msg.Code) 321 //log.Debug("Receive a Pong message, reset msg.Code for eth protocol", "msg.Code", code) 322 323 select { 324 case proto.in <- msg: 325 return nil 326 case <-p.closed: 327 return io.EOF 328 } 329 case msg.Code == discMsg: 330 var reason [1]DiscReason 331 // This is the last message. We don't need to discard or 332 // check errors because, the connection will be closed after it. 333 rlp.Decode(msg.Payload, &reason) 334 return reason[0] 335 case msg.Code < baseProtocolLength: 336 // ignore other base protocol messages 337 return msg.Discard() 338 default: 339 // it's a subprotocol message 340 proto, err := p.getProto(msg.Code) 341 if err != nil { 342 return fmt.Errorf("msg code out of range: %v", msg.Code) 343 } 344 select { 345 case proto.in <- msg: 346 return nil 347 case <-p.closed: 348 return io.EOF 349 } 350 } 351 return nil 352 } 353 354 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 355 n := 0 356 for _, cap := range caps { 357 for _, proto := range protocols { 358 if proto.Name == cap.Name && proto.Version == cap.Version { 359 n++ 360 } 361 } 362 } 363 return n 364 } 365 366 // matchProtocols creates structures for matching named subprotocols. 367 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 368 sort.Sort(capsByNameAndVersion(caps)) 369 offset := baseProtocolLength 370 result := make(map[string]*protoRW) 371 372 outer: 373 for _, cap := range caps { 374 for _, proto := range protocols { 375 if proto.Name == cap.Name && proto.Version == cap.Version { 376 // If an old protocol version matched, revert it 377 if old := result[cap.Name]; old != nil { 378 offset -= old.Length 379 } 380 // Assign the new match 381 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 382 offset += proto.Length 383 384 continue outer 385 } 386 } 387 } 388 return result 389 } 390 391 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 392 p.wg.Add(len(p.running)) 393 for _, proto := range p.running { 394 proto := proto 395 proto.closed = p.closed 396 proto.wstart = writeStart 397 proto.werr = writeErr 398 var rw MsgReadWriter = proto 399 if p.events != nil { 400 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 401 } 402 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 403 go func() { 404 err := proto.Run(p, rw) 405 if err == nil { 406 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 407 err = errProtocolReturned 408 } else if err != io.EOF { 409 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 410 } 411 p.protoErr <- err 412 p.wg.Done() 413 }() 414 } 415 } 416 417 // getProto finds the protocol responsible for handling 418 // the given message code. 419 func (p *Peer) getProto(code uint64) (*protoRW, error) { 420 for _, proto := range p.running { 421 if code >= proto.offset && code < proto.offset+proto.Length { 422 return proto, nil 423 } 424 } 425 return nil, newPeerError(errInvalidMsgCode, "%d", code) 426 } 427 428 type protoRW struct { 429 Protocol 430 in chan Msg // receives read messages 431 closed <-chan struct{} // receives when peer is shutting down 432 wstart <-chan struct{} // receives when write may start 433 werr chan<- error // for write results 434 offset uint64 435 w MsgWriter 436 } 437 438 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 439 if msg.Code >= rw.Length { 440 return newPeerError(errInvalidMsgCode, "not handled") 441 } 442 msg.Code += rw.offset 443 select { 444 case <-rw.wstart: 445 err = rw.w.WriteMsg(msg) 446 // Report write status back to Peer.run. It will initiate 447 // shutdown if the error is non-nil and unblock the next write 448 // otherwise. The calling protocol code should exit for errors 449 // as well but we don't want to rely on that. 450 rw.werr <- err 451 case <-rw.closed: 452 log.Debug("send message to peer error cause peer is shutting down") 453 err = ErrShuttingDown 454 } 455 return err 456 } 457 458 func (rw *protoRW) ReadMsg() (Msg, error) { 459 select { 460 case msg := <-rw.in: 461 msg.Code -= rw.offset 462 return msg, nil 463 case <-rw.closed: 464 log.Error("ReadMsg from peer error, connection is closed") 465 return Msg{}, io.EOF 466 } 467 } 468 469 // PeerInfo represents a short summary of the information known about a connected 470 // peer. Sub-protocol independent fields are contained and initialized here, with 471 // protocol specifics delegated to all connected sub-protocols. 472 type PeerInfo struct { 473 ID string `json:"id"` // Unique node identifier (also the encryption key) 474 Name string `json:"name"` // Name of the node, including client type, version, OS, custom data 475 Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer 476 Network struct { 477 LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection 478 RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection 479 Inbound bool `json:"inbound"` 480 Trusted bool `json:"trusted"` 481 Static bool `json:"static"` 482 Consensus bool `json:"consensus"` 483 } `json:"network"` 484 Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields 485 } 486 487 // Info gathers and returns a collection of metadata known about a peer. 488 func (p *Peer) Info() *PeerInfo { 489 // Gather the protocol capabilities 490 var caps []string 491 for _, cap := range p.Caps() { 492 caps = append(caps, cap.String()) 493 } 494 // Assemble the generic peer metadata 495 info := &PeerInfo{ 496 ID: p.ID().String(), 497 Name: p.Name(), 498 Caps: caps, 499 Protocols: make(map[string]interface{}), 500 } 501 info.Network.LocalAddress = p.LocalAddr().String() 502 info.Network.RemoteAddress = p.RemoteAddr().String() 503 info.Network.Inbound = p.rw.is(inboundConn) 504 info.Network.Trusted = p.rw.is(trustedConn) 505 info.Network.Static = p.rw.is(staticDialedConn) 506 info.Network.Consensus = p.rw.is(consensusDialedConn) 507 508 // Gather all the running protocol infos 509 for _, proto := range p.running { 510 protoInfo := interface{}("unknown") 511 if query := proto.Protocol.PeerInfo; query != nil { 512 if metadata := query(p.ID()); metadata != nil { 513 protoInfo = metadata 514 } else { 515 protoInfo = "handshake" 516 } 517 } 518 info.Protocols[proto.Name] = protoInfo 519 } 520 return info 521 }