github.com/deso-protocol/core@v1.2.9/lib/connection_manager.go (about)

     1  package lib
     2  
     3  import (
     4  	"math"
     5  	"net"
     6  	"strconv"
     7  	"sync/atomic"
     8  	"time"
     9  
    10  	"github.com/btcsuite/btcd/addrmgr"
    11  	chainlib "github.com/btcsuite/btcd/blockchain"
    12  	"github.com/btcsuite/btcd/wire"
    13  	"github.com/decred/dcrd/lru"
    14  	"github.com/deso-protocol/go-deadlock"
    15  	"github.com/golang/glog"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // connection_manager.go contains most of the logic for creating and managing
    20  // connections with peers. A good place to start is the Start() function.
    21  
    22  const (
    23  	// These values behave as -1 when added to a uint. To decrement a uint
    24  	// atomically you need to do use these values.
    25  
    26  	// Uint64Dec decrements a uint64 by one.
    27  	Uint64Dec = ^uint64(0)
    28  	// Uint32Dec decrements a uint32 by one.
    29  	Uint32Dec = ^uint32(0)
    30  )
    31  
    32  type ConnectionManager struct {
    33  	// Keep a reference to the Server.
    34  	// TODO: I'm pretty sure we can make it so that the ConnectionManager and the Peer
    35  	// doesn't need a reference to the Server object. But for now we keep things lazy.
    36  	srv *Server
    37  
    38  	// When --connectips is set, we don't connect to anything from the addrmgr.
    39  	connectIps []string
    40  
    41  	// The address manager keeps track of peer addresses we're aware of. When
    42  	// we need to connect to a new outbound peer, it chooses one of the addresses
    43  	// it's aware of at random and provides it to us.
    44  	addrMgr *addrmgr.AddrManager
    45  	// The interfaces we listen on for new incoming connections.
    46  	listeners []net.Listener
    47  	// The parameters we are initialized with.
    48  	params *DeSoParams
    49  	// The target number of outbound peers we want to have.
    50  	targetOutboundPeers uint32
    51  	// The maximum number of inbound peers we allow.
    52  	maxInboundPeers uint32
    53  	// When true, only one connection per IP is allowed. Prevents eclipse attacks
    54  	// among other things.
    55  	limitOneInboundConnectionPerIP bool
    56  
    57  	// Keep track of the nonces we've sent in our version messages so
    58  	// we can prevent connections to ourselves.
    59  	sentNonces lru.Cache
    60  
    61  	// This section defines the data structures for storing all the
    62  	// peers we're aware of.
    63  	//
    64  	// A count of the number active connections we have for each IP group.
    65  	// We use this to ensure we don't connect to more than one outbound
    66  	// peer from the same IP group. We need a mutex on it because it's used
    67  	// concurrently by many goroutines to figure out if outbound connections
    68  	// should be made to particular addresses.
    69  
    70  	mtxOutboundConnIPGroups deadlock.Mutex
    71  	outboundConnIPGroups    map[string]int
    72  	// The peer maps map peer ID to peers for various types of peer connections.
    73  	//
    74  	// A persistent peer is typically one we got through a commandline argument.
    75  	// The reason it's called persistent is because we maintain a connection to
    76  	// it, and retry the connection if it fails.
    77  	mtxPeerMaps     deadlock.RWMutex
    78  	persistentPeers map[uint64]*Peer
    79  	outboundPeers   map[uint64]*Peer
    80  	inboundPeers    map[uint64]*Peer
    81  	// Track the number of outbound peers we have so that this value can
    82  	// be accessed concurrently when deciding whether or not to add more
    83  	// outbound peers.
    84  	numOutboundPeers   uint32
    85  	numInboundPeers    uint32
    86  	numPersistentPeers uint32
    87  
    88  	// We keep track of the addresses for the outbound peers so that we can
    89  	// avoid choosing them in the address manager. We need a mutex on this
    90  	// guy because many goroutines will be querying the address manager
    91  	// at once.
    92  	mtxConnectedOutboundAddrs deadlock.RWMutex
    93  	connectedOutboundAddrs    map[string]bool
    94  
    95  	// Used to set peer ids. Must be incremented atomically.
    96  	peerIndex uint64
    97  
    98  	serverMessageQueue chan *ServerMessage
    99  
   100  	// Keeps track of the network time, which is the median of all of our
   101  	// peers' time.
   102  	timeSource chainlib.MedianTimeSource
   103  
   104  	// Events that can happen to a peer.
   105  	newPeerChan  chan *Peer
   106  	donePeerChan chan *Peer
   107  
   108  	// stallTimeoutSeconds is how long we wait to receive responses from Peers
   109  	// for certain types of messages.
   110  	stallTimeoutSeconds uint64
   111  
   112  	minFeeRateNanosPerKB uint64
   113  
   114  	// More chans we might want.	modifyRebroadcastInv chan interface{}
   115  	shutdown int32
   116  }
   117  
   118  func NewConnectionManager(
   119  	_params *DeSoParams, _addrMgr *addrmgr.AddrManager, _listeners []net.Listener,
   120  	_connectIps []string, _timeSource chainlib.MedianTimeSource,
   121  	_targetOutboundPeers uint32, _maxInboundPeers uint32,
   122  	_limitOneInboundConnectionPerIP bool,
   123  	_stallTimeoutSeconds uint64,
   124  	_minFeeRateNanosPerKB uint64,
   125  	_serverMessageQueue chan *ServerMessage,
   126  	_srv *Server) *ConnectionManager {
   127  
   128  	return &ConnectionManager{
   129  		srv:        _srv,
   130  		params:     _params,
   131  		addrMgr:    _addrMgr,
   132  		listeners:  _listeners,
   133  		connectIps: _connectIps,
   134  		// We keep track of the last N nonces we've sent in order to detect
   135  		// self connections.
   136  		sentNonces: lru.NewCache(1000),
   137  		timeSource: _timeSource,
   138  
   139  		//newestBlock: _newestBlock,
   140  
   141  		// Initialize the peer data structures.
   142  		outboundConnIPGroups:   make(map[string]int),
   143  		persistentPeers:        make(map[uint64]*Peer),
   144  		outboundPeers:          make(map[uint64]*Peer),
   145  		inboundPeers:           make(map[uint64]*Peer),
   146  		connectedOutboundAddrs: make(map[string]bool),
   147  
   148  		// Initialize the channels.
   149  		newPeerChan:  make(chan *Peer),
   150  		donePeerChan: make(chan *Peer),
   151  
   152  		targetOutboundPeers:            _targetOutboundPeers,
   153  		maxInboundPeers:                _maxInboundPeers,
   154  		limitOneInboundConnectionPerIP: _limitOneInboundConnectionPerIP,
   155  		serverMessageQueue:             _serverMessageQueue,
   156  		stallTimeoutSeconds:            _stallTimeoutSeconds,
   157  		minFeeRateNanosPerKB:           _minFeeRateNanosPerKB,
   158  	}
   159  }
   160  
   161  func (cmgr *ConnectionManager) GetAddrManager() *addrmgr.AddrManager {
   162  	return cmgr.addrMgr
   163  }
   164  
   165  // Check if the address passed shares a group with any addresses already in our
   166  // data structures.
   167  func (cmgr *ConnectionManager) isRedundantGroupKey(na *wire.NetAddress) bool {
   168  	groupKey := addrmgr.GroupKey(na)
   169  
   170  	cmgr.mtxOutboundConnIPGroups.Lock()
   171  	numGroupsForKey := cmgr.outboundConnIPGroups[groupKey]
   172  	cmgr.mtxOutboundConnIPGroups.Unlock()
   173  
   174  	if numGroupsForKey != 0 && numGroupsForKey != 1 {
   175  		glog.V(2).Infof("isRedundantGroupKey: Found numGroupsForKey != (0 or 1). Is (%d) "+
   176  			"instead for addr (%s) and group key (%s). This "+
   177  			"should never happen.", numGroupsForKey, na.IP.String(), groupKey)
   178  	}
   179  
   180  	if numGroupsForKey == 0 {
   181  		return false
   182  	}
   183  	return true
   184  }
   185  
   186  func (cmgr *ConnectionManager) addToGroupKey(na *wire.NetAddress) {
   187  	groupKey := addrmgr.GroupKey(na)
   188  
   189  	cmgr.mtxOutboundConnIPGroups.Lock()
   190  	cmgr.outboundConnIPGroups[groupKey]++
   191  	cmgr.mtxOutboundConnIPGroups.Unlock()
   192  }
   193  
   194  func (cmgr *ConnectionManager) subFromGroupKey(na *wire.NetAddress) {
   195  	groupKey := addrmgr.GroupKey(na)
   196  
   197  	cmgr.mtxOutboundConnIPGroups.Lock()
   198  	cmgr.outboundConnIPGroups[groupKey]--
   199  	cmgr.mtxOutboundConnIPGroups.Unlock()
   200  }
   201  
   202  func (cmgr *ConnectionManager) getRandomAddr() *wire.NetAddress {
   203  	for tries := 0; tries < 100; tries++ {
   204  		// Lock the address map since multiple threads will be trying to read
   205  		// and modify it at the same time.
   206  		cmgr.mtxConnectedOutboundAddrs.RLock()
   207  		addr := cmgr.addrMgr.GetAddress()
   208  		cmgr.mtxConnectedOutboundAddrs.RUnlock()
   209  
   210  		if addr == nil {
   211  			glog.V(2).Infof("ConnectionManager.getRandomAddr: addr from GetAddressWithExclusions was nil")
   212  			break
   213  		}
   214  
   215  		if cmgr.connectedOutboundAddrs[addrmgr.NetAddressKey(addr.NetAddress())] {
   216  			glog.V(2).Infof("ConnectionManager.getRandomAddr: Not choosing already connected address %v:%v", addr.NetAddress().IP, addr.NetAddress().Port)
   217  			continue
   218  		}
   219  
   220  		// We can only have one outbound address per /16. This is similar to
   221  		// Bitcoin and we do it to prevent Sybil attacks.
   222  		if cmgr.isRedundantGroupKey(addr.NetAddress()) {
   223  			glog.V(2).Infof("ConnectionManager.getRandomAddr: Not choosing address due to redundant group key %v:%v", addr.NetAddress().IP, addr.NetAddress().Port)
   224  			continue
   225  		}
   226  
   227  		glog.V(2).Infof("ConnectionManager.getRandomAddr: Returning %v:%v at %d iterations",
   228  			addr.NetAddress().IP, addr.NetAddress().Port, tries)
   229  		return addr.NetAddress()
   230  	}
   231  
   232  	glog.V(2).Infof("ConnectionManager.getRandomAddr: Returning nil")
   233  	return nil
   234  }
   235  
   236  func _delayRetry(retryCount int, persistentAddrForLogging *wire.NetAddress) {
   237  	// No delay if we haven't tried yet or if the number of retries isn't positive.
   238  	if retryCount <= 0 {
   239  		time.Sleep(time.Second)
   240  		return
   241  	}
   242  	numSecs := int(math.Pow(2.0, float64(retryCount)))
   243  	retryDelay := time.Duration(numSecs) * time.Second
   244  
   245  	if persistentAddrForLogging != nil {
   246  		glog.V(1).Infof("Retrying connection to outbound persistent peer: "+
   247  			"(%s:%d) in (%d) seconds.", persistentAddrForLogging.IP.String(),
   248  			persistentAddrForLogging.Port, numSecs)
   249  	} else {
   250  		glog.V(2).Infof("Retrying connection to outbound non-persistent peer in (%d) seconds.", numSecs)
   251  	}
   252  	time.Sleep(retryDelay)
   253  }
   254  
   255  func (cmgr *ConnectionManager) enoughOutboundPeers() bool {
   256  	val := atomic.LoadUint32(&cmgr.numOutboundPeers)
   257  	if val > cmgr.targetOutboundPeers {
   258  		glog.Errorf("enoughOutboundPeers: Connected to too many outbound "+
   259  			"peers: (%d). Should be "+
   260  			"no more than (%d).", val, cmgr.targetOutboundPeers)
   261  		return true
   262  	}
   263  
   264  	if val == cmgr.targetOutboundPeers {
   265  		return true
   266  	}
   267  	return false
   268  }
   269  
   270  // Chooses a random address and tries to connect to it. Repeats this proocess until
   271  // it finds a peer that can pass version negotiation.
   272  func (cmgr *ConnectionManager) _getOutboundConn(persistentAddr *wire.NetAddress) net.Conn {
   273  	// If a persistentAddr was provided then the connection is a persistent
   274  	// one.
   275  	isPersistent := (persistentAddr != nil)
   276  	retryCount := 0
   277  	for {
   278  		// We want to start backing off exponentially once we've gone through enough
   279  		// unsuccessful retries. However, we want to give more slack to non-persistent
   280  		// peers before we start backing off, which is why it's not as cut and dry as
   281  		// just delaying based on the raw number of retries.
   282  		adjustedRetryCount := retryCount
   283  		if !isPersistent {
   284  			// If the address is not persistent, only start backing off once there
   285  			// has been a large number of failed attempts in a row as this likely indicates
   286  			// that there's a connection issue we need to wait out.
   287  			adjustedRetryCount = retryCount - 5
   288  		}
   289  		_delayRetry(adjustedRetryCount, persistentAddr)
   290  		retryCount++
   291  
   292  		// If the connection manager is saturated with non-persistent
   293  		// outbound peers, no need to keep trying non-persistent outbound
   294  		// connections.
   295  		if !isPersistent && cmgr.enoughOutboundPeers() {
   296  			glog.V(1).Infof("Dropping connection request to non-persistent outbound " +
   297  				"peer because we have enough of them.")
   298  			return nil
   299  		}
   300  
   301  		// If we don't have a persistentAddr, pick one from our addrmgr.
   302  		ipNetAddr := persistentAddr
   303  		if ipNetAddr == nil {
   304  			ipNetAddr = cmgr.getRandomAddr()
   305  		}
   306  		if ipNetAddr == nil {
   307  			// This should never happen but if it does, sleep a bit and try again.
   308  			glog.V(1).Infof("_getOutboundConn: No valid addresses to connect to.")
   309  			time.Sleep(time.Second)
   310  			continue
   311  		}
   312  
   313  		netAddr := net.TCPAddr{
   314  			IP:   ipNetAddr.IP,
   315  			Port: int(ipNetAddr.Port),
   316  		}
   317  
   318  		// If the peer is not persistent, update the addrmgr.
   319  		glog.V(1).Infof("Attempting to connect to addr: %v", netAddr)
   320  		if !isPersistent {
   321  			cmgr.addrMgr.Attempt(ipNetAddr)
   322  		}
   323  		var err error
   324  		conn, err := net.DialTimeout(netAddr.Network(), netAddr.String(), cmgr.params.DialTimeout)
   325  		if err != nil {
   326  			// If we failed to connect to this peer, get a new address and try again.
   327  			glog.V(1).Infof("Connection to addr (%v) failed: %v", netAddr, err)
   328  			continue
   329  		}
   330  
   331  		// We were able to dial successfully so we'll break out now.
   332  		glog.V(1).Infof("Connected to addr: %v", netAddr)
   333  
   334  		// If this was a non-persistent outbound connection, mark the address as
   335  		// connected in the addrmgr.
   336  		if !isPersistent {
   337  			cmgr.addrMgr.Connected(ipNetAddr)
   338  		}
   339  
   340  		// We made a successful outbound connection so return.
   341  		return conn
   342  	}
   343  }
   344  
   345  func IPToNetAddr(ipStr string, addrMgr *addrmgr.AddrManager, params *DeSoParams) (*wire.NetAddress, error) {
   346  	port := params.DefaultSocketPort
   347  	host, portstr, err := net.SplitHostPort(ipStr)
   348  	if err != nil {
   349  		// No port specified so leave port=default and set
   350  		// host to the ipStr.
   351  		host = ipStr
   352  	} else {
   353  		pp, err := strconv.ParseUint(portstr, 10, 16)
   354  		if err != nil {
   355  			return nil, errors.Wrapf(err, "IPToNetAddr: Can not parse port from %s for ip", ipStr)
   356  		}
   357  		port = uint16(pp)
   358  	}
   359  	netAddr, err := addrMgr.HostToNetAddress(host, port, 0)
   360  	if err != nil {
   361  		return nil, errors.Wrapf(err, "IPToNetAddr: Can not parse port from %s for ip", ipStr)
   362  	}
   363  	return netAddr, nil
   364  }
   365  
   366  // Connect either an INBOUND or OUTBOUND peer. If conn == nil, then we will set up
   367  // an OUTBOUND peer. Otherwise we will use the conn to create an INBOUND
   368  // peer. If the connectoin is OUTBOUND and the persistentAddr is set, then
   369  // we will connect only to that addr. Otherwise, we will use the addrmgr to
   370  // randomly select addrs and create OUTBOUND connections with them until
   371  // we find a worthy peer.
   372  func (cmgr *ConnectionManager) ConnectPeer(conn net.Conn, persistentAddr *wire.NetAddress) {
   373  	// If we don't have a connection object then we will try and make an
   374  	// outbound connection to a peer to get one.
   375  	isOutbound := false
   376  	if conn == nil {
   377  		isOutbound = true
   378  	}
   379  	isPersistent := (persistentAddr != nil)
   380  	retryCount := 0
   381  	for {
   382  		if isPersistent {
   383  			_delayRetry(retryCount, persistentAddr)
   384  		}
   385  		retryCount++
   386  
   387  		// If this is an outbound peer, create an outbound connection.
   388  		if isOutbound {
   389  			conn = cmgr._getOutboundConn(persistentAddr)
   390  		}
   391  
   392  		if conn == nil {
   393  			// Conn should only be nil if this is a non-persistent outbound peer.
   394  			if isPersistent {
   395  				glog.Errorf("ConnectPeer: Got a nil connection for a persistent peer. This should never happen: (%s)", persistentAddr.IP.String())
   396  			}
   397  
   398  			// If we end up without a connection object, it implies we had enough
   399  			// outbound peers so just return.
   400  			return
   401  		}
   402  
   403  		// At this point conn is set so create a peer object to do
   404  		// a version negotiation.
   405  		na, err := IPToNetAddr(conn.RemoteAddr().String(), cmgr.addrMgr, cmgr.params)
   406  		if err != nil {
   407  			glog.Errorf("ConnectPeer: Problem calling ipToNetAddr for addr: (%s) err: (%v)", conn.RemoteAddr().String(), err)
   408  
   409  			// If we get an error in the conversion and this is an
   410  			// outbound connection, keep trying it. Otherwise, just return.
   411  			if isOutbound {
   412  				continue
   413  			}
   414  			return
   415  		}
   416  		peer := NewPeer(conn, isOutbound, na, isPersistent,
   417  			cmgr.stallTimeoutSeconds,
   418  			cmgr.minFeeRateNanosPerKB,
   419  			cmgr.params,
   420  			cmgr.srv.incomingMessages, cmgr, cmgr.srv)
   421  
   422  		if err := peer.NegotiateVersion(cmgr.params.VersionNegotiationTimeout); err != nil {
   423  			glog.Errorf("ConnectPeer: Problem negotiating version with peer with addr: (%s) err: (%v)", conn.RemoteAddr().String(), err)
   424  
   425  			// If we have an error in the version negotiation we disconnect
   426  			// from this peer.
   427  			peer.conn.Close()
   428  
   429  			// If the connection is outbound, then
   430  			// we try a new connection until we get one that works. Otherwise
   431  			// we break.
   432  			if isOutbound {
   433  				continue
   434  			}
   435  			return
   436  		}
   437  		peer._logVersionSuccess()
   438  
   439  		// If the version negotiation worked and we have an outbound non-persistent
   440  		// connection, mark the address as good in the addrmgr.
   441  		if isOutbound && !isPersistent {
   442  			cmgr.addrMgr.Good(na)
   443  		}
   444  
   445  		// We connected to the peer and it passed its version negotiation.
   446  		// Handle the next steps in the main loop.
   447  		cmgr.newPeerChan <- peer
   448  
   449  		// Once we've successfully connected to a valid peer we're done. The connection
   450  		// manager will handle starting the peer and, if this is an outbound peer and
   451  		// the peer later disconnects,
   452  		// it will potentially try and reconnect the peer or replace the peer with
   453  		// a new one so that we always maintain a fixed number of outbound peers.
   454  		return
   455  	}
   456  }
   457  
   458  func (cmgr *ConnectionManager) _initiateOutboundConnections() {
   459  	// This is a hack to make outbound connections go away.
   460  	if cmgr.targetOutboundPeers == 0 {
   461  		return
   462  	}
   463  	if len(cmgr.connectIps) > 0 {
   464  		// Connect to addresses passed via the --connectips flag. These addresses
   465  		// are persistent in the sense that if we disconnect from one, we will
   466  		// try to reconnect to the same one.
   467  		for _, connectIp := range cmgr.connectIps {
   468  			ipNetAddr, err := IPToNetAddr(connectIp, cmgr.addrMgr, cmgr.params)
   469  			if err != nil {
   470  				glog.Error(errors.Errorf("Couldn't connect to IP %v: %v", connectIp, err))
   471  				continue
   472  			}
   473  
   474  			go func(na *wire.NetAddress) {
   475  				cmgr.ConnectPeer(nil, na)
   476  			}(ipNetAddr)
   477  		}
   478  		return
   479  	}
   480  	// Only connect to addresses from the addrmgr if we don't specify --connectips.
   481  	// These addresses are *not* persistent, meaning if we disconnect from one we'll
   482  	// try a different one.
   483  	//
   484  	// TODO: We should try more addresses than we need initially to increase the
   485  	// speed at which we saturate our outbound connections. The ConnectionManager
   486  	// will handle the disconnection from peers once we have enough outbound
   487  	// connections. I had this as the logic before but removed it because it caused
   488  	// contention of the addrMgr's lock.
   489  	for ii := 0; ii < int(cmgr.targetOutboundPeers); ii++ {
   490  		go cmgr.ConnectPeer(nil, nil)
   491  	}
   492  }
   493  
   494  func (cmgr *ConnectionManager) _isFromRedundantInboundIPAddress(addrToCheck net.Addr) bool {
   495  	cmgr.mtxPeerMaps.RLock()
   496  	defer cmgr.mtxPeerMaps.RUnlock()
   497  
   498  	// Loop through all the peers to see if any have the same IP
   499  	// address. This map is normally pretty small so doing this
   500  	// every time a Peer connects should be fine.
   501  	netAddr, err := IPToNetAddr(addrToCheck.String(), cmgr.addrMgr, cmgr.params)
   502  	if err != nil {
   503  		// Return true in case we have an error. We do this because it
   504  		// will result in the peer connection not being accepted, which
   505  		// is desired in this case.
   506  		glog.Warningf(errors.Wrapf(err,
   507  			"ConnectionManager._isFromRedundantInboundIPAddress: Problem parsing "+
   508  				"net.Addr to wire.NetAddress so marking as redundant and not "+
   509  				"making connection").Error())
   510  		return true
   511  	}
   512  	if netAddr == nil {
   513  		glog.Warningf("ConnectionManager._isFromRedundantInboundIPAddress: " +
   514  			"address was nil after parsing so marking as redundant and not " +
   515  			"making connection")
   516  		return true
   517  	}
   518  	// If the IP is a localhost IP let it slide. This is useful for testing fake
   519  	// nodes on a local machine.
   520  	// TODO: Should this be a flag?
   521  	if net.IP([]byte{127, 0, 0, 1}).Equal(netAddr.IP) {
   522  		glog.V(1).Infof("ConnectionManager._isFromRedundantInboundIPAddress: Allowing " +
   523  			"localhost IP address to connect")
   524  		return false
   525  	}
   526  	for _, peer := range cmgr.inboundPeers {
   527  		// If the peer's IP is equal to the passed IP then we have found a duplicate
   528  		// inbound connection
   529  		if peer.netAddr.IP.Equal(netAddr.IP) {
   530  			return true
   531  		}
   532  	}
   533  
   534  	// If we get here then no duplicate inbound IPs were found.
   535  	return false
   536  }
   537  
   538  func (cmgr *ConnectionManager) _handleInboundConnections() {
   539  	for _, outerListener := range cmgr.listeners {
   540  		go func(ll net.Listener) {
   541  			for {
   542  				conn, err := ll.Accept()
   543  				if atomic.LoadInt32(&cmgr.shutdown) != 0 {
   544  					glog.Info("_handleInboundConnections: Ignoring connection due to shutdown")
   545  					return
   546  				}
   547  				if err != nil {
   548  					glog.Errorf("_handleInboundConnections: Can't accept connection: %v", err)
   549  					continue
   550  				}
   551  
   552  				// As a quick check, reject the peer if we have too many already. Note that
   553  				// this check isn't perfect but we have a later check at the end after doing
   554  				// a version negotiation that will properly reject the peer if this check
   555  				// messes up e.g. due to a concurrency issue.
   556  				//
   557  				// TODO: We should instead have eviction logic here to prevent
   558  				// someone from monopolizing a node's inbound connections.
   559  				numInboundPeers := atomic.LoadUint32(&cmgr.numInboundPeers)
   560  				if numInboundPeers > cmgr.maxInboundPeers {
   561  
   562  					glog.Infof("Rejecting INBOUND peer (%s) due to max inbound peers (%d) hit.",
   563  						conn.RemoteAddr().String(), cmgr.maxInboundPeers)
   564  					conn.Close()
   565  
   566  					continue
   567  				}
   568  
   569  				// If we want to limit inbound connections to one per IP address, check to
   570  				// make sure this address isn't already connected.
   571  				if cmgr.limitOneInboundConnectionPerIP &&
   572  					cmgr._isFromRedundantInboundIPAddress(conn.RemoteAddr()) {
   573  
   574  					glog.Infof("Rejecting INBOUND peer (%s) due to already having an "+
   575  						"inbound connection from the same IP with "+
   576  						"limit_one_inbound_connection_per_ip set.",
   577  						conn.RemoteAddr().String())
   578  					conn.Close()
   579  
   580  					continue
   581  				}
   582  
   583  				go cmgr.ConnectPeer(conn, nil)
   584  			}
   585  		}(outerListener)
   586  	}
   587  }
   588  
   589  // GetAllPeers holds the mtxPeerMaps lock for reading and returns a list containing
   590  // pointers to all the active peers.
   591  func (cmgr *ConnectionManager) GetAllPeers() []*Peer {
   592  	cmgr.mtxPeerMaps.RLock()
   593  	defer cmgr.mtxPeerMaps.RUnlock()
   594  
   595  	allPeers := []*Peer{}
   596  	for _, pp := range cmgr.persistentPeers {
   597  		allPeers = append(allPeers, pp)
   598  	}
   599  	for _, pp := range cmgr.outboundPeers {
   600  		allPeers = append(allPeers, pp)
   601  	}
   602  	for _, pp := range cmgr.inboundPeers {
   603  		allPeers = append(allPeers, pp)
   604  	}
   605  
   606  	return allPeers
   607  }
   608  
   609  func (cmgr *ConnectionManager) RandomPeer() *Peer {
   610  	cmgr.mtxPeerMaps.RLock()
   611  	defer cmgr.mtxPeerMaps.RUnlock()
   612  
   613  	// Prefer persistent peers over all other peers.
   614  	if len(cmgr.persistentPeers) > 0 {
   615  		// Maps iterate randomly so this should be sufficient.
   616  		for _, pp := range cmgr.persistentPeers {
   617  			return pp
   618  		}
   619  	}
   620  
   621  	// Prefer outbound peers over inbound peers.
   622  	if len(cmgr.outboundPeers) > 0 {
   623  		// Maps iterate randomly so this should be sufficient.
   624  		for _, pp := range cmgr.outboundPeers {
   625  			return pp
   626  		}
   627  	}
   628  
   629  	// If we don't have any other type of peer, use an inbound peer.
   630  	if len(cmgr.inboundPeers) > 0 {
   631  		// Maps iterate randomly so this should be sufficient.
   632  		for _, pp := range cmgr.inboundPeers {
   633  			return pp
   634  		}
   635  	}
   636  
   637  	return nil
   638  }
   639  
   640  // Update our data structures to add this peer.
   641  func (cmgr *ConnectionManager) addPeer(pp *Peer) {
   642  	// Acquire the mtxPeerMaps lock for writing.
   643  	cmgr.mtxPeerMaps.Lock()
   644  	defer cmgr.mtxPeerMaps.Unlock()
   645  
   646  	// Figure out what list this peer belongs to.
   647  	var peerList map[uint64]*Peer
   648  	if pp.isPersistent {
   649  		peerList = cmgr.persistentPeers
   650  		atomic.AddUint32(&cmgr.numPersistentPeers, 1)
   651  	} else if pp.isOutbound {
   652  		peerList = cmgr.outboundPeers
   653  
   654  		// If this is a non-persistent outbound peer and if
   655  		// the peer was not previously in our data structures then
   656  		// increment the count for this IP group and increment the
   657  		// number of outbound peers. Also add the peer's address to
   658  		// our map.
   659  		if _, ok := peerList[pp.ID]; !ok {
   660  			cmgr.addToGroupKey(pp.netAddr)
   661  			atomic.AddUint32(&cmgr.numOutboundPeers, 1)
   662  
   663  			cmgr.mtxConnectedOutboundAddrs.Lock()
   664  			cmgr.connectedOutboundAddrs[addrmgr.NetAddressKey(pp.netAddr)] = true
   665  			cmgr.mtxConnectedOutboundAddrs.Unlock()
   666  		}
   667  	} else {
   668  		// This is an inbound peer.
   669  		atomic.AddUint32(&cmgr.numInboundPeers, 1)
   670  		peerList = cmgr.inboundPeers
   671  	}
   672  
   673  	peerList[pp.ID] = pp
   674  }
   675  
   676  // Update our data structures to remove this peer.
   677  func (cmgr *ConnectionManager) RemovePeer(pp *Peer) {
   678  	// Acquire the mtxPeerMaps lock for writing.
   679  	cmgr.mtxPeerMaps.Lock()
   680  	defer cmgr.mtxPeerMaps.Unlock()
   681  
   682  	// Figure out what list this peer belongs to.
   683  	var peerList map[uint64]*Peer
   684  	if pp.isPersistent {
   685  		peerList = cmgr.persistentPeers
   686  		atomic.AddUint32(&cmgr.numPersistentPeers, Uint32Dec)
   687  	} else if pp.isOutbound {
   688  		peerList = cmgr.outboundPeers
   689  
   690  		// If this is a non-persistent outbound peer and if
   691  		// the peer was previously in our data structures then
   692  		// decrement the outbound group count and the number of
   693  		// outbound peers.
   694  		if _, ok := peerList[pp.ID]; ok {
   695  			cmgr.subFromGroupKey(pp.netAddr)
   696  			atomic.AddUint32(&cmgr.numOutboundPeers, Uint32Dec)
   697  
   698  			cmgr.mtxConnectedOutboundAddrs.Lock()
   699  			delete(cmgr.connectedOutboundAddrs, addrmgr.NetAddressKey(pp.netAddr))
   700  			cmgr.mtxConnectedOutboundAddrs.Unlock()
   701  		}
   702  	} else {
   703  		// This is an inbound peer.
   704  		atomic.AddUint32(&cmgr.numInboundPeers, Uint32Dec)
   705  		peerList = cmgr.inboundPeers
   706  	}
   707  
   708  	// Update the last seen time before we finish removing the peer.
   709  	cmgr.addrMgr.Connected(pp.netAddr)
   710  
   711  	// Remove the peer from our data structure.
   712  	delete(peerList, pp.ID)
   713  }
   714  
   715  func (cmgr *ConnectionManager) _maybeReplacePeer(pp *Peer) {
   716  	// If the peer was outbound, replace her with a
   717  	// new peer to maintain a fixed number of outbound connections.
   718  	if pp.isOutbound {
   719  		// If the peer is not persistent then we don't want to pass an
   720  		// address to connectPeer. The lack of an address will cause it
   721  		// to choose random addresses from the addrmgr until one works.
   722  		na := pp.netAddr
   723  		if !pp.isPersistent {
   724  			na = nil
   725  		}
   726  		go cmgr.ConnectPeer(nil, na)
   727  	}
   728  }
   729  
   730  func (cmgr *ConnectionManager) _logOutboundPeerData() {
   731  	numOutboundPeers := int(atomic.LoadUint32(&cmgr.numOutboundPeers))
   732  	numInboundPeers := int(atomic.LoadUint32(&cmgr.numInboundPeers))
   733  	numPersistentPeers := int(atomic.LoadUint32(&cmgr.numPersistentPeers))
   734  	glog.V(1).Infof("Num peers: OUTBOUND(%d) INBOUND(%d) PERSISTENT(%d)", numOutboundPeers, numInboundPeers, numPersistentPeers)
   735  
   736  	cmgr.mtxOutboundConnIPGroups.Lock()
   737  	for _, vv := range cmgr.outboundConnIPGroups {
   738  		if vv != 0 && vv != 1 {
   739  			glog.V(1).Infof("_logOutboundPeerData: Peer group count != (0 or 1). "+
   740  				"Is (%d) instead. This "+
   741  				"should never happen.", vv)
   742  		}
   743  	}
   744  	cmgr.mtxOutboundConnIPGroups.Unlock()
   745  }
   746  
   747  func (cmgr *ConnectionManager) Stop() {
   748  	if atomic.AddInt32(&cmgr.shutdown, 1) != 1 {
   749  		glog.Warningf("ConnectionManager.Stop is already in the process of " +
   750  			"shutting down")
   751  		return
   752  	}
   753  	glog.Info("ConnectionManager.Stop: Gracefully shutting down ConnectionManager")
   754  
   755  	// Close all of the listeners.
   756  	for _, listener := range cmgr.listeners {
   757  		_ = listener.Close()
   758  	}
   759  }
   760  
   761  func (cmgr *ConnectionManager) Start() {
   762  	// Below is a basic description of the ConnectionManager's main loop:
   763  	//
   764  	// We have listeners (for inbound connections) and we have an addrmgr (for outbound connections).
   765  	// Specify TargetOutbound connections we want to have.
   766  	// Create TargetOutbound connection objects each with their own id.
   767  	// Add these connection objects to a map of some sort.
   768  	// Initiate TargetOutbound connections to peers using the addrmgr.
   769  	// When a connection fails, remove that connection from the map and try another connection in its place. Wait for that connection to return. Repeat.
   770  	// - If a connection has failed a few times then add a retryduration (since we're probably out of addresses).
   771  	// - If you can't connect to a node because the addrmgr returned nil, wait some amount of time and then try again.
   772  	// When a connection succeeds:
   773  	// - Send the peer a version message.
   774  	// - Read a version message from the peer.
   775  	// - Wait for the above two steps to return.
   776  	// - If the above steps don't return, then disconnect from the peer as above. Try to reconnect to another peer.
   777  	// If the steps above succeed
   778  	// - Have the peer enter a switch statement listening for all kinds of messages.
   779  	// - Send addr and getaddr messages as appropriate.
   780  
   781  	// Initiate outbound connections with peers either using the --connectips passed
   782  	// in or using the addrmgr.
   783  	cmgr._initiateOutboundConnections()
   784  
   785  	// Accept inbound connections from peers on our listeners.
   786  	cmgr._handleInboundConnections()
   787  
   788  	glog.Infof("Full node socket initialized")
   789  
   790  	for {
   791  		// Log some data for each event.
   792  		cmgr._logOutboundPeerData()
   793  
   794  		select {
   795  		case pp := <-cmgr.newPeerChan:
   796  			{
   797  				// We have successfully connected to a peer and it passed its version
   798  				// negotiation.
   799  
   800  				// if this is a non-persistent outbound peer and we already have enough
   801  				// outbound peers, then don't bother adding this one.
   802  				if !pp.isPersistent && pp.isOutbound && cmgr.enoughOutboundPeers() {
   803  					// TODO: Make this less verbose
   804  					glog.V(1).Infof("Dropping peer because we already have enough outbound peer connections.")
   805  					pp.conn.Close()
   806  					continue
   807  				}
   808  
   809  				// If this is a non-persistent outbound peer and the group key
   810  				// overlaps with another peer we're already connected to then
   811  				// abort mission. We only connect to one peer per IP group in
   812  				// order to prevent Sybil attacks.
   813  				if pp.isOutbound &&
   814  					!pp.isPersistent &&
   815  					cmgr.isRedundantGroupKey(pp.netAddr) {
   816  
   817  					// TODO: Make this less verbose
   818  					glog.Infof("Rejecting OUTBOUND NON-PERSISTENT peer (%v) with "+
   819  						"redundant group key (%s).",
   820  						pp, addrmgr.GroupKey(pp.netAddr))
   821  
   822  					pp.conn.Close()
   823  					cmgr._maybeReplacePeer(pp)
   824  					continue
   825  				}
   826  
   827  				// Check that we have not exceeded the maximum number of inbound
   828  				// peers allowed.
   829  				//
   830  				// TODO: We should instead have eviction logic to prevent
   831  				// someone from monopolizing a node's inbound connections.
   832  				numInboundPeers := atomic.LoadUint32(&cmgr.numInboundPeers)
   833  				if !pp.isOutbound && numInboundPeers > cmgr.maxInboundPeers {
   834  
   835  					// TODO: Make this less verbose
   836  					glog.Infof("Rejecting INBOUND peer (%v) due to max inbound peers (%d) hit.",
   837  						pp, cmgr.maxInboundPeers)
   838  
   839  					pp.conn.Close()
   840  					continue
   841  				}
   842  
   843  				// Now we can add the peer to our data structures.
   844  				pp._logAddPeer()
   845  				cmgr.addPeer(pp)
   846  
   847  				// Start the peer's message loop.
   848  				pp.Start()
   849  
   850  				// Signal the server about the new Peer in case it wants to do something with it.
   851  				cmgr.serverMessageQueue <- &ServerMessage{
   852  					Peer: pp,
   853  					Msg:  &MsgDeSoNewPeer{},
   854  				}
   855  
   856  			}
   857  		case pp := <-cmgr.donePeerChan:
   858  			{
   859  				// By the time we get here, it can be assumed that the Peer's Disconnect function
   860  				// has already been called, since that is what's responsible for adding the peer
   861  				// to this queue in the first place.
   862  
   863  				glog.V(1).Infof("Done with peer (%v).", pp)
   864  
   865  				if !pp.PeerManuallyRemovedFromConnectionManager {
   866  					// Remove the peer from our data structures.
   867  					cmgr.RemovePeer(pp)
   868  
   869  					// Potentially replace the peer. For example, if the Peer was an outbound Peer
   870  					// then we want to find a new peer in order to maintain our TargetOutboundPeers.
   871  					cmgr._maybeReplacePeer(pp)
   872  				}
   873  
   874  				// Signal the server about the Peer being done in case it wants to do something
   875  				// with it.
   876  				cmgr.serverMessageQueue <- &ServerMessage{
   877  					Peer: pp,
   878  					Msg:  &MsgDeSoDonePeer{},
   879  				}
   880  			}
   881  		}
   882  	}
   883  }