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