OSDN Git Service

Thanos did someting
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / connmgr / connmanager.go
diff --git a/vendor/github.com/btcsuite/btcd/connmgr/connmanager.go b/vendor/github.com/btcsuite/btcd/connmgr/connmanager.go
deleted file mode 100644 (file)
index 5f056b3..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-// Copyright (c) 2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package connmgr
-
-import (
-       "errors"
-       "fmt"
-       "net"
-       "sync"
-       "sync/atomic"
-       "time"
-)
-
-// maxFailedAttempts is the maximum number of successive failed connection
-// attempts after which network failure is assumed and new connections will
-// be delayed by the configured retry duration.
-const maxFailedAttempts = 25
-
-var (
-       //ErrDialNil is used to indicate that Dial cannot be nil in the configuration.
-       ErrDialNil = errors.New("Config: Dial cannot be nil")
-
-       // maxRetryDuration is the max duration of time retrying of a persistent
-       // connection is allowed to grow to.  This is necessary since the retry
-       // logic uses a backoff mechanism which increases the interval base times
-       // the number of retries that have been done.
-       maxRetryDuration = time.Minute * 5
-
-       // defaultRetryDuration is the default duration of time for retrying
-       // persistent connections.
-       defaultRetryDuration = time.Second * 5
-
-       // defaultTargetOutbound is the default number of outbound connections to
-       // maintain.
-       defaultTargetOutbound = uint32(8)
-)
-
-// ConnState represents the state of the requested connection.
-type ConnState uint8
-
-// ConnState can be either pending, established, disconnected or failed.  When
-// a new connection is requested, it is attempted and categorized as
-// established or failed depending on the connection result.  An established
-// connection which was disconnected is categorized as disconnected.
-const (
-       ConnPending ConnState = iota
-       ConnEstablished
-       ConnDisconnected
-       ConnFailed
-)
-
-// ConnReq is the connection request to a network address. If permanent, the
-// connection will be retried on disconnection.
-type ConnReq struct {
-       // The following variables must only be used atomically.
-       id uint64
-
-       Addr      net.Addr
-       Permanent bool
-
-       conn       net.Conn
-       state      ConnState
-       stateMtx   sync.RWMutex
-       retryCount uint32
-}
-
-// updateState updates the state of the connection request.
-func (c *ConnReq) updateState(state ConnState) {
-       c.stateMtx.Lock()
-       c.state = state
-       c.stateMtx.Unlock()
-}
-
-// ID returns a unique identifier for the connection request.
-func (c *ConnReq) ID() uint64 {
-       return atomic.LoadUint64(&c.id)
-}
-
-// State is the connection state of the requested connection.
-func (c *ConnReq) State() ConnState {
-       c.stateMtx.RLock()
-       state := c.state
-       c.stateMtx.RUnlock()
-       return state
-}
-
-// String returns a human-readable string for the connection request.
-func (c *ConnReq) String() string {
-       if c.Addr.String() == "" {
-               return fmt.Sprintf("reqid %d", atomic.LoadUint64(&c.id))
-       }
-       return fmt.Sprintf("%s (reqid %d)", c.Addr, atomic.LoadUint64(&c.id))
-}
-
-// Config holds the configuration options related to the connection manager.
-type Config struct {
-       // Listeners defines a slice of listeners for which the connection
-       // manager will take ownership of and accept connections.  When a
-       // connection is accepted, the OnAccept handler will be invoked with the
-       // connection.  Since the connection manager takes ownership of these
-       // listeners, they will be closed when the connection manager is
-       // stopped.
-       //
-       // This field will not have any effect if the OnAccept field is not
-       // also specified.  It may be nil if the caller does not wish to listen
-       // for incoming connections.
-       Listeners []net.Listener
-
-       // OnAccept is a callback that is fired when an inbound connection is
-       // accepted.  It is the caller's responsibility to close the connection.
-       // Failure to close the connection will result in the connection manager
-       // believing the connection is still active and thus have undesirable
-       // side effects such as still counting toward maximum connection limits.
-       //
-       // This field will not have any effect if the Listeners field is not
-       // also specified since there couldn't possibly be any accepted
-       // connections in that case.
-       OnAccept func(net.Conn)
-
-       // TargetOutbound is the number of outbound network connections to
-       // maintain. Defaults to 8.
-       TargetOutbound uint32
-
-       // RetryDuration is the duration to wait before retrying connection
-       // requests. Defaults to 5s.
-       RetryDuration time.Duration
-
-       // OnConnection is a callback that is fired when a new outbound
-       // connection is established.
-       OnConnection func(*ConnReq, net.Conn)
-
-       // OnDisconnection is a callback that is fired when an outbound
-       // connection is disconnected.
-       OnDisconnection func(*ConnReq)
-
-       // GetNewAddress is a way to get an address to make a network connection
-       // to.  If nil, no new connections will be made automatically.
-       GetNewAddress func() (net.Addr, error)
-
-       // Dial connects to the address on the named network. It cannot be nil.
-       Dial func(net.Addr) (net.Conn, error)
-}
-
-// handleConnected is used to queue a successful connection.
-type handleConnected struct {
-       c    *ConnReq
-       conn net.Conn
-}
-
-// handleDisconnected is used to remove a connection.
-type handleDisconnected struct {
-       id    uint64
-       retry bool
-}
-
-// handleFailed is used to remove a pending connection.
-type handleFailed struct {
-       c   *ConnReq
-       err error
-}
-
-// ConnManager provides a manager to handle network connections.
-type ConnManager struct {
-       // The following variables must only be used atomically.
-       connReqCount uint64
-       start        int32
-       stop         int32
-
-       cfg            Config
-       wg             sync.WaitGroup
-       failedAttempts uint64
-       requests       chan interface{}
-       quit           chan struct{}
-}
-
-// handleFailedConn handles a connection failed due to a disconnect or any
-// other failure. If permanent, it retries the connection after the configured
-// retry duration. Otherwise, if required, it makes a new connection request.
-// After maxFailedConnectionAttempts new connections will be retried after the
-// configured retry duration.
-func (cm *ConnManager) handleFailedConn(c *ConnReq) {
-       if atomic.LoadInt32(&cm.stop) != 0 {
-               return
-       }
-       if c.Permanent {
-               c.retryCount++
-               d := time.Duration(c.retryCount) * cm.cfg.RetryDuration
-               if d > maxRetryDuration {
-                       d = maxRetryDuration
-               }
-               log.Debugf("Retrying connection to %v in %v", c, d)
-               time.AfterFunc(d, func() {
-                       cm.Connect(c)
-               })
-       } else if cm.cfg.GetNewAddress != nil {
-               cm.failedAttempts++
-               if cm.failedAttempts >= maxFailedAttempts {
-                       log.Debugf("Max failed connection attempts reached: [%d] "+
-                               "-- retrying connection in: %v", maxFailedAttempts,
-                               cm.cfg.RetryDuration)
-                       time.AfterFunc(cm.cfg.RetryDuration, func() {
-                               cm.NewConnReq()
-                       })
-               } else {
-                       go cm.NewConnReq()
-               }
-       }
-}
-
-// connHandler handles all connection related requests.  It must be run as a
-// goroutine.
-//
-// The connection handler makes sure that we maintain a pool of active outbound
-// connections so that we remain connected to the network.  Connection requests
-// are processed and mapped by their assigned ids.
-func (cm *ConnManager) connHandler() {
-       conns := make(map[uint64]*ConnReq, cm.cfg.TargetOutbound)
-out:
-       for {
-               select {
-               case req := <-cm.requests:
-                       switch msg := req.(type) {
-
-                       case handleConnected:
-                               connReq := msg.c
-                               connReq.updateState(ConnEstablished)
-                               connReq.conn = msg.conn
-                               conns[connReq.id] = connReq
-                               log.Debugf("Connected to %v", connReq)
-                               connReq.retryCount = 0
-                               cm.failedAttempts = 0
-
-                               if cm.cfg.OnConnection != nil {
-                                       go cm.cfg.OnConnection(connReq, msg.conn)
-                               }
-
-                       case handleDisconnected:
-                               if connReq, ok := conns[msg.id]; ok {
-                                       connReq.updateState(ConnDisconnected)
-                                       if connReq.conn != nil {
-                                               connReq.conn.Close()
-                                       }
-                                       log.Debugf("Disconnected from %v", connReq)
-                                       delete(conns, msg.id)
-
-                                       if cm.cfg.OnDisconnection != nil {
-                                               go cm.cfg.OnDisconnection(connReq)
-                                       }
-
-                                       if uint32(len(conns)) < cm.cfg.TargetOutbound && msg.retry {
-                                               cm.handleFailedConn(connReq)
-                                       }
-                               } else {
-                                       log.Errorf("Unknown connection: %d", msg.id)
-                               }
-
-                       case handleFailed:
-                               connReq := msg.c
-                               connReq.updateState(ConnFailed)
-                               log.Debugf("Failed to connect to %v: %v", connReq, msg.err)
-                               cm.handleFailedConn(connReq)
-                       }
-
-               case <-cm.quit:
-                       break out
-               }
-       }
-
-       cm.wg.Done()
-       log.Trace("Connection handler done")
-}
-
-// NewConnReq creates a new connection request and connects to the
-// corresponding address.
-func (cm *ConnManager) NewConnReq() {
-       if atomic.LoadInt32(&cm.stop) != 0 {
-               return
-       }
-       if cm.cfg.GetNewAddress == nil {
-               return
-       }
-
-       c := &ConnReq{}
-       atomic.StoreUint64(&c.id, atomic.AddUint64(&cm.connReqCount, 1))
-
-       addr, err := cm.cfg.GetNewAddress()
-       if err != nil {
-               cm.requests <- handleFailed{c, err}
-               return
-       }
-
-       c.Addr = addr
-
-       cm.Connect(c)
-}
-
-// Connect assigns an id and dials a connection to the address of the
-// connection request.
-func (cm *ConnManager) Connect(c *ConnReq) {
-       if atomic.LoadInt32(&cm.stop) != 0 {
-               return
-       }
-       if atomic.LoadUint64(&c.id) == 0 {
-               atomic.StoreUint64(&c.id, atomic.AddUint64(&cm.connReqCount, 1))
-       }
-       log.Debugf("Attempting to connect to %v", c)
-       conn, err := cm.cfg.Dial(c.Addr)
-       if err != nil {
-               cm.requests <- handleFailed{c, err}
-       } else {
-               cm.requests <- handleConnected{c, conn}
-       }
-}
-
-// Disconnect disconnects the connection corresponding to the given connection
-// id. If permanent, the connection will be retried with an increasing backoff
-// duration.
-func (cm *ConnManager) Disconnect(id uint64) {
-       if atomic.LoadInt32(&cm.stop) != 0 {
-               return
-       }
-       cm.requests <- handleDisconnected{id, true}
-}
-
-// Remove removes the connection corresponding to the given connection
-// id from known connections.
-func (cm *ConnManager) Remove(id uint64) {
-       if atomic.LoadInt32(&cm.stop) != 0 {
-               return
-       }
-       cm.requests <- handleDisconnected{id, false}
-}
-
-// listenHandler accepts incoming connections on a given listener.  It must be
-// run as a goroutine.
-func (cm *ConnManager) listenHandler(listener net.Listener) {
-       log.Infof("Server listening on %s", listener.Addr())
-       for atomic.LoadInt32(&cm.stop) == 0 {
-               conn, err := listener.Accept()
-               if err != nil {
-                       // Only log the error if not forcibly shutting down.
-                       if atomic.LoadInt32(&cm.stop) == 0 {
-                               log.Errorf("Can't accept connection: %v", err)
-                       }
-                       continue
-               }
-               go cm.cfg.OnAccept(conn)
-       }
-
-       cm.wg.Done()
-       log.Tracef("Listener handler done for %s", listener.Addr())
-}
-
-// Start launches the connection manager and begins connecting to the network.
-func (cm *ConnManager) Start() {
-       // Already started?
-       if atomic.AddInt32(&cm.start, 1) != 1 {
-               return
-       }
-
-       log.Trace("Connection manager started")
-       cm.wg.Add(1)
-       go cm.connHandler()
-
-       // Start all the listeners so long as the caller requested them and
-       // provided a callback to be invoked when connections are accepted.
-       if cm.cfg.OnAccept != nil {
-               for _, listner := range cm.cfg.Listeners {
-                       cm.wg.Add(1)
-                       go cm.listenHandler(listner)
-               }
-       }
-
-       for i := atomic.LoadUint64(&cm.connReqCount); i < uint64(cm.cfg.TargetOutbound); i++ {
-               go cm.NewConnReq()
-       }
-}
-
-// Wait blocks until the connection manager halts gracefully.
-func (cm *ConnManager) Wait() {
-       cm.wg.Wait()
-}
-
-// Stop gracefully shuts down the connection manager.
-func (cm *ConnManager) Stop() {
-       if atomic.AddInt32(&cm.stop, 1) != 1 {
-               log.Warnf("Connection manager already stopped")
-               return
-       }
-
-       // Stop all the listeners.  There will not be any listeners if
-       // listening is disabled.
-       for _, listener := range cm.cfg.Listeners {
-               // Ignore the error since this is shutdown and there is no way
-               // to recover anyways.
-               _ = listener.Close()
-       }
-
-       close(cm.quit)
-       log.Trace("Connection manager stopped")
-}
-
-// New returns a new connection manager.
-// Use Start to start connecting to the network.
-func New(cfg *Config) (*ConnManager, error) {
-       if cfg.Dial == nil {
-               return nil, ErrDialNil
-       }
-       // Default to sane values
-       if cfg.RetryDuration <= 0 {
-               cfg.RetryDuration = defaultRetryDuration
-       }
-       if cfg.TargetOutbound == 0 {
-               cfg.TargetOutbound = defaultTargetOutbound
-       }
-       cm := ConnManager{
-               cfg:      *cfg, // Copy so caller can't mutate
-               requests: make(chan interface{}),
-               quit:     make(chan struct{}),
-       }
-       return &cm, nil
-}