github.com/beyonderyue/gochain/v3@v3.3.6-0.20200509024509-b25a97312b8c/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 "bytes" 21 "context" 22 "encoding/hex" 23 "errors" 24 "fmt" 25 "io" 26 "net" 27 "sort" 28 "sync" 29 "time" 30 31 "go.opencensus.io/trace" 32 33 "github.com/gochain/gochain/v3/common/mclock" 34 "github.com/gochain/gochain/v3/log" 35 "github.com/gochain/gochain/v3/p2p/discover" 36 "github.com/gochain/gochain/v3/rlp" 37 ) 38 39 const ( 40 baseProtocolVersion = 5 41 baseProtocolLength = uint64(16) 42 baseProtocolMaxMsgSize = 2 * 1024 43 44 snappyProtocolVersion = 5 45 46 pingInterval = 15 * time.Second 47 ) 48 49 const ( 50 // devp2p message codes 51 handshakeMsg = 0x00 52 discMsg = 0x01 53 pingMsg = 0x02 54 pongMsg = 0x03 55 getPeersMsg = 0x04 56 peersMsg = 0x05 57 ) 58 59 var ErrShuttingDown = errors.New("shutting down") 60 61 // protoHandshake is the RLP structure of the protocol handshake. 62 type protoHandshake struct { 63 Version uint64 64 Name string 65 Caps []Cap 66 ListenPort uint64 67 ID discover.NodeID 68 69 // Ignore additional fields (for forward compatibility). 70 Rest []rlp.RawValue `rlp:"tail"` 71 } 72 73 // PeerEventType is the type of peer events emitted by a p2p.Server 74 type PeerEventType string 75 76 const ( 77 // PeerEventTypeAdd is the type of event emitted when a peer is added 78 // to a p2p.Server 79 PeerEventTypeAdd PeerEventType = "add" 80 81 // PeerEventTypeDrop is the type of event emitted when a peer is 82 // dropped from a p2p.Server 83 PeerEventTypeDrop PeerEventType = "drop" 84 85 // PeerEventTypeMsgSend is the type of event emitted when a 86 // message is successfully sent to a peer 87 PeerEventTypeMsgSend PeerEventType = "msgsend" 88 89 // PeerEventTypeMsgRecv is the type of event emitted when a 90 // message is received from a peer 91 PeerEventTypeMsgRecv PeerEventType = "msgrecv" 92 ) 93 94 // PeerEvent is an event emitted when peers are either added or dropped from 95 // a p2p.Server or when a message is sent or received on a peer connection 96 type PeerEvent struct { 97 Type PeerEventType `json:"type"` 98 Peer discover.NodeID `json:"peer"` 99 Error string `json:"error,omitempty"` 100 Protocol string `json:"protocol,omitempty"` 101 MsgCode *uint64 `json:"msg_code,omitempty"` 102 MsgSize *uint32 `json:"msg_size,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 *PeerFeed 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.flags&inboundConn != 0 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 } 186 return p 187 } 188 189 func (p *Peer) Log() log.Logger { 190 return p.log 191 } 192 193 func (p *Peer) run() (remoteRequested bool, err error) { 194 var ( 195 writeStart = make(chan struct{}, 1) 196 writeErr = make(chan error, 1) 197 readErr = make(chan error, 1) 198 reason DiscReason // sent to the peer 199 ) 200 p.wg.Add(2) 201 go p.readLoop(readErr) 202 go p.pingLoop() 203 204 // Start all protocol handlers. 205 writeStart <- struct{}{} 206 p.startProtocols(writeStart, writeErr) 207 208 // Wait for an error or disconnect. 209 loop: 210 for { 211 select { 212 case err = <-writeErr: 213 // A write finished. Allow the next write to start if 214 // there was no error. 215 if err != nil { 216 reason = DiscNetworkError 217 break loop 218 } 219 writeStart <- struct{}{} 220 case err = <-readErr: 221 if r, ok := err.(DiscReason); ok { 222 remoteRequested = true 223 reason = r 224 } else { 225 reason = DiscNetworkError 226 } 227 break loop 228 case err = <-p.protoErr: 229 reason = discReasonForError(err) 230 break loop 231 case err = <-p.disc: 232 reason = discReasonForError(err) 233 break loop 234 } 235 } 236 237 close(p.closed) 238 p.rw.close(reason) 239 p.wg.Wait() 240 return remoteRequested, err 241 } 242 243 func (p *Peer) pingLoop() { 244 ping := time.NewTimer(pingInterval) 245 defer p.wg.Done() 246 defer ping.Stop() 247 for { 248 select { 249 case <-ping.C: 250 if err := SendItems(p.rw, pingMsg); err != nil { 251 p.protoErr <- err 252 return 253 } 254 ping.Reset(pingInterval) 255 case <-p.closed: 256 return 257 } 258 } 259 } 260 261 func (p *Peer) readLoop(errc chan<- error) { 262 defer p.wg.Done() 263 for { 264 msg, err := p.rw.ReadMsg() 265 if err != nil { 266 errc <- err 267 return 268 } 269 msg.ReceivedAt = time.Now() 270 if err = p.handle(msg); err != nil { 271 errc <- err 272 return 273 } 274 } 275 } 276 277 func (p *Peer) handle(msg Msg) error { 278 _, span := trace.StartSpan(context.Background(), "Peer.handle") 279 defer span.End() 280 span.AddAttributes(trace.StringAttribute("code", MsgCodeString(msg.Code))) 281 switch { 282 case msg.Code == pingMsg: 283 msg.Discard() 284 go func() { 285 if err := SendItems(p.rw, pongMsg); err != nil { 286 log.Trace("Cannot send items", "err", err) 287 } 288 }() 289 case msg.Code == discMsg: 290 buf := bytes.NewBuffer(make([]byte, 0, msg.Size)) 291 if _, err := io.Copy(buf, msg.Payload); err != nil { 292 return fmt.Errorf("failed to read disc msg: %s", err) 293 } 294 var reason [1]DiscReason 295 // This is the last message. We don't need to discard or 296 // check errors because, the connection will be closed after it. 297 if err := rlp.Decode(buf, &reason); err != nil { 298 p.Log().Error("Cannot decode disc msg payload", "msg", hex.EncodeToString(buf.Bytes()), "err", err) 299 return fmt.Errorf("failed to decode disc msg: %s", err) 300 } 301 return reason[0] 302 case msg.Code < baseProtocolLength: 303 // ignore other base protocol messages 304 return msg.Discard() 305 default: 306 // it's a subprotocol message 307 proto, err := p.getProto(msg.Code) 308 if err != nil { 309 return fmt.Errorf("msg code out of range: %v", msg.Code) 310 } 311 select { 312 case proto.in <- msg: 313 return nil 314 case <-p.closed: 315 return io.EOF 316 } 317 } 318 return nil 319 } 320 321 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 322 n := 0 323 for _, cap := range caps { 324 for _, proto := range protocols { 325 if proto.Name == cap.Name && proto.Version == cap.Version { 326 n++ 327 } 328 } 329 } 330 return n 331 } 332 333 // matchProtocols creates structures for matching named subprotocols. 334 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 335 sort.Sort(capsByNameAndVersion(caps)) 336 offset := baseProtocolLength 337 result := make(map[string]*protoRW) 338 339 outer: 340 for _, cap := range caps { 341 for _, proto := range protocols { 342 if proto.Name == cap.Name && proto.Version == cap.Version { 343 // If an old protocol version matched, revert it 344 if old := result[cap.Name]; old != nil { 345 offset -= old.Length 346 } 347 // Assign the new match 348 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 349 offset += proto.Length 350 351 continue outer 352 } 353 } 354 } 355 return result 356 } 357 358 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 359 p.wg.Add(len(p.running)) 360 for _, proto := range p.running { 361 proto := proto 362 proto.closed = p.closed 363 proto.wstart = writeStart 364 proto.werr = writeErr 365 var rw MsgReadWriter = proto 366 if p.events != nil { 367 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 368 } 369 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 370 go func() { 371 err := proto.Run(p, rw) 372 if err == nil { 373 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 374 err = errProtocolReturned 375 } else if err != io.EOF { 376 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 377 } 378 p.protoErr <- err 379 p.wg.Done() 380 }() 381 } 382 } 383 384 // getProto finds the protocol responsible for handling 385 // the given message code. 386 func (p *Peer) getProto(code uint64) (*protoRW, error) { 387 for _, proto := range p.running { 388 if code >= proto.offset && code < proto.offset+proto.Length { 389 return proto, nil 390 } 391 } 392 return nil, newPeerError(errInvalidMsgCode, "%d", code) 393 } 394 395 type protoRW struct { 396 Protocol 397 in chan Msg // receices read messages 398 closed <-chan struct{} // receives when peer is shutting down 399 wstart <-chan struct{} // receives when write may start 400 werr chan<- error // for write results 401 offset uint64 402 w MsgWriter 403 } 404 405 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 406 if msg.Code >= rw.Length { 407 return newPeerError(errInvalidMsgCode, "not handled") 408 } 409 msg.Code += rw.offset 410 select { 411 case <-rw.wstart: 412 err = rw.w.WriteMsg(msg) 413 // Report write status back to Peer.run. It will initiate 414 // shutdown if the error is non-nil and unblock the next write 415 // otherwise. The calling protocol code should exit for errors 416 // as well but we don't want to rely on that. 417 rw.werr <- err 418 case <-rw.closed: 419 err = ErrShuttingDown 420 } 421 return err 422 } 423 424 func (rw *protoRW) ReadMsg() (Msg, error) { 425 select { 426 case msg := <-rw.in: 427 msg.Code -= rw.offset 428 return msg, nil 429 case <-rw.closed: 430 return Msg{}, io.EOF 431 } 432 } 433 434 // PeerInfo represents a short summary of the information known about a connected 435 // peer. Sub-protocol independent fields are contained and initialized here, with 436 // protocol specifics delegated to all connected sub-protocols. 437 type PeerInfo struct { 438 ID string `json:"id"` // Unique node identifier (also the encryption key) 439 Name string `json:"name"` // Name of the node, including client type, version, OS, custom data 440 Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer 441 Network struct { 442 LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection 443 RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection 444 Inbound bool `json:"inbound"` 445 Trusted bool `json:"trusted"` 446 Static bool `json:"static"` 447 } `json:"network"` 448 Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields 449 } 450 451 // Info gathers and returns a collection of metadata known about a peer. 452 func (p *Peer) Info() *PeerInfo { 453 // Gather the protocol capabilities 454 var caps []string 455 for _, cap := range p.Caps() { 456 caps = append(caps, cap.String()) 457 } 458 // Assemble the generic peer metadata 459 info := &PeerInfo{ 460 ID: p.ID().String(), 461 Name: p.Name(), 462 Caps: caps, 463 Protocols: make(map[string]interface{}), 464 } 465 info.Network.LocalAddress = p.LocalAddr().String() 466 info.Network.RemoteAddress = p.RemoteAddr().String() 467 info.Network.Inbound = p.rw.is(inboundConn) 468 info.Network.Trusted = p.rw.is(trustedConn) 469 info.Network.Static = p.rw.is(staticDialedConn) 470 471 // Gather all the running protocol infos 472 for _, proto := range p.running { 473 protoInfo := interface{}("unknown") 474 if query := proto.Protocol.PeerInfo; query != nil { 475 if metadata := query(p.ID()); metadata != nil { 476 protoInfo = metadata 477 } else { 478 protoInfo = "handshake" 479 } 480 } 481 info.Protocols[proto.Name] = protoInfo 482 } 483 return info 484 } 485 486 type PeerFeed struct { 487 mu sync.RWMutex 488 subs map[chan<- *PeerEvent]string 489 } 490 491 func (f *PeerFeed) Close() { 492 f.mu.Lock() 493 defer f.mu.Unlock() 494 for sub := range f.subs { 495 close(sub) 496 } 497 f.subs = nil 498 } 499 500 func (f *PeerFeed) Subscribe(ch chan<- *PeerEvent, name string) { 501 f.mu.Lock() 502 defer f.mu.Unlock() 503 if f.subs == nil { 504 f.subs = make(map[chan<- *PeerEvent]string) 505 } 506 f.subs[ch] = name 507 } 508 509 func (f *PeerFeed) Unsubscribe(ch chan<- *PeerEvent) { 510 f.mu.Lock() 511 defer f.mu.Unlock() 512 if _, ok := f.subs[ch]; ok { 513 delete(f.subs, ch) 514 close(ch) 515 } 516 } 517 518 const timeout = 500 * time.Millisecond 519 520 func (f *PeerFeed) Send(e *PeerEvent) { 521 f.mu.RLock() 522 defer f.mu.RUnlock() 523 for sub, name := range f.subs { 524 select { 525 case sub <- e: 526 default: 527 start := time.Now() 528 var action string 529 select { 530 case sub <- e: 531 action = "delayed" 532 case <-time.After(timeout): 533 action = "dropped" 534 } 535 dur := time.Since(start) 536 log.Warn(fmt.Sprintf("PeerFeed send %s: channel full", action), "name", name, "cap", cap(sub), "time", dur, "val", e) 537 } 538 } 539 }