github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/peer.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:41</date> 10 //</624450105574952960> 11 12 13 package p2p 14 15 import ( 16 "errors" 17 "fmt" 18 "io" 19 "net" 20 "sort" 21 "sync" 22 "time" 23 24 "github.com/ethereum/go-ethereum/common/mclock" 25 "github.com/ethereum/go-ethereum/event" 26 "github.com/ethereum/go-ethereum/log" 27 "github.com/ethereum/go-ethereum/p2p/enode" 28 "github.com/ethereum/go-ethereum/p2p/enr" 29 "github.com/ethereum/go-ethereum/rlp" 30 ) 31 32 var ( 33 ErrShuttingDown = errors.New("shutting down") 34 ) 35 36 const ( 37 baseProtocolVersion = 5 38 baseProtocolLength = uint64(16) 39 baseProtocolMaxMsgSize = 2 * 1024 40 41 snappyProtocolVersion = 5 42 43 pingInterval = 15 * time.Second 44 ) 45 46 const ( 47 //DEVP2P消息代码 48 handshakeMsg = 0x00 49 discMsg = 0x01 50 pingMsg = 0x02 51 pongMsg = 0x03 52 ) 53 54 //协议握手是协议握手的RLP结构。 55 type protoHandshake struct { 56 Version uint64 57 Name string 58 Caps []Cap 59 ListenPort uint64 60 ID []byte //secp256k1公钥 61 62 //忽略其他字段(为了向前兼容)。 63 Rest []rlp.RawValue `rlp:"tail"` 64 } 65 66 //PeerEventType是P2P服务器发出的对等事件类型。 67 type PeerEventType string 68 69 const ( 70 //PeerEventTypeAdd是添加对等方时发出的事件类型 71 //到P2P服务器 72 PeerEventTypeAdd PeerEventType = "add" 73 74 //PeerEventTypeDrop是当对等机 75 //从p2p服务器上删除 76 PeerEventTypeDrop PeerEventType = "drop" 77 78 //PeerEventTypeMSGSEND是在 79 //消息已成功发送到对等方 80 PeerEventTypeMsgSend PeerEventType = "msgsend" 81 82 //PeerEventTypeMsgrecv是在 83 //从对等端接收消息 84 PeerEventTypeMsgRecv PeerEventType = "msgrecv" 85 ) 86 87 //PeerEvent是在添加或删除对等方时发出的事件 88 //一个p2p服务器,或者当通过对等连接发送或接收消息时 89 type PeerEvent struct { 90 Type PeerEventType `json:"type"` 91 Peer enode.ID `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 //对等表示已连接的远程节点。 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 //事件接收消息发送/接收事件(如果设置) 111 events *event.Feed 112 } 113 114 //newpeer返回用于测试目的的对等机。 115 func NewPeer(id enode.ID, name string, caps []Cap) *Peer { 116 pipe, _ := net.Pipe() 117 node := enode.SignNull(new(enr.Record), id) 118 conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name} 119 peer := newPeer(conn, nil) 120 close(peer.closed) //确保断开连接不会阻塞 121 return peer 122 } 123 124 //ID返回节点的公钥。 125 func (p *Peer) ID() enode.ID { 126 return p.rw.node.ID() 127 } 128 129 //node返回对等方的节点描述符。 130 func (p *Peer) Node() *enode.Node { 131 return p.rw.node 132 } 133 134 //name返回远程节点公布的节点名。 135 func (p *Peer) Name() string { 136 return p.rw.name 137 } 138 139 //caps返回远程对等机的功能(支持的子协议)。 140 func (p *Peer) Caps() []Cap { 141 //托多:也许还回副本 142 return p.rw.caps 143 } 144 145 //remoteaddr返回网络连接的远程地址。 146 func (p *Peer) RemoteAddr() net.Addr { 147 return p.rw.fd.RemoteAddr() 148 } 149 150 //localaddr返回网络连接的本地地址。 151 func (p *Peer) LocalAddr() net.Addr { 152 return p.rw.fd.LocalAddr() 153 } 154 155 //disconnect以给定的原因终止对等连接。 156 //它会立即返回,并且不会等待连接关闭。 157 func (p *Peer) Disconnect(reason DiscReason) { 158 select { 159 case p.disc <- reason: 160 case <-p.closed: 161 } 162 } 163 164 //字符串实现fmt.stringer。 165 func (p *Peer) String() string { 166 id := p.ID() 167 return fmt.Sprintf("Peer %x %v", id[:8], p.RemoteAddr()) 168 } 169 170 //如果对等端是入站连接,则inbound返回true 171 func (p *Peer) Inbound() bool { 172 return p.rw.is(inboundConn) 173 } 174 175 func newPeer(conn *conn, protocols []Protocol) *Peer { 176 protomap := matchProtocols(protocols, conn.caps, conn) 177 p := &Peer{ 178 rw: conn, 179 running: protomap, 180 created: mclock.Now(), 181 disc: make(chan DiscReason), 182 protoErr: make(chan error, len(protomap)+1), //协议+PingLoop 183 closed: make(chan struct{}), 184 log: log.New("id", conn.node.ID(), "conn", conn.flags), 185 } 186 return p 187 } 188 189 func (p *Peer) Log() log.Logger { 190 return p.log 191 } 192 193 func (p *Peer) run() (remoteRequested bool, err error) { 194 var ( 195 writeStart = make(chan struct{}, 1) 196 writeErr = make(chan error, 1) 197 readErr = make(chan error, 1) 198 reason DiscReason //发送给对等方 199 ) 200 p.wg.Add(2) 201 go p.readLoop(readErr) 202 go p.pingLoop() 203 204 //启动所有协议处理程序。 205 writeStart <- struct{}{} 206 p.startProtocols(writeStart, writeErr) 207 208 //等待错误或断开连接。 209 loop: 210 for { 211 select { 212 case err = <-writeErr: 213 //已完成写入。允许在以下情况下开始下一次写入 214 //没有错误。 215 if err != nil { 216 reason = DiscNetworkError 217 break loop 218 } 219 writeStart <- struct{}{} 220 case err = <-readErr: 221 if r, ok := err.(DiscReason); ok { 222 remoteRequested = true 223 reason = r 224 } else { 225 reason = DiscNetworkError 226 } 227 break loop 228 case err = <-p.protoErr: 229 reason = discReasonForError(err) 230 break loop 231 case err = <-p.disc: 232 reason = discReasonForError(err) 233 break loop 234 } 235 } 236 237 close(p.closed) 238 p.rw.close(reason) 239 p.wg.Wait() 240 return remoteRequested, err 241 } 242 243 func (p *Peer) pingLoop() { 244 ping := time.NewTimer(pingInterval) 245 defer p.wg.Done() 246 defer ping.Stop() 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 case <-p.closed: 256 return 257 } 258 } 259 } 260 261 func (p *Peer) readLoop(errc chan<- error) { 262 defer p.wg.Done() 263 for { 264 msg, err := p.rw.ReadMsg() 265 if err != nil { 266 errc <- err 267 return 268 } 269 msg.ReceivedAt = time.Now() 270 if err = p.handle(msg); err != nil { 271 errc <- err 272 return 273 } 274 } 275 } 276 277 func (p *Peer) handle(msg Msg) error { 278 switch { 279 case msg.Code == pingMsg: 280 msg.Discard() 281 go SendItems(p.rw, pongMsg) 282 case msg.Code == discMsg: 283 var reason [1]DiscReason 284 //这是最后一条信息。我们不需要抛弃或 285 //检查错误,因为连接之后将关闭。 286 rlp.Decode(msg.Payload, &reason) 287 return reason[0] 288 case msg.Code < baseProtocolLength: 289 //忽略其他基本协议消息 290 return msg.Discard() 291 default: 292 //这是一个子协议消息 293 proto, err := p.getProto(msg.Code) 294 if err != nil { 295 return fmt.Errorf("msg code out of range: %v", msg.Code) 296 } 297 select { 298 case proto.in <- msg: 299 return nil 300 case <-p.closed: 301 return io.EOF 302 } 303 } 304 return nil 305 } 306 307 func countMatchingProtocols(protocols []Protocol, caps []Cap) int { 308 n := 0 309 for _, cap := range caps { 310 for _, proto := range protocols { 311 if proto.Name == cap.Name && proto.Version == cap.Version { 312 n++ 313 } 314 } 315 } 316 return n 317 } 318 319 //MatchProtocols为匹配命名的子协议创建结构。 320 func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { 321 sort.Sort(capsByNameAndVersion(caps)) 322 offset := baseProtocolLength 323 result := make(map[string]*protoRW) 324 325 outer: 326 for _, cap := range caps { 327 for _, proto := range protocols { 328 if proto.Name == cap.Name && proto.Version == cap.Version { 329 //如果旧协议版本匹配,请将其还原 330 if old := result[cap.Name]; old != nil { 331 offset -= old.Length 332 } 333 //分配新匹配项 334 result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} 335 offset += proto.Length 336 337 continue outer 338 } 339 } 340 } 341 return result 342 } 343 344 func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) { 345 p.wg.Add(len(p.running)) 346 for _, proto := range p.running { 347 proto := proto 348 proto.closed = p.closed 349 proto.wstart = writeStart 350 proto.werr = writeErr 351 var rw MsgReadWriter = proto 352 if p.events != nil { 353 rw = newMsgEventer(rw, p.events, p.ID(), proto.Name) 354 } 355 p.log.Trace(fmt.Sprintf("Starting protocol %s/%d", proto.Name, proto.Version)) 356 go func() { 357 err := proto.Run(p, rw) 358 if err == nil { 359 p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) 360 err = errProtocolReturned 361 } else if err != io.EOF { 362 p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) 363 } 364 p.protoErr <- err 365 p.wg.Done() 366 }() 367 } 368 } 369 370 //getproto查找负责处理的协议 371 //给定的消息代码。 372 func (p *Peer) getProto(code uint64) (*protoRW, error) { 373 for _, proto := range p.running { 374 if code >= proto.offset && code < proto.offset+proto.Length { 375 return proto, nil 376 } 377 } 378 return nil, newPeerError(errInvalidMsgCode, "%d", code) 379 } 380 381 type protoRW struct { 382 Protocol 383 in chan Msg //接收已读消息 384 closed <-chan struct{} //对等机关闭时接收 385 wstart <-chan struct{} //当写入可能开始时接收 386 werr chan<- error //用于写入结果 387 offset uint64 388 w MsgWriter 389 } 390 391 func (rw *protoRW) WriteMsg(msg Msg) (err error) { 392 if msg.Code >= rw.Length { 393 return newPeerError(errInvalidMsgCode, "not handled") 394 } 395 msg.Code += rw.offset 396 select { 397 case <-rw.wstart: 398 err = rw.w.WriteMsg(msg) 399 //将写状态报告回peer.run。它将启动 400 //如果错误为非零,则关闭并取消阻止下一次写入 401 //否则。如果出现错误,调用协议代码应退出。 402 //但我们不想依赖它。 403 rw.werr <- err 404 case <-rw.closed: 405 err = ErrShuttingDown 406 } 407 return err 408 } 409 410 func (rw *protoRW) ReadMsg() (Msg, error) { 411 select { 412 case msg := <-rw.in: 413 msg.Code -= rw.offset 414 return msg, nil 415 case <-rw.closed: 416 return Msg{}, io.EOF 417 } 418 } 419 420 //PeerInfo表示有关连接的 421 //同龄人。子协议独立字段包含在此处并在此处初始化,使用 422 //协议细节委托给所有连接的子协议。 423 type PeerInfo struct { 424 Enode string `json:"enode"` //节点URL 425 ID string `json:"id"` //唯一节点标识符 426 Name string `json:"name"` //节点的名称,包括客户端类型、版本、操作系统、自定义数据 427 Caps []string `json:"caps"` //此对等方公布的协议 428 Network struct { 429 LocalAddress string `json:"localAddress"` //TCP数据连接的本地终结点 430 RemoteAddress string `json:"remoteAddress"` //TCP数据连接的远程终结点 431 Inbound bool `json:"inbound"` 432 Trusted bool `json:"trusted"` 433 Static bool `json:"static"` 434 } `json:"network"` 435 Protocols map[string]interface{} `json:"protocols"` //子协议特定的元数据字段 436 } 437 438 //INFO收集并返回有关对等机的已知元数据集合。 439 func (p *Peer) Info() *PeerInfo { 440 //收集协议功能 441 var caps []string 442 for _, cap := range p.Caps() { 443 caps = append(caps, cap.String()) 444 } 445 //组装通用对等元数据 446 info := &PeerInfo{ 447 Enode: p.Node().String(), 448 ID: p.ID().String(), 449 Name: p.Name(), 450 Caps: caps, 451 Protocols: make(map[string]interface{}), 452 } 453 info.Network.LocalAddress = p.LocalAddr().String() 454 info.Network.RemoteAddress = p.RemoteAddr().String() 455 info.Network.Inbound = p.rw.is(inboundConn) 456 info.Network.Trusted = p.rw.is(trustedConn) 457 info.Network.Static = p.rw.is(staticDialedConn) 458 459 //收集所有正在运行的协议信息 460 for _, proto := range p.running { 461 protoInfo := interface{}("unknown") 462 if query := proto.Protocol.PeerInfo; query != nil { 463 if metadata := query(p.ID()); metadata != nil { 464 protoInfo = metadata 465 } else { 466 protoInfo = "handshake" 467 } 468 } 469 info.Protocols[proto.Name] = protoInfo 470 } 471 return info 472 } 473