github.com/klaytn/klaytn@v1.12.1/networks/p2p/dial.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from p2p/dial.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package p2p
    22  
    23  import (
    24  	"container/heap"
    25  	"crypto/ecdsa"
    26  	"crypto/rand"
    27  	"errors"
    28  	"fmt"
    29  	"net"
    30  	"time"
    31  
    32  	"github.com/klaytn/klaytn/common/math"
    33  	"github.com/klaytn/klaytn/networks/p2p/discover"
    34  	"github.com/klaytn/klaytn/networks/p2p/netutil"
    35  )
    36  
    37  const (
    38  	// This is the amount of time spent waiting in between
    39  	// redialing a certain node.
    40  	dialHistoryExpiration = 30 * time.Second
    41  
    42  	// Discovery lookups are throttled and can only run
    43  	// once every few seconds.
    44  	lookupInterval = 4 * time.Second
    45  
    46  	// If no peers are found for this amount of time, the initial bootnodes are
    47  	// attempted to be connected.
    48  	fallbackInterval = 20 * time.Second
    49  
    50  	// Endpoint resolution is throttled with bounded backoff.
    51  	initialResolveDelay = 60 * time.Second
    52  	maxResolveDelay     = time.Hour
    53  )
    54  
    55  // NodeDialer is used to connect to nodes in the network, typically by using
    56  // an underlying net.Dialer but also using net.Pipe in tests.
    57  type NodeDialer interface {
    58  	Dial(*discover.Node) (net.Conn, error)
    59  	DialMulti(*discover.Node) ([]net.Conn, error)
    60  }
    61  
    62  // TCPDialer implements the NodeDialer interface by using a net.Dialer to
    63  // create TCP connections to nodes in the network.
    64  type TCPDialer struct {
    65  	*net.Dialer
    66  }
    67  
    68  // Dial creates a TCP connection to the node.
    69  func (t TCPDialer) Dial(dest *discover.Node) (net.Conn, error) {
    70  	addr := &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)}
    71  	return t.Dialer.Dial("tcp", addr.String())
    72  }
    73  
    74  // DialMulti creates TCP connections to the node.
    75  func (t TCPDialer) DialMulti(dest *discover.Node) ([]net.Conn, error) {
    76  	var conns []net.Conn
    77  	if dest.TCPs != nil || len(dest.TCPs) != 0 {
    78  		conns = make([]net.Conn, 0, len(dest.TCPs))
    79  		for _, tcp := range dest.TCPs {
    80  			addr := &net.TCPAddr{IP: dest.IP, Port: int(tcp)}
    81  			conn, err := t.Dialer.Dial("tcp", addr.String())
    82  			conns = append(conns, conn)
    83  			if err != nil {
    84  				return nil, err
    85  			}
    86  		}
    87  	}
    88  	return conns, nil
    89  }
    90  
    91  // dialstate schedules dials and discovery lookups.
    92  // it get's a chance to compute new tasks on every iteration
    93  // of the main loop in Server.run.
    94  type dialstate struct {
    95  	maxDynDials int
    96  	ntab        discover.Discovery
    97  	netrestrict *netutil.Netlist
    98  
    99  	lookupRunning      bool
   100  	typedLookupRunning map[dialType]bool
   101  	dialing            map[discover.NodeID]connFlag
   102  	lookupBuf          []*discover.Node // current discovery lookup results
   103  	randomNodes        []*discover.Node // filled from Table
   104  	static             map[discover.NodeID]*dialTask
   105  	hist               *dialHistory
   106  
   107  	start     time.Time        // time when the dialer was first used
   108  	bootnodes []*discover.Node // default dials when there are no peers
   109  
   110  	tsMap map[dialType]typedStatic // tsMap holds typedStaticDial per dialType(discovery name)
   111  }
   112  
   113  // the dial history remembers recent dials.
   114  type dialHistory []pastDial
   115  
   116  // pastDial is an entry in the dial history.
   117  type pastDial struct {
   118  	id  discover.NodeID
   119  	exp time.Time
   120  }
   121  
   122  type task interface {
   123  	Do(Server)
   124  }
   125  
   126  // A dialTask is generated for each node that is dialed. Its
   127  // fields cannot be accessed while the task is running.
   128  type dialTask struct {
   129  	flags        connFlag
   130  	dest         *discover.Node
   131  	lastResolved time.Time
   132  	resolveDelay time.Duration
   133  	failedTry    int
   134  	dialType     dialType
   135  }
   136  
   137  // discoverTask runs discovery table operations.
   138  // Only one discoverTask is active at any time.
   139  // discoverTask.Do performs a random lookup.
   140  type discoverTask struct {
   141  	results []*discover.Node
   142  }
   143  
   144  // A waitExpireTask is generated if there are no other tasks
   145  // to keep the loop in Server.run ticking.
   146  type waitExpireTask struct {
   147  	time.Duration
   148  }
   149  
   150  type typedStatic struct {
   151  	maxNodeCount int
   152  	maxTry       int
   153  }
   154  
   155  type discoverTypedStaticTask struct {
   156  	name    dialType
   157  	max     int
   158  	results []*discover.Node
   159  }
   160  
   161  func (t *discoverTypedStaticTask) Do(srv Server) {
   162  	// newTasks generates a lookup task whenever typed static dials are
   163  	// necessary. Lookups need to take some time, otherwise the
   164  	// event loop spins too fast.
   165  	next := srv.AddLastLookup()
   166  	if now := time.Now(); now.Before(next) {
   167  		time.Sleep(next.Sub(now))
   168  	}
   169  	srv.SetLastLookupToNow()
   170  	t.results = srv.GetNodes(convertDialT2NodeT(t.name), t.max)
   171  	logger.Trace("discoverTypedStaticTask", "result", len(t.results))
   172  }
   173  
   174  func (t *discoverTypedStaticTask) String() string {
   175  	s := fmt.Sprintf("discover TypedStaticTask: max: %d", t.max)
   176  	if len(t.results) > 0 {
   177  		s += fmt.Sprintf(" (%d results)", len(t.results))
   178  	}
   179  	return s
   180  }
   181  
   182  const (
   183  	DT_UNLIMITED = dialType("DIAL_TYPE_UNLIMITED")
   184  	DT_CN        = dialType("CN")
   185  	DT_PN        = dialType("PN")
   186  	DT_EN        = dialType("EN")
   187  )
   188  
   189  type dialType string
   190  
   191  func convertDialT2NodeT(dt dialType) discover.NodeType {
   192  	switch dt {
   193  	case DT_CN:
   194  		return discover.NodeTypeCN
   195  	case DT_PN:
   196  		return discover.NodeTypePN
   197  	default:
   198  		logger.Crit("Support only CN, PN for typed static dial", "DialType", dt)
   199  	}
   200  	return discover.NodeTypeUnknown
   201  }
   202  
   203  func newDialState(static []*discover.Node, bootnodes []*discover.Node, ntab discover.Discovery, maxdyn int,
   204  	netrestrict *netutil.Netlist, privateKey *ecdsa.PrivateKey, tsMap map[dialType]typedStatic,
   205  ) *dialstate {
   206  	if tsMap == nil {
   207  		tsMap = make(map[dialType]typedStatic)
   208  	}
   209  	tsMap[DT_UNLIMITED] = typedStatic{maxTry: math.MaxInt64, maxNodeCount: math.MaxInt64}
   210  
   211  	s := &dialstate{
   212  		maxDynDials:        maxdyn,
   213  		ntab:               ntab,
   214  		netrestrict:        netrestrict,
   215  		static:             make(map[discover.NodeID]*dialTask),
   216  		dialing:            make(map[discover.NodeID]connFlag),
   217  		bootnodes:          make([]*discover.Node, len(bootnodes)),
   218  		randomNodes:        make([]*discover.Node, maxdyn/2),
   219  		hist:               new(dialHistory),
   220  		tsMap:              tsMap,
   221  		typedLookupRunning: make(map[dialType]bool),
   222  	}
   223  	copy(s.bootnodes, bootnodes)
   224  
   225  	if privateKey != nil {
   226  		selfNodeID := discover.PubkeyID(&privateKey.PublicKey)
   227  
   228  		for _, n := range static {
   229  			if selfNodeID != n.ID {
   230  				s.addStatic(n)
   231  			} else {
   232  				logger.Debug("[Dial] Ignored static node which has same id with myself", "mySelfID", selfNodeID)
   233  			}
   234  		}
   235  		return s
   236  	}
   237  
   238  	for _, n := range static {
   239  		s.addStatic(n)
   240  	}
   241  	return s
   242  }
   243  
   244  func (s *dialstate) addStatic(n *discover.Node) {
   245  	s.addTypedStatic(n, DT_UNLIMITED)
   246  }
   247  
   248  func (s *dialstate) addTypedStatic(n *discover.Node, dType dialType) {
   249  	// This overwrites the task instead of updating an existing
   250  	// entry, giving users the opportunity to force a resolve operation.
   251  	if s.static[n.ID] == nil {
   252  		logger.Trace("[Dial] Add TypedStatic", "node", n, "dialType", dType)
   253  		if dType != DT_UNLIMITED {
   254  			s.static[n.ID] = &dialTask{flags: staticDialedConn | trustedConn, dest: n, dialType: dType}
   255  		} else {
   256  			s.static[n.ID] = &dialTask{flags: staticDialedConn, dest: n, dialType: dType}
   257  		}
   258  
   259  	}
   260  }
   261  
   262  func (s *dialstate) removeStatic(n *discover.Node) {
   263  	// This removes a task so future attempts to connect will not be made.
   264  	delete(s.static, n.ID)
   265  	// This removes a previous dial timestamp so that application
   266  	// can force a server to reconnect with chosen peer immediately.
   267  	s.hist.remove(n.ID)
   268  }
   269  
   270  func (s *dialstate) newTasks(nRunning int, peers map[discover.NodeID]*Peer, now time.Time) []task {
   271  	if s.start.IsZero() {
   272  		s.start = now
   273  	}
   274  
   275  	var newtasks []task
   276  	addDialTask := func(flag connFlag, n *discover.Node) bool {
   277  		logger.Trace("[Dial] Try to add dialTask", "connFlag", flag, "node", n)
   278  		if err := s.checkDial(n, peers); err != nil {
   279  			logger.Trace("[Dial] Skipping dial candidate from discovery nodes", "id", n.ID,
   280  				"addr", &net.TCPAddr{IP: n.IP, Port: int(n.TCP)}, "err", err)
   281  			return false
   282  		}
   283  		s.dialing[n.ID] = flag
   284  		logger.Debug("[Dial] Add dial candidate from discovery nodes", "id", n.ID, "addr",
   285  			&net.TCPAddr{IP: n.IP, Port: int(n.TCP)})
   286  		newtasks = append(newtasks, &dialTask{flags: flag, dest: n})
   287  		return true
   288  	}
   289  
   290  	var needDynDials int
   291  	calcNeedDynDials := func() {
   292  		needDynDials = s.maxDynDials
   293  		for _, p := range peers {
   294  			if p.rws[ConnDefault].is(dynDialedConn) {
   295  				needDynDials--
   296  			}
   297  		}
   298  		for _, flag := range s.dialing {
   299  			if flag&dynDialedConn != 0 {
   300  				needDynDials--
   301  			}
   302  		}
   303  	}
   304  
   305  	addStaticDialTasks := func() {
   306  		cnt := make(map[dialType]int)
   307  		for _, t := range s.static {
   308  			cnt[t.dialType]++
   309  		}
   310  
   311  		checkStaticDial := func(dt *dialTask, peers map[discover.NodeID]*Peer) error {
   312  			err := s.checkDial(dt.dest, peers)
   313  			if err != nil {
   314  				return err
   315  			}
   316  
   317  			sd := s.static[dt.dest.ID]
   318  			if sd.flags&staticDialedConn == 0 {
   319  				err := fmt.Errorf("dialer: can't check conntype except staticconn [connType : %d]", sd.flags)
   320  				logger.Error("[Dial] ", "err", err)
   321  				return err
   322  			}
   323  
   324  			typeSpec, ok := s.tsMap[dt.dialType]
   325  			if !ok {
   326  				err := fmt.Errorf("dialer: no data for typespec [%s]", dt.dialType)
   327  				logger.Error("[Dial] ", "err", err)
   328  				return err
   329  			}
   330  
   331  			if dt.failedTry > typeSpec.maxTry {
   332  				return errExpired
   333  			}
   334  
   335  			if cnt[dt.dialType] > s.tsMap[dt.dialType].maxNodeCount {
   336  				return errExceedMaxTypedDial
   337  			}
   338  			return nil
   339  		}
   340  
   341  		for id, t := range s.static {
   342  			err := checkStaticDial(t, peers)
   343  			switch err {
   344  			case errNotWhitelisted, errSelf:
   345  				logger.Info("[Dial] Removing static dial candidate from static nodes", "id",
   346  					t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "err", err)
   347  				delete(s.static, t.dest.ID)
   348  				cnt[t.dialType]--
   349  			case errExpired:
   350  				logger.Info("[Dial] Removing expired dial candidate from static nodes", "id",
   351  					t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "dialType", t.dialType,
   352  					"dialCount", cnt[t.dialType], "err", err)
   353  				delete(s.static, t.dest.ID)
   354  				cnt[t.dialType]--
   355  			case errExceedMaxTypedDial:
   356  				logger.Info("[Dial] Removing exceeded dial candidate from static nodes", "id",
   357  					t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)}, "dialType", t.dialType,
   358  					"dialCount", cnt[t.dialType], "err", err,
   359  				)
   360  				delete(s.static, t.dest.ID)
   361  				cnt[t.dialType]--
   362  			case nil:
   363  				s.dialing[id] = t.flags
   364  				newtasks = append(newtasks, t)
   365  				logger.Info("[Dial] Add dial candidate from static nodes", "id", t.dest.ID,
   366  					"NodeType", t.dest.NType, "ip", t.dest.IP, "mainPort", t.dest.TCP, "port", t.dest.TCPs)
   367  			default:
   368  				logger.Trace("[Dial] Skipped addStaticDial", "reason", err, "to", t.dest)
   369  			}
   370  		}
   371  		// 2. add typedStaticDiscoverTask
   372  		if s.ntab != nil { // Run DiscoveryTasks when only Discovery Mode
   373  			for k, ts := range s.tsMap {
   374  				if k != DT_UNLIMITED && !s.typedLookupRunning[k] && cnt[k] < ts.maxNodeCount {
   375  					logger.Debug("[Dial] Add new discoverTypedStaticTask", "name", k)
   376  					s.typedLookupRunning[k] = true
   377  					maxDiscover := ts.maxNodeCount - cnt[k]
   378  					newtasks = append(newtasks, &discoverTypedStaticTask{name: k, max: maxDiscover})
   379  				}
   380  			}
   381  		}
   382  	}
   383  
   384  	// Compute number of dynamic dials necessary at this point.
   385  	calcNeedDynDials()
   386  	logger.Trace("[Dial] Dynamic Dials Remained Capacity", "needDynDials", needDynDials, "maxDynDials", s.maxDynDials)
   387  
   388  	// Expire the dial history on every invocation.
   389  	s.hist.expire(now)
   390  
   391  	// Create dials for static nodes if they are not connected.
   392  	addStaticDialTasks()
   393  
   394  	// Use random nodes from the table for half of the necessary
   395  	// dynamic dials.
   396  	randomCandidates := needDynDials / 2
   397  	if randomCandidates > 0 {
   398  		n := s.ntab.ReadRandomNodes(s.randomNodes, discover.NodeTypeEN)
   399  		for i := 0; i < randomCandidates && i < n; i++ {
   400  			if addDialTask(dynDialedConn, s.randomNodes[i]) {
   401  				needDynDials--
   402  			}
   403  		}
   404  	}
   405  	// Create dynamic dials from random lookup results, removing tried
   406  	// items from the result buffer.
   407  	i := 0
   408  	for ; i < len(s.lookupBuf) && needDynDials > 0; i++ {
   409  		if addDialTask(dynDialedConn, s.lookupBuf[i]) {
   410  			needDynDials--
   411  		}
   412  	}
   413  	s.lookupBuf = s.lookupBuf[:copy(s.lookupBuf, s.lookupBuf[i:])]
   414  	// Launch a discovery lookup if more candidates are needed.
   415  	if len(s.lookupBuf) < needDynDials && !s.lookupRunning {
   416  		s.lookupRunning = true
   417  		newtasks = append(newtasks, &discoverTask{})
   418  	}
   419  
   420  	// Launch a timer to wait for the next node to expire if all
   421  	// candidates have been tried and no task is currently active.
   422  	// This should prevent cases where the dialer logic is not ticked
   423  	// because there are no pending events.
   424  	if nRunning == 0 && len(newtasks) == 0 && s.hist.Len() > 0 {
   425  		t := &waitExpireTask{s.hist.min().exp.Sub(now)}
   426  		newtasks = append(newtasks, t)
   427  	}
   428  	return newtasks
   429  }
   430  
   431  var (
   432  	errSelf               = errors.New("is self")
   433  	errAlreadyDialing     = errors.New("already dialing")
   434  	errAlreadyConnected   = errors.New("already connected")
   435  	errRecentlyDialed     = errors.New("recently dialed")
   436  	errNotWhitelisted     = errors.New("not contained in netrestrict whitelist")
   437  	errExpired            = errors.New("is expired")
   438  	errExceedMaxTypedDial = errors.New("exceeded max typed dial")
   439  	errUpdateDial         = errors.New("updated to be multichannel peer")
   440  )
   441  
   442  func (s *dialstate) checkDial(n *discover.Node, peers map[discover.NodeID]*Peer) error {
   443  	_, dialing := s.dialing[n.ID]
   444  	switch {
   445  	case dialing:
   446  		return errAlreadyDialing
   447  	case peers[n.ID] != nil:
   448  		return errAlreadyConnected
   449  	case s.ntab != nil && n.ID == s.ntab.Self().ID:
   450  		return errSelf
   451  	case s.netrestrict != nil && !s.netrestrict.Contains(n.IP):
   452  		return errNotWhitelisted
   453  	case s.hist.contains(n.ID):
   454  		return errRecentlyDialed
   455  	}
   456  	return nil
   457  }
   458  
   459  func (s *dialstate) taskDone(t task, now time.Time) {
   460  	switch t := t.(type) {
   461  	case *dialTask:
   462  		s.hist.add(t.dest.ID, now.Add(dialHistoryExpiration))
   463  		delete(s.dialing, t.dest.ID)
   464  	case *discoverTask:
   465  		s.lookupRunning = false
   466  		s.lookupBuf = append(s.lookupBuf, t.results...)
   467  	case *discoverTypedStaticTask:
   468  		logger.Trace("[Dial] discoverTypedStaticTask - done", "t.name", t.name,
   469  			"result count", len(t.results))
   470  		s.typedLookupRunning[t.name] = false
   471  		for _, r := range t.results {
   472  			s.addTypedStatic(r, t.name)
   473  		}
   474  	}
   475  }
   476  
   477  func (t *dialTask) Do(srv Server) {
   478  	if t.dest.Incomplete() {
   479  		if !t.resolve(srv, t.dest.NType) {
   480  			return
   481  		}
   482  	}
   483  	var err error
   484  	if len(t.dest.TCPs) > 1 {
   485  		err = t.dialMulti(srv, t.dest)
   486  	} else {
   487  		err = t.dial(srv, t.dest)
   488  	}
   489  
   490  	if err != nil {
   491  		logger.Debug("[Dial] Failed dialing", "task", t, "err", err)
   492  		// Try resolving the ID of static nodes if dialing failed.
   493  		if _, ok := err.(*dialError); ok && t.flags&staticDialedConn != 0 && t.resolve(srv, t.dest.NType) {
   494  			if len(t.dest.TCPs) > 1 {
   495  				err = t.dialMulti(srv, t.dest)
   496  			} else {
   497  				err = t.dial(srv, t.dest)
   498  			}
   499  		}
   500  
   501  		// redial with updated connection
   502  		if err == errUpdateDial {
   503  			err = t.dialMulti(srv, t.dest)
   504  		}
   505  
   506  		if err != nil {
   507  			t.failedTry++
   508  		}
   509  	}
   510  }
   511  
   512  // resolve attempts to find the current endpoint for the destination
   513  // using discovery.
   514  //
   515  // Resolve operations are throttled with backoff to avoid flooding the
   516  // discovery network with useless queries for nodes that don't exist.
   517  // The backoff delay resets when the node is found.
   518  func (t *dialTask) resolve(srv Server, nType discover.NodeType) bool {
   519  	if srv.CheckNilNetworkTable() {
   520  		logger.Debug("Can't resolve node", "id", t.dest.ID, "NodeType", nType,
   521  			"err", "discovery is disabled")
   522  		return false
   523  	}
   524  	if t.resolveDelay == 0 {
   525  		t.resolveDelay = initialResolveDelay
   526  	}
   527  	if time.Since(t.lastResolved) < t.resolveDelay {
   528  		return false
   529  	}
   530  	resolved := srv.Resolve(t.dest.ID, nType)
   531  	t.lastResolved = time.Now()
   532  	if resolved == nil {
   533  		t.resolveDelay *= 2
   534  		if t.resolveDelay > maxResolveDelay {
   535  			t.resolveDelay = maxResolveDelay
   536  		}
   537  		logger.Debug("Resolving node failed", "id", t.dest.ID, "newdelay", t.resolveDelay)
   538  		return false
   539  	}
   540  	// The node was found.
   541  	t.resolveDelay = initialResolveDelay
   542  	t.dest = resolved
   543  	logger.Debug("Resolved node", "id", t.dest.ID, "addr", &net.TCPAddr{IP: t.dest.IP, Port: int(t.dest.TCP)})
   544  	return true
   545  }
   546  
   547  type dialError struct {
   548  	error
   549  }
   550  
   551  // dial performs the actual connection attempt.
   552  func (t *dialTask) dial(srv Server, dest *discover.Node) error {
   553  	dialTryCounter.Inc(1)
   554  	logger.Debug("[Dial] Dialing node", "id", dest.ID, "addr", &net.TCPAddr{IP: dest.IP, Port: int(dest.TCP)})
   555  
   556  	fd, err := srv.Dial(dest)
   557  	if err != nil {
   558  		dialFailCounter.Inc(1)
   559  		return &dialError{err}
   560  	}
   561  	mfd := newMeteredConn(fd, false)
   562  	return srv.SetupConn(mfd, t.flags, dest)
   563  }
   564  
   565  // dialMulti performs the actual connection attempt.
   566  func (t *dialTask) dialMulti(srv Server, dest *discover.Node) error {
   567  	dialTryCounter.Inc(1)
   568  	addresses := make([]*net.TCPAddr, 0, len(dest.TCPs))
   569  	for _, tcp := range dest.TCPs {
   570  		addresses = append(addresses, &net.TCPAddr{IP: dest.IP, Port: int(tcp)})
   571  	}
   572  	logger.Debug("[Dial] Dialing node", "id", dest.ID, "addresses", addresses)
   573  
   574  	fds, err := srv.DialMulti(dest)
   575  	if err != nil {
   576  		dialFailCounter.Inc(1)
   577  		return &dialError{err}
   578  	}
   579  
   580  	var errorBackup error
   581  	for portOrder, fd := range fds {
   582  		mfd := newMeteredConn(fd, false)
   583  		dest.PortOrder = uint16(portOrder)
   584  		err := srv.SetupConn(mfd, t.flags, dest)
   585  		if err != nil {
   586  			errorBackup = err
   587  		}
   588  	}
   589  	if errorBackup != nil {
   590  		for _, fd := range fds {
   591  			fd.Close()
   592  		}
   593  	}
   594  	return errorBackup
   595  }
   596  
   597  func (t *dialTask) String() string {
   598  	return fmt.Sprintf("%v %x %v:%d", t.flags, t.dest.ID[:8], t.dest.IP, t.dest.TCP)
   599  }
   600  
   601  func (t *discoverTask) Do(srv Server) {
   602  	// newTasks generates a lookup task whenever dynamic dials are
   603  	// necessary. Lookups need to take some time, otherwise the
   604  	// event loop spins too fast.
   605  	next := srv.AddLastLookup()
   606  	if now := time.Now(); now.Before(next) {
   607  		logger.Trace("discoverTask sleep", "period", next.Sub(now))
   608  		time.Sleep(next.Sub(now))
   609  	}
   610  	logger.Trace("discoverTask wakeup")
   611  	srv.SetLastLookupToNow()
   612  	var target discover.NodeID
   613  	rand.Read(target[:])
   614  	t.results = srv.Lookup(target, discover.NodeTypeEN) // TODO-Klaytn Supposed dynamicDial discover only en, but type have to get from argument.
   615  }
   616  
   617  func (t *discoverTask) String() string {
   618  	s := "discovery lookup"
   619  	if len(t.results) > 0 {
   620  		s += fmt.Sprintf(" (%d results)", len(t.results))
   621  	}
   622  	return s
   623  }
   624  
   625  func (t waitExpireTask) Do(Server) {
   626  	time.Sleep(t.Duration)
   627  }
   628  
   629  func (t waitExpireTask) String() string {
   630  	return fmt.Sprintf("wait for dial hist expire (%v)", t.Duration)
   631  }
   632  
   633  // Use only these methods to access or modify dialHistory.
   634  func (h dialHistory) min() pastDial {
   635  	return h[0]
   636  }
   637  
   638  func (h *dialHistory) add(id discover.NodeID, exp time.Time) {
   639  	heap.Push(h, pastDial{id, exp})
   640  }
   641  
   642  func (h *dialHistory) remove(id discover.NodeID) bool {
   643  	for i, v := range *h {
   644  		if v.id == id {
   645  			heap.Remove(h, i)
   646  			return true
   647  		}
   648  	}
   649  	return false
   650  }
   651  
   652  func (h dialHistory) contains(id discover.NodeID) bool {
   653  	for _, v := range h {
   654  		if v.id == id {
   655  			return true
   656  		}
   657  	}
   658  	return false
   659  }
   660  
   661  func (h *dialHistory) expire(now time.Time) {
   662  	for h.Len() > 0 && h.min().exp.Before(now) {
   663  		heap.Pop(h)
   664  	}
   665  }
   666  
   667  // heap.Interface boilerplate
   668  func (h dialHistory) Len() int           { return len(h) }
   669  func (h dialHistory) Less(i, j int) bool { return h[i].exp.Before(h[j].exp) }
   670  func (h dialHistory) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
   671  func (h *dialHistory) Push(x interface{}) {
   672  	*h = append(*h, x.(pastDial))
   673  }
   674  
   675  func (h *dialHistory) Pop() interface{} {
   676  	old := *h
   677  	n := len(old)
   678  	x := old[n-1]
   679  	*h = old[0 : n-1]
   680  	return x
   681  }