github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/peer.go (about)

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