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