github.com/tuotoo/go-ethereum@v1.7.4-0.20171121184211-049797d40a24/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 func newPeer(conn *conn, protocols []Protocol) *Peer { 164 protomap := matchProtocols(protocols, conn.caps, conn) 165 p := &Peer{ 166 rw: conn, 167 running: protomap, 168 created: mclock.Now(), 169 disc: make(chan DiscReason), 170 protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop 171 closed: make(chan struct{}), 172 log: log.New("id", conn.id, "conn", conn.flags), 173 } 174 return p 175 } 176 177 func (p *Peer) Log() log.Logger { 178 return p.log 179 } 180 181 func (p *Peer) run() (remoteRequested bool, err error) { 182 var ( 183 writeStart = make(chan struct{}, 1) 184 writeErr = make(chan error, 1) 185 readErr = make(chan error, 1) 186 reason DiscReason // sent to the peer 187 ) 188 p.wg.Add(2) 189 go p.readLoop(readErr) 190 go p.pingLoop() 191 192 // Start all protocol handlers. 193 writeStart <- struct{}{} 194 p.startProtocols(writeStart, writeErr) 195 196 // Wait for an error or disconnect. 197 loop: 198 for { 199 select { 200 case err = <-writeErr: 201 // A write finished. Allow the next write to start if 202 // there was no error. 203 if err != nil { 204 reason = DiscNetworkError 205 break loop 206 } 207 writeStart <- struct{}{} 208 case err = <-readErr: 209 if r, ok := err.(DiscReason); ok { 210 remoteRequested = true 211 reason = r 212 } else { 213 reason = DiscNetworkError 214 } 215 break loop 216 case err = <-p.protoErr: 217 reason = discReasonForError(err) 218 break loop 219 case err = <-p.disc: 220 break loop 221 } 222 } 223 224 close(p.closed) 225 p.rw.close(reason) 226 p.wg.Wait() 227 return remoteRequested, err 228 } 229 230 func (p *Peer) pingLoop() { 231 ping := time.NewTimer(pingInterval) 232 defer p.wg.Done() 233 defer ping.Stop() 234 for { 235 select { 236 case <-ping.C: 237 if err := SendItems(p.rw, pingMsg); err != nil { 238 p.protoErr <- err 239 return 240 } 241 ping.Reset(pingInterval) 242 case <-p.closed: 243 return 244 } 245 } 246 } 247 248 func (p *Peer) readLoop(errc chan<- error) { 249 defer p.wg.Done() 250 for { 251 msg, err := p.rw.ReadMsg() 252 if err != nil { 253 errc <- err 254 return 255 } 256 msg.ReceivedAt = time.Now() 257 if err = p.handle(msg); err != nil { 258 errc <- err 259 return 260 } 261 } 262 } 263 264 func (p *Peer) handle(msg Msg) error { 265 switch { 266 case msg.Code == pingMsg: 267 msg.Discard() 268 go SendItems(p.rw, pongMsg) 269 case msg.Code == discMsg: 270 var reason [1]DiscReason 271 // This is the last message. We don't need to discard or 272 // check errors because, the connection will be closed after it. 273 rlp.Decode(msg.Payload, &reason) 274 return reason[0] 275 case msg.Code < baseProtocolLength: 276 // ignore other base protocol messages 277 return msg.Discard() 278 default: 279 // it's a subprotocol message 280 proto, err := p.getProto(msg.Code) 281 if err != nil { 282 return fmt.Errorf("msg code out of range: %v", msg.Code) 283 } 284 select { 285 case proto.in <- msg: 286 return nil 287 case <-p.closed: 288 return io.EOF 289 } 290 } 291 return nil 292 } 293 294 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 295 n := 0 296 for _, cap := range caps { 297 for _, proto := range protocols { 298 if proto.Name == cap.Name && proto.Version == cap.Version { 299 n++ 300 } 301 } 302 } 303 return n 304 } 305 306 // matchProtocols creates structures for matching named subprotocols. 307 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 308 sort.Sort(capsByNameAndVersion(caps)) 309 offset := baseProtocolLength 310 result := make(map[string]*protoRW) 311 312 outer: 313 for _, cap := range caps { 314 for _, proto := range protocols { 315 if proto.Name == cap.Name && proto.Version == cap.Version { 316 // If an old protocol version matched, revert it 317 if old := result[cap.Name]; old != nil { 318 offset -= old.Length 319 } 320 // Assign the new match 321 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 322 offset += proto.Length 323 324 continue outer 325 } 326 } 327 } 328 return result 329 } 330 331 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 332 p.wg.Add(len(p.running)) 333 for _, proto := range p.running { 334 proto := proto 335 proto.closed = p.closed 336 proto.wstart = writeStart 337 proto.werr = writeErr 338 var rw MsgReadWriter = proto 339 if p.events != nil { 340 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 341 } 342 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 343 go func() { 344 err := proto.Run(p, rw) 345 if err == nil { 346 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 347 err = errProtocolReturned 348 } else if err != io.EOF { 349 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 350 } 351 p.protoErr <- err 352 p.wg.Done() 353 }() 354 } 355 } 356 357 // getProto finds the protocol responsible for handling 358 // the given message code. 359 func (p *Peer) getProto(code uint64) (*protoRW, error) { 360 for _, proto := range p.running { 361 if code >= proto.offset && code < proto.offset+proto.Length { 362 return proto, nil 363 } 364 } 365 return nil, newPeerError(errInvalidMsgCode, "%d", code) 366 } 367 368 type protoRW struct { 369 Protocol 370 in chan Msg // receices read messages 371 closed <-chan struct{} // receives when peer is shutting down 372 wstart <-chan struct{} // receives when write may start 373 werr chan<- error // for write results 374 offset uint64 375 w MsgWriter 376 } 377 378 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 379 if msg.Code >= rw.Length { 380 return newPeerError(errInvalidMsgCode, "not handled") 381 } 382 msg.Code += rw.offset 383 select { 384 case <-rw.wstart: 385 err = rw.w.WriteMsg(msg) 386 // Report write status back to Peer.run. It will initiate 387 // shutdown if the error is non-nil and unblock the next write 388 // otherwise. The calling protocol code should exit for errors 389 // as well but we don't want to rely on that. 390 rw.werr <- err 391 case <-rw.closed: 392 err = fmt.Errorf("shutting down") 393 } 394 return err 395 } 396 397 func (rw *protoRW) ReadMsg() (Msg, error) { 398 select { 399 case msg := <-rw.in: 400 msg.Code -= rw.offset 401 return msg, nil 402 case <-rw.closed: 403 return Msg{}, io.EOF 404 } 405 } 406 407 // PeerInfo represents a short summary of the information known about a connected 408 // peer. Sub-protocol independent fields are contained and initialized here, with 409 // protocol specifics delegated to all connected sub-protocols. 410 type PeerInfo struct { 411 ID string `json:"id"` // Unique node identifier (also the encryption key) 412 Name string `json:"name"` // Name of the node, including client type, version, OS, custom data 413 Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer 414 Network struct { 415 LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection 416 RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection 417 } `json:"network"` 418 Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields 419 } 420 421 // Info gathers and returns a collection of metadata known about a peer. 422 func (p *Peer) Info() *PeerInfo { 423 // Gather the protocol capabilities 424 var caps []string 425 for _, cap := range p.Caps() { 426 caps = append(caps, cap.String()) 427 } 428 // Assemble the generic peer metadata 429 info := &PeerInfo{ 430 ID: p.ID().String(), 431 Name: p.Name(), 432 Caps: caps, 433 Protocols: make(map[string]interface{}), 434 } 435 info.Network.LocalAddress = p.LocalAddr().String() 436 info.Network.RemoteAddress = p.RemoteAddr().String() 437 438 // Gather all the running protocol infos 439 for _, proto := range p.running { 440 protoInfo := interface{}("unknown") 441 if query := proto.Protocol.PeerInfo; query != nil { 442 if metadata := query(p.ID()); metadata != nil { 443 protoInfo = metadata 444 } else { 445 protoInfo = "handshake" 446 } 447 } 448 info.Protocols[proto.Name] = protoInfo 449 } 450 return info 451 }