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