github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/p2p/dial.go (about)

     1  // Copyright 2015 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  	"container/heap"
    21  	"crypto/rand"
    22  	"errors"
    23  	"fmt"
    24  	"net"
    25  	"time"
    26  
    27  	"github.com/PlatONnetwork/PlatON-Go/log"
    28  	"github.com/PlatONnetwork/PlatON-Go/p2p/discover"
    29  	"github.com/PlatONnetwork/PlatON-Go/p2p/netutil"
    30  )
    31  
    32  const (
    33  	// This is the amount of time spent waiting in between
    34  	// redialing a certain node.
    35  	dialHistoryExpiration = 30 * time.Second
    36  
    37  	// Discovery lookups are throttled and can only run
    38  	// once every few seconds.
    39  	lookupInterval = 4 * time.Second
    40  
    41  	// If no peers are found for this amount of time, the initial bootnodes are
    42  	// attempted to be connected.
    43  	fallbackInterval = 20 * time.Second
    44  
    45  	// Endpoint resolution is throttled with bounded backoff.
    46  	initialResolveDelay = 60 * time.Second
    47  	maxResolveDelay     = time.Hour
    48  )
    49  
    50  type removeConsensusPeerFn func(node *discover.Node)
    51  
    52  // NodeDialer is used to connect to nodes in the network, typically by using
    53  // an underlying net.Dialer but also using net.Pipe in tests
    54  type NodeDialer interface {
    55  	Dial(*discover.Node) (net.Conn, error)
    56  }
    57  
    58  // TCPDialer implements the NodeDialer interface by using a net.Dialer to
    59  // create TCP connections to nodes in the network
    60  type TCPDialer struct {
    61  	*net.Dialer
    62  }
    63  
    64  // Dial creates a TCP connection to the node
    65  func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) {
    66  	addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)}
    67  	return t.Dialer.Dial("tcp", addr.String())
    68  }
    69  
    70  // dialstate schedules dials and discovery lookups.
    71  // it get's a chance to compute new tasks on every iteration
    72  // of the main loop in Server.run.
    73  type dialstate struct {
    74  	maxDynDials int
    75  	ntab        discoverTable
    76  	netrestrict *netutil.Netlist
    77  
    78  	lookupRunning bool
    79  	dialing       map[discover.NodeID]connFlag
    80  	lookupBuf     []*discover.Node // current discovery lookup results
    81  	randomNodes   []*discover.Node // filled from Table
    82  	static        map[discover.NodeID]*dialTask
    83  	//consensus     map[discover.NodeID]*dialTask
    84  	consensus	  *dialedTasks
    85  	hist          *dialHistory
    86  
    87  	start     time.Time        // time when the dialer was first used
    88  	bootnodes []*discover.Node // default dials when there are no peers
    89  }
    90  
    91  type discoverTable interface {
    92  	Self() *discover.Node
    93  	Close()
    94  	Resolve(target discover.NodeID) *discover.Node
    95  	Lookup(target discover.NodeID) []*discover.Node
    96  	ReadRandomNodes([]*discover.Node) int
    97  }
    98  
    99  // the dial history remembers recent dials.
   100  type dialHistory []pastDial
   101  
   102  // pastDial is an entry in the dial history.
   103  type pastDial struct {
   104  	id  discover.NodeID
   105  	exp time.Time
   106  }
   107  
   108  type task interface {
   109  	Do(*Server)
   110  }
   111  
   112  // A dialTask is generated for each node that is dialed. Its
   113  // fields cannot be accessed while the task is running.
   114  type dialTask struct {
   115  	flags        connFlag
   116  	dest         *discover.Node
   117  	lastResolved time.Time
   118  	resolveDelay time.Duration
   119  }
   120  
   121  // discoverTask runs discovery table operations.
   122  // Only one discoverTask is active at any time.
   123  // discoverTask.Do performs a random lookup.
   124  type discoverTask struct {
   125  	results []*discover.Node
   126  }
   127  
   128  // A waitExpireTask is generated if there are no other tasks
   129  // to keep the loop in Server.run ticking.
   130  type waitExpireTask struct {
   131  	time.Duration
   132  }
   133  
   134  func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab discoverTable, maxdyn int, netrestrict *netutil.Netlist, maxConsensusPeers int) *dialstate {
   135  	s := &dialstate{
   136  		maxDynDials: maxdyn,
   137  		ntab:        ntab,
   138  		netrestrict: netrestrict,
   139  		static:      make(map[discover.NodeID]*dialTask),
   140  		//consensus:	 make(map[discover.NodeID]*dialTask),
   141  		consensus:   NewDialedTasks(maxConsensusPeers, nil),
   142  		dialing:     make(map[discover.NodeID]connFlag),
   143  		bootnodes:   make([]*discover.Node, len(bootnodes)),
   144  		randomNodes: make([]*discover.Node, maxdyn/2),
   145  		hist:        new(dialHistory),
   146  	}
   147  	copy(s.bootnodes, bootnodes)
   148  	for _, n := range static {
   149  		s.addStatic(n)
   150  	}
   151  	return s
   152  }
   153  
   154  func (s *dialstate) addStatic(n *discover.Node) {
   155  	// This overwrites the task instead of updating an existing
   156  	// entry, giving users the opportunity to force a resolve operation.
   157  	s.static[n.ID] = &dialTask{flags: staticDialedConn, dest: n}
   158  }
   159  
   160  func (s *dialstate) removeStatic(n *discover.Node) {
   161  	// This removes a task so future attempts to connect will not be made.
   162  	delete(s.static, n.ID)
   163  	// This removes a previous dial timestamp so that application
   164  	// can force a server to reconnect with chosen peer immediately.
   165  	s.hist.remove(n.ID)
   166  }
   167  
   168  func (s *dialstate) addConsensus(n *discover.Node) {
   169  	log.Warn("dial adding consensus node", "node", n)
   170  	//s.consensus[n.ID] = &dialTask{flags: consensusDialedConn, dest: n}
   171  	s.consensus.AddTask(&dialTask{flags: consensusDialedConn, dest: n})
   172  }
   173  
   174  func (s *dialstate) removeConsensus(n *discover.Node) {
   175  	//delete(s.consensus, n.ID)
   176  	s.consensus.RemoveTask(n.ID)
   177  	s.hist.remove(n.ID)
   178  }
   179  
   180  func (s *dialstate) removeConsensusFromQueue(n *discover.Node) {
   181  	//delete(s.consensus, n.ID)
   182  	//s.consensus.RemoveTask(n.ID)
   183  	s.hist.remove(n.ID)
   184  }
   185  
   186  func (s *dialstate) initRemoveConsensusPeerFn(removeConsensusPeerFn removeConsensusPeerFn) {
   187  	s.consensus.InitRemoveConsensusPeerFn(removeConsensusPeerFn)
   188  }
   189  
   190  func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task {
   191  	if s.start.IsZero() {
   192  		s.start = now
   193  	}
   194  
   195  	var newtasks []task
   196  	addDial := func(flag connFlag, n *discover.Node) bool {
   197  		if err := s.checkDial(n, peers); err != nil {
   198  			log.Trace("Skipping dial candidate", "id", n.ID, "addr", &net.TCPAddr{IP: n.IP, Port: int(n.TCP)}, "err", err)
   199  			return false
   200  		}
   201  		s.dialing[n.ID] = flag
   202  		newtasks = append(newtasks, &dialTask{flags: flag, dest: n})
   203  		return true
   204  	}
   205  
   206  	// Compute number of dynamic dials necessary at this point.
   207  	needDynDials := s.maxDynDials
   208  	for _, p := range peers {
   209  		if p.rw.is(dynDialedConn) {
   210  			needDynDials--
   211  		}
   212  	}
   213  	for _, flag := range s.dialing {
   214  		if flag&dynDialedConn != 0 {
   215  			needDynDials--
   216  		}
   217  	}
   218  
   219  	// Expire the dial history on every invocation.
   220  	s.hist.expire(now)
   221  
   222  	// Create dials for static nodes if they are not connected.
   223  	for id, t := range s.static {
   224  		err := s.checkDial(t.dest, peers)
   225  		switch err {
   226  		case errNotWhitelisted, errSelf:
   227  			log.Warn("Removing static dial candidate", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "err", err)
   228  			delete(s.static, t.dest.ID)
   229  		case nil:
   230  			s.dialing[id] = t.flags
   231  			newtasks = append(newtasks, t)
   232  		}
   233  	}
   234  
   235  	// Create dials for consensus nodes if they are not connected.
   236  	for _, t := range s.consensus.ListTask() {
   237  		err := s.checkDial(t.dest, peers)
   238  		switch err {
   239  		case errNotWhitelisted, errSelf:
   240  			//delete(s.consensus, t.dest.ID)
   241  			s.consensus.RemoveTask(t.dest.ID)
   242  		case nil:
   243  			s.dialing[t.dest.ID] = t.flags
   244  			newtasks = append(newtasks, t)
   245  		}
   246  	}
   247  
   248  	// If we don't have any peers whatsoever, try to dial a random bootnode. This
   249  	// scenario is useful for the testnet (and private networks) where the discovery
   250  	// table might be full of mostly bad peers, making it hard to find good ones.
   251  	if len(peers) == 0 && len(s.bootnodes) > 0 && needDynDials > 0 && now.Sub(s.start) > fallbackInterval {
   252  		bootnode := s.bootnodes[0]
   253  		s.bootnodes = append(s.bootnodes[:0], s.bootnodes[1:]...)
   254  		s.bootnodes = append(s.bootnodes, bootnode)
   255  
   256  		if addDial(dynDialedConn, bootnode) {
   257  			needDynDials--
   258  		}
   259  	}
   260  	// Use random nodes from the table for half of the necessary
   261  	// dynamic dials.
   262  	randomCandidates := needDynDials / 2
   263  	if randomCandidates > 0 {
   264  		n := s.ntab.ReadRandomNodes(s.randomNodes)
   265  		for i := 0; i < randomCandidates && i < n; i++ {
   266  			if addDial(dynDialedConn, s.randomNodes[i]) {
   267  				needDynDials--
   268  			}
   269  		}
   270  	}
   271  	// Create dynamic dials from random lookup results, removing tried
   272  	// items from the result buffer.
   273  	i := 0
   274  	for ; i < len(s.lookupBuf) && needDynDials > 0; i++ {
   275  		if addDial(dynDialedConn, s.lookupBuf[i]) {
   276  			needDynDials--
   277  		}
   278  	}
   279  	s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])]
   280  	// Launch a discovery lookup if more candidates are needed.
   281  	if len(s.lookupBuf) < needDynDials && !s.lookupRunning {
   282  		s.lookupRunning = true
   283  		newtasks = append(newtasks, &discoverTask{})
   284  	}
   285  
   286  	// Launch a timer to wait for the next node to expire if all
   287  	// candidates have been tried and no task is currently active.
   288  	// This should prevent cases where the dialer logic is not ticked
   289  	// because there are no pending events.
   290  	if nRunning == 0 && len(newtasks) == 0 && s.hist.Len() > 0 {
   291  		t := &waitExpireTask{s.hist.min().exp.Sub(now)}
   292  		newtasks = append(newtasks, t)
   293  	}
   294  	return newtasks
   295  }
   296  
   297  var (
   298  	errSelf             = errors.New("is self")
   299  	errAlreadyDialing   = errors.New("already dialing")
   300  	errAlreadyConnected = errors.New("already connected")
   301  	errRecentlyDialed   = errors.New("recently dialed")
   302  	errNotWhitelisted   = errors.New("not contained in netrestrict whitelist")
   303  )
   304  
   305  func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) error {
   306  	_, dialing := s.dialing[n.ID]
   307  	switch {
   308  	case dialing:
   309  		return errAlreadyDialing
   310  	case peers[n.ID] != nil:
   311  		return errAlreadyConnected
   312  	case s.ntab != nil && n.ID == s.ntab.Self().ID:
   313  		return errSelf
   314  	case s.netrestrict != nil && !s.netrestrict.Contains(n.IP):
   315  		return errNotWhitelisted
   316  	case s.hist.contains(n.ID):
   317  		return errRecentlyDialed
   318  	}
   319  	return nil
   320  }
   321  
   322  func (s *dialstate) taskDone(t task, now time.Time) {
   323  	switch t := t.(type) {
   324  	case *dialTask:
   325  		s.hist.add(t.dest.ID, now.Add(dialHistoryExpiration))
   326  		delete(s.dialing, t.dest.ID)
   327  	case *discoverTask:
   328  		s.lookupRunning = false
   329  		s.lookupBuf = append(s.lookupBuf, t.results...)
   330  	}
   331  }
   332  
   333  func (t *dialTask) Do(srv *Server) {
   334  	if t.dest.Incomplete() {
   335  		if !t.resolve(srv) {
   336  			return
   337  		}
   338  	}
   339  	err := t.dial(srv, t.dest)
   340  	if err != nil {
   341  		log.Trace("Dial error", "task", t, "err", err)
   342  		// Try resolving the ID of static nodes if dialing failed.
   343  		if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 {
   344  			if t.resolve(srv) {
   345  				t.dial(srv, t.dest)
   346  			}
   347  		}
   348  	}
   349  }
   350  
   351  // resolve attempts to find the current endpoint for the destination
   352  // using discovery.
   353  //
   354  // Resolve operations are throttled with backoff to avoid flooding the
   355  // discovery network with useless queries for nodes that don't exist.
   356  // The backoff delay resets when the node is found.
   357  func (t *dialTask) resolve(srv *Server) bool {
   358  	if srv.ntab == nil {
   359  		log.Debug("Can't resolve node", "id", t.dest.ID, "err", "discovery is disabled")
   360  		return false
   361  	}
   362  	if t.resolveDelay == 0 {
   363  		t.resolveDelay = initialResolveDelay
   364  	}
   365  	if time.Since(t.lastResolved) < t.resolveDelay {
   366  		return false
   367  	}
   368  	resolved := srv.ntab.Resolve(t.dest.ID)
   369  	t.lastResolved = time.Now()
   370  	if resolved == nil {
   371  		t.resolveDelay *= 2
   372  		if t.resolveDelay > maxResolveDelay {
   373  			t.resolveDelay = maxResolveDelay
   374  		}
   375  		log.Debug("Resolving node failed", "id", t.dest.ID, "newdelay", t.resolveDelay)
   376  		return false
   377  	}
   378  	// The node was found.
   379  	t.resolveDelay = initialResolveDelay
   380  	t.dest = resolved
   381  	log.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)})
   382  	return true
   383  }
   384  
   385  type dialError struct {
   386  	error
   387  }
   388  
   389  // dial performs the actual connection attempt.
   390  func (t *dialTask) dial(srv *Server, dest *discover.Node) error {
   391  	fd, err := srv.Dialer.Dial(dest)
   392  	if err != nil {
   393  		return &dialError{err}
   394  	}
   395  	mfd := newMeteredConn(fd, false)
   396  	return srv.SetupConn(mfd, t.flags, dest)
   397  }
   398  
   399  func (t *dialTask) String() string {
   400  	return fmt.Sprintf("%v %x %v:%d", t.flags, t.dest.ID[:8], t.dest.IP, t.dest.TCP)
   401  }
   402  
   403  func (t *discoverTask) Do(srv *Server) {
   404  	// newTasks generates a lookup task whenever dynamic dials are
   405  	// necessary. Lookups need to take some time, otherwise the
   406  	// event loop spins too fast.
   407  	next := srv.lastLookup.Add(lookupInterval)
   408  	if now := time.Now(); now.Before(next) {
   409  		time.Sleep(next.Sub(now))
   410  	}
   411  	srv.lastLookup = time.Now()
   412  	var target discover.NodeID
   413  	rand.Read(target[:])
   414  	t.results = srv.ntab.Lookup(target)
   415  }
   416  
   417  func (t *discoverTask) String() string {
   418  	s := "discovery lookup"
   419  	if len(t.results) > 0 {
   420  		s += fmt.Sprintf(" (%d results)", len(t.results))
   421  	}
   422  	return s
   423  }
   424  
   425  func (t waitExpireTask) Do(*Server) {
   426  	time.Sleep(t.Duration)
   427  }
   428  func (t waitExpireTask) String() string {
   429  	return fmt.Sprintf("wait for dial hist expire (%v)", t.Duration)
   430  }
   431  
   432  // Use only these methods to access or modify dialHistory.
   433  func (h dialHistory) min() pastDial {
   434  	return h[0]
   435  }
   436  func (h *dialHistory) add(id discover.NodeID, exp time.Time) {
   437  	heap.Push(h, pastDial{id, exp})
   438  
   439  }
   440  func (h *dialHistory) remove(id discover.NodeID) bool {
   441  	for i, v := range *h {
   442  		if v.id == id {
   443  			heap.Remove(h, i)
   444  			return true
   445  		}
   446  	}
   447  	return false
   448  }
   449  func (h dialHistory) contains(id discover.NodeID) bool {
   450  	for _, v := range h {
   451  		if v.id == id {
   452  			return true
   453  		}
   454  	}
   455  	return false
   456  }
   457  func (h *dialHistory) expire(now time.Time) {
   458  	for h.Len() > 0 && h.min().exp.Before(now) {
   459  		heap.Pop(h)
   460  	}
   461  }
   462  
   463  // heap.Interface boilerplate
   464  func (h dialHistory) Len() int           { return len(h) }
   465  func (h dialHistory) Less(i, j int) bool { return h[i].exp.Before(h[j].exp) }
   466  func (h dialHistory) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
   467  func (h *dialHistory) Push(x interface{}) {
   468  	*h = append(*h, x.(pastDial))
   469  }
   470  func (h *dialHistory) Pop() interface{} {
   471  	old := *h
   472  	n := len(old)
   473  	x := old[n-1]
   474  	*h = old[0 : n-1]
   475  	return x
   476  }