torProvider now also consults network-liveness

This commit is contained in:
Dan Ballard 2020-05-08 11:52:26 -07:00
parent beb2665c49
commit 35293ea087
5 changed files with 83 additions and 36 deletions

4
acn.go
View File

@ -34,10 +34,12 @@ type ListenService interface {
// ACN is Anonymous Communication Network implementation wrapper that supports Open for new connections and Listen to accept connections
type ACN interface {
// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
// On Network down it returns -1
// On ACN error state it returns -2
GetBootstrapStatus() (int, string)
// WaitTillBootstrapped Blocks until underlying network is bootstrapped
WaitTillBootstrapped()
// Sets the calback function to be called when ACN status changes
// Sets the callback function to be called when ACN status changes
SetStatusCallback(callback func(int, string))
// Restarts the underlying connection

0
quality.sh Normal file → Executable file
View File

0
tests.sh Normal file → Executable file
View File

View File

@ -26,6 +26,7 @@ import (
const (
minStatusIntervalMs = 200
maxStatusIntervalMs = 2000
restartCooldown = time.Second * 30
)
const (
@ -33,6 +34,12 @@ const (
CannotDialRicochetAddressError = connectivity.Error("CannotDialRicochetAddressError")
)
const (
networkUnknown int = iota
networkDown
networkUp
)
type onionListenService struct {
os *tor.OnionService
tp *torProvider
@ -47,6 +54,7 @@ type torProvider struct {
breakChan chan bool
childListeners map[string]*onionListenService
statusCallback func(int, string)
lastRestartTime time.Time
}
func (ols *onionListenService) AddressFull() string {
@ -66,14 +74,22 @@ func (ols *onionListenService) Close() {
ols.os.Close()
}
// GetBootstrapStatus returns an int -1 on error or 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
// returns -1 on network disconnected
// returns -2 on error
func (tp *torProvider) GetBootstrapStatus() (int, string) {
if tp.t == nil {
return -1, "error: no tor, trying to restart..."
return -2, "error: no tor, trying to restart..."
}
netStatus := tp.getNetworkStatus()
if netStatus == networkDown {
return -1, "Network Down"
}
kvs, err := tp.t.Control.GetInfo("status/bootstrap-phase")
if err != nil {
return -1, "error"
return -2, "error querrying status/bootstrap-phase"
}
progress := 0
status := ""
@ -104,6 +120,21 @@ func (tp *torProvider) WaitTillBootstrapped() {
}
}
// getNetworkStatus returns tor's beleif in the underlying network's status
func (tp *torProvider) getNetworkStatus() int {
if tp.t == nil {
return networkDown
}
val, err := tp.t.Control.GetInfo("network-liveness")
if err != nil {
return networkDown
}
if val[0].Val == "up" {
return networkUp
}
return networkDown
}
func (tp *torProvider) Listen(identity connectivity.PrivateKey, port int) (connectivity.ListenService, error) {
var onion = ""
var privkey ed25519.PrivateKey
@ -154,9 +185,7 @@ func (tp *torProvider) Listen(identity connectivity.PrivateKey, port int) (conne
}
func (tp *torProvider) Restart() {
if tp.statusCallback != nil {
tp.statusCallback(0, "rebooting")
}
tp.callStatusCallback(0, "rebooting")
tp.restart()
}
@ -199,6 +228,14 @@ func (tp *torProvider) SetStatusCallback(callback func(int, string)) {
tp.statusCallback = callback
}
func (tp *torProvider) callStatusCallback(prog int, status string) {
tp.lock.Lock()
if tp.statusCallback != nil {
tp.statusCallback(prog, status)
}
tp.lock.Unlock()
}
// NewTorACN creates/starts a Tor ACN and returns a usable ACN object
func NewTorACN(appDirectory string, bundledTorPath string) (connectivity.ACN, error) {
tp, err := startTor(appDirectory, bundledTorPath)
@ -225,7 +262,7 @@ func newHideCmd(exePath string) process.Creator {
func startTor(appDirectory string, bundledTorPath string) (*torProvider, error) {
dataDir := path.Join(appDirectory, "tor")
os.MkdirAll(dataDir, 0700)
tp := &torProvider{appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool), statusCallback: nil}
tp := &torProvider{appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool), statusCallback: nil, lastRestartTime: time.Now()}
// attempt connect to system tor
log.Debugf("dialing system tor control port\n")
@ -277,34 +314,38 @@ func (tp *torProvider) unregisterListener(id string) {
func (tp *torProvider) monitorRestart() {
lastBootstrapProgress := 0
lastNetworkStatus := networkUnknown
interval := minStatusIntervalMs
for {
select {
case <-time.After(time.Millisecond * time.Duration(interval)):
prog, status := tp.GetBootstrapStatus()
if prog == -1 && tp.t != nil {
tp.lock.Lock()
if tp.statusCallback != nil {
tp.statusCallback(prog, status)
}
tp.lock.Unlock()
tp.restart()
interval = minStatusIntervalMs
} else if prog != lastBootstrapProgress {
tp.lock.Lock()
if tp.statusCallback != nil {
tp.statusCallback(prog, status)
}
tp.lock.Unlock()
interval = minStatusIntervalMs
} else {
if interval < maxStatusIntervalMs {
interval *= 2
}
if interval < maxStatusIntervalMs {
interval *= 2
}
lastBootstrapProgress = prog
netStatus := tp.getNetworkStatus()
if netStatus == networkDown {
if lastNetworkStatus != netStatus {
tp.callStatusCallback(-1, "Network Down")
}
lastBootstrapProgress = 0
lastNetworkStatus = netStatus
} else {
lastNetworkStatus = networkUp
prog, status := tp.GetBootstrapStatus()
if prog == -1 && tp.t != nil {
tp.callStatusCallback(-2, status)
log.Infof("monitorRestart calling tp.restart() with prog:%v\n", prog)
tp.restart()
interval = minStatusIntervalMs
} else if prog != lastBootstrapProgress {
tp.callStatusCallback(prog, status)
interval = minStatusIntervalMs
}
lastBootstrapProgress = prog
}
case <-tp.breakChan:
return
}
@ -312,13 +353,17 @@ func (tp *torProvider) monitorRestart() {
}
func (tp *torProvider) restart() {
for _, child := range tp.childListeners {
child.Close()
}
tp.lock.Lock()
defer tp.lock.Unlock()
if time.Now().Sub(tp.lastRestartTime) < restartCooldown {
return
}
tp.lastRestartTime = time.Now()
for _, child := range tp.childListeners {
delete(tp.childListeners, child.AddressIdentity())
child.os.Close()
}
tp.t.Close()
tp.t = nil

View File

@ -48,4 +48,4 @@ func IsValidHostname(address string) bool {
}
}
return false
}
}