|
|
@ -1,6 +1,7 @@ |
|
|
|
package tor |
|
|
|
|
|
|
|
import ( |
|
|
|
"context" |
|
|
|
"crypto/rand" |
|
|
|
"encoding/base64" |
|
|
|
"errors" |
|
|
@ -15,13 +16,14 @@ import ( |
|
|
|
|
|
|
|
// BaseOnionService is a concrete implementation of the service interface over Tor onion services.
|
|
|
|
type BaseOnionService struct { |
|
|
|
connections sync.Map |
|
|
|
acn connectivity.ACN |
|
|
|
id *primitives.Identity |
|
|
|
privateKey ed25519.PrivateKey |
|
|
|
ls connectivity.ListenService |
|
|
|
lock sync.Mutex |
|
|
|
port int |
|
|
|
connections sync.Map |
|
|
|
acn connectivity.ACN |
|
|
|
id *primitives.Identity |
|
|
|
privateKey ed25519.PrivateKey |
|
|
|
ls connectivity.ListenService |
|
|
|
lock sync.Mutex |
|
|
|
port int |
|
|
|
shutdownChannel chan bool |
|
|
|
} |
|
|
|
|
|
|
|
// Metrics provides a report of useful information about the status of the service e.g. the number of active
|
|
|
@ -53,6 +55,25 @@ func (s *BaseOnionService) Init(acn connectivity.ACN, sk ed25519.PrivateKey, id |
|
|
|
s.id = id |
|
|
|
s.privateKey = sk |
|
|
|
s.port = 9878 |
|
|
|
// blocking so we can wait on shutdown for closing of this goroutine
|
|
|
|
s.shutdownChannel = make(chan bool) |
|
|
|
go func() { |
|
|
|
for s.waitOrTimeout() { |
|
|
|
s.GarbageCollect() |
|
|
|
} |
|
|
|
log.Debugf("closing down garbage collection goroutine") |
|
|
|
}() |
|
|
|
} |
|
|
|
|
|
|
|
func (s *BaseOnionService) waitOrTimeout() bool { |
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) |
|
|
|
defer cancel() |
|
|
|
select { |
|
|
|
case <-s.shutdownChannel: |
|
|
|
return false |
|
|
|
case <-ctx.Done(): |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// SetPort configures the port that the service uses.
|
|
|
@ -183,6 +204,20 @@ func (s *BaseOnionService) GetConnection(hostname string) (tapir.Connection, err |
|
|
|
return conn[0], nil |
|
|
|
} |
|
|
|
|
|
|
|
// GarbageCollect iterates through the connection pool and cleans up any connections that are closed
|
|
|
|
// that haven't been removed from the map.
|
|
|
|
func (s *BaseOnionService) GarbageCollect() { |
|
|
|
log.Debugf("running garbage collection...") |
|
|
|
s.connections.Range(func(key, value interface{}) bool { |
|
|
|
connection := value.(tapir.Connection) |
|
|
|
if connection.IsClosed() { |
|
|
|
// Delete this Closed Connection
|
|
|
|
s.connections.Delete(key) |
|
|
|
} |
|
|
|
return true |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// Connect initializes a new outbound connection to the given peer, using the defined Application
|
|
|
|
func (s *BaseOnionService) Connect(hostname string, app tapir.Application) (bool, error) { |
|
|
|
currconn, _ := s.GetConnection(hostname) |
|
|
@ -263,11 +298,16 @@ func (s *BaseOnionService) Shutdown() { |
|
|
|
if s.ls != nil { |
|
|
|
s.ls.Close() |
|
|
|
} |
|
|
|
|
|
|
|
// close all existing connections manually
|
|
|
|
s.connections.Range(func(key, value interface{}) bool { |
|
|
|
connection := value.(tapir.Connection) |
|
|
|
connection.Close() |
|
|
|
return true |
|
|
|
}) |
|
|
|
|
|
|
|
// wait for the return of our garbage collection goroutine
|
|
|
|
s.shutdownChannel <- true |
|
|
|
} |
|
|
|
|
|
|
|
// Broadcast sends a message to all connections who possess the given capability
|
|
|
|