github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/dial.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:40</date>
    10  //</624450102777352192>
    11  
    12  
    13  package p2p
    14  
    15  import (
    16  	"container/heap"
    17  	"errors"
    18  	"fmt"
    19  	"net"
    20  	"time"
    21  
    22  	"github.com/ethereum/go-ethereum/log"
    23  	"github.com/ethereum/go-ethereum/p2p/enode"
    24  	"github.com/ethereum/go-ethereum/p2p/netutil"
    25  )
    26  
    27  const (
    28  //这是介于
    29  //重拨某个节点。
    30  	dialHistoryExpiration = 30 * time.Second
    31  
    32  //发现查找受到限制,只能运行
    33  //每隔几秒钟一次。
    34  	lookupInterval = 4 * time.Second
    35  
    36  //如果在这段时间内找不到对等点,则初始引导节点为
    37  //试图连接。
    38  	fallbackInterval = 20 * time.Second
    39  
    40  //端点分辨率通过有界退避进行限制。
    41  	initialResolveDelay = 60 * time.Second
    42  	maxResolveDelay     = time.Hour
    43  )
    44  
    45  //nodeadialer用于连接到网络中的节点,通常使用
    46  //一个底层的net.dialer,但在测试中也使用了net.pipe
    47  type NodeDialer interface {
    48  	Dial(*enode.Node) (net.Conn, error)
    49  }
    50  
    51  //tcpDialer通过使用net.dialer
    52  //创建到网络中节点的TCP连接
    53  type TCPDialer struct {
    54  	*net.Dialer
    55  }
    56  
    57  //拨号创建到节点的TCP连接
    58  func (t TCPDialer) Dial(dest *enode.Node) (net.Conn, error) {
    59  	addr := &net.TCPAddr{IP: dest.IP(), Port: dest.TCP()}
    60  	return t.Dialer.Dial("tcp", addr.String())
    61  }
    62  
    63  //拨号状态计划拨号和查找。
    64  //每次迭代都有机会计算新任务
    65  //在server.run中的主循环。
    66  type dialstate struct {
    67  	maxDynDials int
    68  	ntab        discoverTable
    69  	netrestrict *netutil.Netlist
    70  	self        enode.ID
    71  
    72  	lookupRunning bool
    73  	dialing       map[enode.ID]connFlag
    74  lookupBuf     []*enode.Node //当前发现查找结果
    75  randomNodes   []*enode.Node //从表中填充
    76  	static        map[enode.ID]*dialTask
    77  	hist          *dialHistory
    78  
    79  start     time.Time     //拨号器首次使用的时间
    80  bootnodes []*enode.Node //没有对等机时的默认拨号
    81  }
    82  
    83  type discoverTable interface {
    84  	Close()
    85  	Resolve(*enode.Node) *enode.Node
    86  	LookupRandom() []*enode.Node
    87  	ReadRandomNodes([]*enode.Node) int
    88  }
    89  
    90  //拨号历史记录会记住最近的拨号。
    91  type dialHistory []pastDial
    92  
    93  //PastDial是拨号历史记录中的一个条目。
    94  type pastDial struct {
    95  	id  enode.ID
    96  	exp time.Time
    97  }
    98  
    99  type task interface {
   100  	Do(*Server)
   101  }
   102  
   103  //为所拨的每个节点生成一个拨号任务。它的
   104  //任务运行时无法访问字段。
   105  type dialTask struct {
   106  	flags        connFlag
   107  	dest         *enode.Node
   108  	lastResolved time.Time
   109  	resolveDelay time.Duration
   110  }
   111  
   112  //discovertask运行发现表操作。
   113  //任何时候只有一个discovertask处于活动状态。
   114  //discovertask.do执行随机查找。
   115  type discoverTask struct {
   116  	results []*enode.Node
   117  }
   118  
   119  //如果没有其他任务,则生成waitexpiretask
   120  //在server.run中保持循环。
   121  type waitExpireTask struct {
   122  	time.Duration
   123  }
   124  
   125  func newDialState(self enode.ID, static []*enode.Node, bootnodes []*enode.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist) *dialstate {
   126  	s := &dialstate{
   127  		maxDynDials: maxdyn,
   128  		ntab:        ntab,
   129  		self:        self,
   130  		netrestrict: netrestrict,
   131  		static:      make(map[enode.ID]*dialTask),
   132  		dialing:     make(map[enode.ID]connFlag),
   133  		bootnodes:   make([]*enode.Node, len(bootnodes)),
   134  		randomNodes: make([]*enode.Node, maxdyn/2),
   135  		hist:        new(dialHistory),
   136  	}
   137  	copy(s.bootnodes, bootnodes)
   138  	for _, n := range static {
   139  		s.addStatic(n)
   140  	}
   141  	return s
   142  }
   143  
   144  func (s *dialstate) addStatic(n *enode.Node) {
   145  //这将覆盖任务,而不是更新现有的
   146  //输入,让用户有机会强制执行解决操作。
   147  	s.static[n.ID()] = &dialTask{flags: staticDialedConn, dest: n}
   148  }
   149  
   150  func (s *dialstate) removeStatic(n *enode.Node) {
   151  //这将删除一个任务,因此将来不会尝试连接。
   152  	delete(s.static, n.ID())
   153  //这将删除以前的拨号时间戳,以便应用程序
   154  //可以强制服务器立即与所选对等机重新连接。
   155  	s.hist.remove(n.ID())
   156  }
   157  
   158  func (s *dialstate) newTasks(nRunning int, peers map[enode.ID]*Peer, now time.Time) []task {
   159  	if s.start.IsZero() {
   160  		s.start = now
   161  	}
   162  
   163  	var newtasks []task
   164  	addDial := func(flag connFlag, n *enode.Node) bool {
   165  		if err := s.checkDial(n, peers); err != nil {
   166  			log.Trace("Skipping dial candidate", "id", n.ID(), "addr", &net.TCPAddr{IP: n.IP(), Port: n.TCP()}, "err", err)
   167  			return false
   168  		}
   169  		s.dialing[n.ID()] = flag
   170  		newtasks = append(newtasks, &dialTask{flags: flag, dest: n})
   171  		return true
   172  	}
   173  
   174  //计算此时所需的动态拨号数。
   175  	needDynDials := s.maxDynDials
   176  	for _, p := range peers {
   177  		if p.rw.is(dynDialedConn) {
   178  			needDynDials--
   179  		}
   180  	}
   181  	for _, flag := range s.dialing {
   182  		if flag&dynDialedConn != 0 {
   183  			needDynDials--
   184  		}
   185  	}
   186  
   187  //每次调用时使拨号历史记录过期。
   188  	s.hist.expire(now)
   189  
   190  //如果静态节点未连接,则为其创建拨号。
   191  	for id, t := range s.static {
   192  		err := s.checkDial(t.dest, peers)
   193  		switch err {
   194  		case errNotWhitelisted, errSelf:
   195  			log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()}, "err", err)
   196  			delete(s.static, t.dest.ID())
   197  		case nil:
   198  			s.dialing[id] = t.flags
   199  			newtasks = append(newtasks, t)
   200  		}
   201  	}
   202  //如果我们没有任何对等点,请尝试拨打随机引导节点。这个
   203  //场景对于发现
   204  //桌子上可能满是坏同学,很难找到好同学。
   205  	if len(peers) == 0 && len(s.bootnodes) > 0 && needDynDials > 0 && now.Sub(s.start) > fallbackInterval {
   206  		bootnode := s.bootnodes[0]
   207  		s.bootnodes = append(s.bootnodes[:0], s.bootnodes[1:]...)
   208  		s.bootnodes = append(s.bootnodes, bootnode)
   209  
   210  		if addDial(dynDialedConn, bootnode) {
   211  			needDynDials--
   212  		}
   213  	}
   214  //将表中的随机节点用于所需的一半
   215  //动态拨号。
   216  	randomCandidates := needDynDials / 2
   217  	if randomCandidates > 0 {
   218  		n := s.ntab.ReadRandomNodes(s.randomNodes)
   219  		for i := 0; i < randomCandidates && i < n; i++ {
   220  			if addDial(dynDialedConn, s.randomNodes[i]) {
   221  				needDynDials--
   222  			}
   223  		}
   224  	}
   225  //从随机查找结果创建动态拨号,已尝试删除
   226  //结果缓冲区中的项。
   227  	i := 0
   228  	for ; i < len(s.lookupBuf) && needDynDials > 0; i++ {
   229  		if addDial(dynDialedConn, s.lookupBuf[i]) {
   230  			needDynDials--
   231  		}
   232  	}
   233  	s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])]
   234  //如果需要更多候选项,则启动查找。
   235  	if len(s.lookupBuf) < needDynDials && !s.lookupRunning {
   236  		s.lookupRunning = true
   237  		newtasks = append(newtasks, &discoverTask{})
   238  	}
   239  
   240  //启动计时器,等待下一个节点全部过期
   241  //候选人已被试用,目前没有活动任务。
   242  //这样可以防止拨号程序逻辑没有勾选的情况发生。
   243  //因为没有挂起的事件。
   244  	if nRunning == 0 && len(newtasks) == 0 && s.hist.Len() > 0 {
   245  		t := &waitExpireTask{s.hist.min().exp.Sub(now)}
   246  		newtasks = append(newtasks, t)
   247  	}
   248  	return newtasks
   249  }
   250  
   251  var (
   252  	errSelf             = errors.New("is self")
   253  	errAlreadyDialing   = errors.New("already dialing")
   254  	errAlreadyConnected = errors.New("already connected")
   255  	errRecentlyDialed   = errors.New("recently dialed")
   256  	errNotWhitelisted   = errors.New("not contained in netrestrict whitelist")
   257  )
   258  
   259  func (s *dialstate) checkDial(n *enode.Node, peers map[enode.ID]*Peer) error {
   260  	_, dialing := s.dialing[n.ID()]
   261  	switch {
   262  	case dialing:
   263  		return errAlreadyDialing
   264  	case peers[n.ID()] != nil:
   265  		return errAlreadyConnected
   266  	case n.ID() == s.self:
   267  		return errSelf
   268  	case s.netrestrict != nil && !s.netrestrict.Contains(n.IP()):
   269  		return errNotWhitelisted
   270  	case s.hist.contains(n.ID()):
   271  		return errRecentlyDialed
   272  	}
   273  	return nil
   274  }
   275  
   276  func (s *dialstate) taskDone(t task, now time.Time) {
   277  	switch t := t.(type) {
   278  	case *dialTask:
   279  		s.hist.add(t.dest.ID(), now.Add(dialHistoryExpiration))
   280  		delete(s.dialing, t.dest.ID())
   281  	case *discoverTask:
   282  		s.lookupRunning = false
   283  		s.lookupBuf = append(s.lookupBuf, t.results...)
   284  	}
   285  }
   286  
   287  func (t *dialTask) Do(srv *Server) {
   288  	if t.dest.Incomplete() {
   289  		if !t.resolve(srv) {
   290  			return
   291  		}
   292  	}
   293  	err := t.dial(srv, t.dest)
   294  	if err != nil {
   295  		log.Trace("Dial error", "task", t, "err", err)
   296  //如果拨号失败,请尝试解析静态节点的ID。
   297  		if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 {
   298  			if t.resolve(srv) {
   299  				t.dial(srv, t.dest)
   300  			}
   301  		}
   302  	}
   303  }
   304  
   305  //解决查找目标的当前终结点的尝试
   306  //使用发现。
   307  //
   308  //解决操作通过后退进行节流,以避免淹没
   309  //对不存在的节点进行无用查询的发现网络。
   310  //当找到节点时,退避延迟重置。
   311  func (t *dialTask) resolve(srv *Server) bool {
   312  	if srv.ntab == nil {
   313  		log.Debug("Can't resolve node", "id", t.dest.ID, "err", "discovery is disabled")
   314  		return false
   315  	}
   316  	if t.resolveDelay == 0 {
   317  		t.resolveDelay = initialResolveDelay
   318  	}
   319  	if time.Since(t.lastResolved) < t.resolveDelay {
   320  		return false
   321  	}
   322  	resolved := srv.ntab.Resolve(t.dest)
   323  	t.lastResolved = time.Now()
   324  	if resolved == nil {
   325  		t.resolveDelay *= 2
   326  		if t.resolveDelay > maxResolveDelay {
   327  			t.resolveDelay = maxResolveDelay
   328  		}
   329  		log.Debug("Resolving node failed", "id", t.dest.ID, "newdelay", t.resolveDelay)
   330  		return false
   331  	}
   332  //找到节点。
   333  	t.resolveDelay = initialResolveDelay
   334  	t.dest = resolved
   335  	log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP(), Port: t.dest.TCP()})
   336  	return true
   337  }
   338  
   339  type dialError struct {
   340  	error
   341  }
   342  
   343  //拨号执行实际连接尝试。
   344  func (t *dialTask) dial(srv *Server, dest *enode.Node) error {
   345  	fd, err := srv.Dialer.Dial(dest)
   346  	if err != nil {
   347  		return &dialError{err}
   348  	}
   349  	mfd := newMeteredConn(fd, false, dest.IP())
   350  	return srv.SetupConn(mfd, t.flags, dest)
   351  }
   352  
   353  func (t *dialTask) String() string {
   354  	id := t.dest.ID()
   355  	return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], t.dest.IP(), t.dest.TCP())
   356  }
   357  
   358  func (t *discoverTask) Do(srv *Server) {
   359  //每当动态拨号
   360  //必要的。查找需要花费一些时间,否则
   361  //事件循环旋转过快。
   362  	next := srv.lastLookup.Add(lookupInterval)
   363  	if now := time.Now(); now.Before(next) {
   364  		time.Sleep(next.Sub(now))
   365  	}
   366  	srv.lastLookup = time.Now()
   367  	t.results = srv.ntab.LookupRandom()
   368  }
   369  
   370  func (t *discoverTask) String() string {
   371  	s := "discovery lookup"
   372  	if len(t.results) > 0 {
   373  		s += fmt.Sprintf(" (%d results)", len(t.results))
   374  	}
   375  	return s
   376  }
   377  
   378  func (t waitExpireTask) Do(*Server) {
   379  	time.Sleep(t.Duration)
   380  }
   381  func (t waitExpireTask) String() string {
   382  	return fmt.Sprintf("wait for dial hist expire (%v)", t.Duration)
   383  }
   384  
   385  //仅使用这些方法访问或修改拨号历史记录。
   386  func (h dialHistory) min() pastDial {
   387  	return h[0]
   388  }
   389  func (h *dialHistory) add(id enode.ID, exp time.Time) {
   390  	heap.Push(h, pastDial{id, exp})
   391  
   392  }
   393  func (h *dialHistory) remove(id enode.ID) bool {
   394  	for i, v := range *h {
   395  		if v.id == id {
   396  			heap.Remove(h, i)
   397  			return true
   398  		}
   399  	}
   400  	return false
   401  }
   402  func (h dialHistory) contains(id enode.ID) bool {
   403  	for _, v := range h {
   404  		if v.id == id {
   405  			return true
   406  		}
   407  	}
   408  	return false
   409  }
   410  func (h *dialHistory) expire(now time.Time) {
   411  	for h.Len() > 0 && h.min().exp.Before(now) {
   412  		heap.Pop(h)
   413  	}
   414  }
   415  
   416  //堆接口样板
   417  func (h dialHistory) Len() int           { return len(h) }
   418  func (h dialHistory) Less(i, j int) bool { return h[i].exp.Before(h[j].exp) }
   419  func (h dialHistory) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
   420  func (h *dialHistory) Push(x interface{}) {
   421  	*h = append(*h, x.(pastDial))
   422  }
   423  func (h *dialHistory) Pop() interface{} {
   424  	old := *h
   425  	n := len(old)
   426  	x := old[n-1]
   427  	*h = old[0 : n-1]
   428  	return x
   429  }
   430