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