kaspad/connmanager/connection_requests.go
Svarog b42b8b16fd
[NOD-1120] Connection Manager (#796)
* [NOD-1120] Removed closure in NetAdapter.onConnectedHanlder

* [NOD-1120] Implement all connection manager methods

* [NOD-1120] Integrated connmanager into kaspad + added call for dnsseeder

* [NOD-1120] Allow buffer to not be bytes.Buffer

* [NOD-1120] Added timeout to connect

* [NOD-1120] Don't enter connections to  add loop if none needed

* [NOD-1120] Add call for addressManager.Good

* [NOD-1120] Minor bug fixes

* [NOD-1120] Remove errChan from grpcConnection

* [NOD-1120] Add comments to exported methods

* [NOD-1120] cancel the context for DialContext in gRPCServer.Connect

* [NOD-1120] Don't try to remove from connSet a connection that doesn't exist

* [NOD-1120] add ok bool to connectionSet.get

* [NOD-1120] Remove overuse of if-else in checkConnectionRequests

* [NOD-1120] Made some order in ConnectionManager

* [NOD-1120] Moved checkIncomingConnections to it's own file

* [NOD-1120] cleanup in checkOutgoingConnections

* [NOD-1120] Cleanup in SeedDNS, and move call outside of connection manager

* [NOD-1120] Add check that both --connect and --addpeer aren't used

* [NOD-1120] Move dial timeout to constant

* [NOD-1120] Enhance comment

* [NOD-1120] Log connection failure out of initiateConnection

* [NOD-1148] Reshuffle checkRequestedConnections to make more sense

* [NOD-1120] Move continue to correct place + reshuffle logging code

* [NOD-1120] Don't expose server.Connection outside netAdapter - expose a wrapper instead

* [NOD-1120] Add comments

* [NOD-1120] Don't return the connection from netAdapter.Connect()

* [NOD-1120] Use .Address as key for connectionSet

* [NOD-1120] Fix minRetryDuration usage

* [NOD-1120] Remove the correct number of incoming connections

* [NOD-1120] Add comment

* [NOD-1120] Rename connSet -> incomingConnectionSet

* [NOD-1120] fix grammar
2020-07-16 17:15:58 +03:00

105 lines
3.1 KiB
Go

package connmanager
import (
"time"
)
const (
minRetryDuration = 30 * time.Second
maxRetryDuration = 10 * time.Minute
)
func nextRetryDuration(previousDuration time.Duration) time.Duration {
if previousDuration < minRetryDuration {
return minRetryDuration
}
if previousDuration*2 > maxRetryDuration {
return maxRetryDuration
}
return previousDuration * 2
}
// checkRequestedConnections checks that all activeRequested are still active, and initiates connections
// for pendingRequested.
// While doing so, it filters out of connSet all connections that were initiated as a connectionRequest
func (c *ConnectionManager) checkRequestedConnections(connSet connectionSet) {
c.connectionRequestsLock.Lock()
defer c.connectionRequestsLock.Unlock()
now := time.Now()
for address, connReq := range c.activeRequested {
connection, ok := connSet.get(address)
if !ok { // a requested connection was disconnected
delete(c.activeRequested, address)
if connReq.isPermanent { // if is one-try - ignore. If permanent - add to pending list to retry
connReq.nextAttempt = now
connReq.retryDuration = 0
c.pendingRequested[address] = connReq
}
continue
}
connSet.remove(connection)
}
for address, connReq := range c.pendingRequested {
if connReq.nextAttempt.After(now) { // ignore connection requests which are still waiting for retry
continue
}
connection, ok := connSet.get(address)
// The pending connection request has already connected - move it to active
// This can happen in rare cases such as when the other side has connected to our node
// while it has been pending on our side.
if ok {
delete(c.pendingRequested, address)
c.pendingRequested[address] = connReq
connSet.remove(connection)
continue
}
// try to initiate connection
err := c.initiateConnection(connReq.address)
if err != nil {
log.Infof("Couldn't connect to %s: %s", address, err)
// if connection request is one try - remove from pending and ignore failure
if !connReq.isPermanent {
delete(c.pendingRequested, address)
continue
}
// if connection request is permanent - keep in pending, and increase retry time
connReq.retryDuration = nextRetryDuration(connReq.retryDuration)
connReq.nextAttempt = now.Add(connReq.retryDuration)
log.Debugf("Retrying permanent connection to %s in %s", address, connReq.retryDuration)
continue
}
// if connected successfully - move from pending to active
delete(c.pendingRequested, address)
c.activeRequested[address] = connReq
}
}
// AddConnectionRequest adds the given address to list of pending connection requests
func (c *ConnectionManager) AddConnectionRequest(address string, isPermanent bool) {
// spawn goroutine so that caller doesn't wait in case connectionManager is in the midst of handling
// connection requests
spawn(func() {
c.connectionRequestsLock.Lock()
defer c.connectionRequestsLock.Unlock()
if _, ok := c.activeRequested[address]; ok {
return
}
c.pendingRequested[address] = &connectionRequest{
address: address,
isPermanent: isPermanent,
}
})
}