From 35293ea0871bfe0c6a80c1aeabb2a356d986b7d3 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 8 May 2020 11:52:26 -0700 Subject: [PATCH] torProvider now also consults network-liveness --- acn.go | 4 +- quality.sh | 0 tests.sh | 0 tor/torProvider.go | 113 +++++++++++++++++++++++++++++++-------------- tor/torUtils.go | 2 +- 5 files changed, 83 insertions(+), 36 deletions(-) mode change 100644 => 100755 quality.sh mode change 100644 => 100755 tests.sh diff --git a/acn.go b/acn.go index 4cbc45a..ab64a64 100644 --- a/acn.go +++ b/acn.go @@ -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 diff --git a/quality.sh b/quality.sh old mode 100644 new mode 100755 diff --git a/tests.sh b/tests.sh old mode 100644 new mode 100755 diff --git a/tor/torProvider.go b/tor/torProvider.go index 2541f9a..ead21ca 100644 --- a/tor/torProvider.go +++ b/tor/torProvider.go @@ -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 diff --git a/tor/torUtils.go b/tor/torUtils.go index 5a4ac32..2da1ec1 100644 --- a/tor/torUtils.go +++ b/tor/torUtils.go @@ -48,4 +48,4 @@ func IsValidHostname(address string) bool { } } return false -} \ No newline at end of file +}