torProvider now also consults network-liveness
This commit is contained in:
parent
beb2665c49
commit
35293ea087
4
acn.go
4
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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue