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