Merge pull request 'Actively Deduplicate Connections on WaitForCapabilityOrClose' (#40) from dedupe into master
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone/push Build is failing Details

Reviewed-on: #40
This commit is contained in:
Dan Ballard 2021-09-08 20:36:38 +00:00
commit 0845156bea
1 changed files with 26 additions and 7 deletions

View File

@ -10,7 +10,6 @@ import (
"git.openprivacy.ca/openprivacy/log"
"golang.org/x/crypto/ed25519"
"sync"
"time"
)
// BaseOnionService is a concrete implementation of the service interface over Tor onion services.
@ -66,16 +65,36 @@ func (s *BaseOnionService) WaitForCapabilityOrClose(cid string, name tapir.Capab
conn, err := s.GetConnection(cid)
// If there is at least one active connection, then check the one that is returned and use it
for conn != nil {
if conn.HasCapability(name) {
// if we have only one and it has the right capability then return
if conn.HasCapability(name) && err == nil {
return conn, nil
}
time.Sleep(time.Millisecond * 200)
// If we received both a Connection and an Error from GetConnection that means we have multiple connections
// If that was the case we refresh from the connection store as the likely case is one of them has been
// closed and the other one has the capabilities we need.
// If We have 2 connections for the same hostname...
if err != nil {
conn, err = s.GetConnection(cid)
log.Debugf("found duplicate connections for %v <-> %v", s.id.Hostname(), cid)
// By convention the lowest lexicographical hostname purges all their outbounds to the higher
// hostname
// Which should only leave a single connection remaining (as we dedupe on connect too)
// This does allow people to attempt to guarantee being the outbound connection but due to the bidirectional
// authentication this should never result in an advantage in the protocol.
if s.id.Hostname() < cid {
// Close all output connections to connection
s.connections.Range(func(key, value interface{}) bool {
connection := value.(tapir.Connection)
if connection.Hostname() == cid {
if !connection.IsClosed() && connection.IsOutbound() {
connection.Close()
}
}
return true
})
}
}
// We had a connection but it didn't have a cpability...try again
conn, err = s.GetConnection(cid)
}
// There are no active connections with that hostname
return nil, err