commit 057637013e32ebf8db9e4b762077add45b4c92d7 Author: Damian Johnson atagar@torproject.org Date: Sat Jul 9 16:53:08 2011 -0700
Moving managed tor functions into helper
Putting the util functions for managing a wizard generated tor instance into a helper instance accessable from the controller. I'm also fixing a couple important bugs along the way:
- Race condition between arm and tor starting its control port, so half the time a managed tor instance reported that it couldn't connect to the control port. Now waiting for up to five seconds instead.
- If we're already connected to a managed instance then the wizard should modify that instance rather than starting an new one. --- src/cli/controller.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++-- src/cli/wizard.py | 17 ++++++----- 2 files changed, 79 insertions(+), 11 deletions(-)
diff --git a/src/cli/controller.py b/src/cli/controller.py index ae1a59b..5ba7f42 100644 --- a/src/cli/controller.py +++ b/src/cli/controller.py @@ -21,6 +21,8 @@ import cli.graphing.connStats import cli.graphing.resourceStats import cli.connections.connPanel
+from TorCtl import TorCtl + from util import connections, conf, enum, log, panel, sysTools, torConfig, torTools
ARM_CONTROLLER = None @@ -38,6 +40,7 @@ CONFIG = {"startup.events": "N3", "features.confirmQuit": True, "features.graph.type": 1, "features.graph.bw.prepopulate": True, + "wizard.default": {}, "log.startTime": log.INFO, "log.torEventTypeUnrecognized": log.NOTICE, "log.configEntryUndefined": log.NOTICE, @@ -167,6 +170,7 @@ class Controller: self._isPaused = False self._forceRedraw = False self._isDone = False + self._torManager = TorManager(self) self.setMsg() # initializes our control message
def getScreen(self): @@ -380,6 +384,13 @@ class Controller: if not os.path.exists(dataDir): os.makedirs(dataDir) return os.path.expanduser(dataDir)
+ def getTorManager(self): + """ + Provides management utils for an arm managed tor instance. + """ + + return self._torManager + def isDone(self): """ True if arm should be terminated, false otherwise. @@ -398,10 +409,8 @@ class Controller:
if CONFIG["features.offerTorShutdownOnQuit"]: conn = torTools.getConn() - torrcLoc = conn.getInfo("config-file") - wizardTorrcLoc = self.getDataDirectory() + "torrc"
- if torrcLoc == wizardTorrcLoc: + if self.getTorManager().isManaged(conn): while True: msg = "Shut down the Tor instance arm started (y/n)?" confirmationKey = cli.popups.showMsg(msg, attr = curses.A_BOLD) @@ -416,6 +425,64 @@ class Controller: elif confirmationKey in (ord('n'), ord('N')): break
+class TorManager: + """ + Bundle of utils for starting and manipulating an arm generated tor instance. + """ + + def __init__(self, controller): + self._controller = controller + + def getTorrcPath(self): + """ + Provides the path to a wizard generated torrc. + """ + + return self._controller.getDataDirectory() + "torrc" + + def isTorrcAvailable(self): + """ + True if a wizard generated torrc exists, false otherwise. + """ + + return os.path.exists(self.getTorrcPath()) + + def isManaged(self, conn): + """ + Returns true if the given tor instance is managed by us, false otherwise. + + Arguments: + conn - controller instance to be checked + """ + + return conn.getInfo("config-file") == self.getTorrcPath() + + def startManagedInstance(self): + """ + Starts a managed instance of tor, raising an IOError if unsuccessful. + """ + + os.system("tor --quiet -f %s&" % self.getTorrcPath()) + startTime = time.time() + + # attempts to connect for five seconds (tor might or might not be + # immediately available) + torctlConn, authType, authValue, raisedExc = None, None, None, None + while not torctlConn and time.time() - startTime < 5: + try: + torctlConn, authType, authValue = TorCtl.preauth_connect(controlPort = int(CONFIG["wizard.default"]["Control"])) + except IOError, exc: + raisedExc == exc + time.sleep(0.5) + + if not torctlConn: raise raisedExc + + if authType == TorCtl.AUTH_TYPE.COOKIE: + torctlConn.authenticate(authValue) + torTools.getConn().init(torctlConn) + else: + raise IOError("unexpected authentication type '%s'" % authType) + def shutdownDaemons(): """ Stops and joins on worker threads. diff --git a/src/cli/wizard.py b/src/cli/wizard.py index 7e0907e..8a5a138 100644 --- a/src/cli/wizard.py +++ b/src/cli/wizard.py @@ -254,6 +254,7 @@ def showWizard(): # remembers the last selection made on the type prompt page relaySelection = RelayType.RELAY controller = cli.controller.getController() + manager = controller.getTorManager()
while True: if relayType == None: @@ -268,7 +269,7 @@ def showWizard(): elif selection == NEXT: generatedTorrc = getTorrc(relayType, config)
- torrcLocation = controller.getDataDirectory() + "torrc" + torrcLocation = manager.getTorrcPath() controller.requestRedraw(True) confirmationSelection = showConfirmationDialog(generatedTorrc, torrcLocation)
@@ -285,14 +286,14 @@ def showWizard(): torrcFile.close()
try: - os.system("tor --quiet -f %s&" % torrcLocation) - torctlConn, authType, authValue = TorCtl.preauth_connect(controlPort = int(CONFIG["wizard.default"][Options.CONTROL])) + conn = torTools.getConn()
- if authType == TorCtl.AUTH_TYPE.COOKIE: - torctlConn.authenticate(authValue) - torTools.getConn().init(torctlConn) - else: - raise IOError("unexpected authentication type '%s'" % authType) + # If we're connected to a managed instance then just need to + # issue a sighup to pick up the new settings. Otherwise starts + # a new tor instance. + + if manager.isManaged(conn): conn.reset() + else: manager.startManagedInstance() except IOError, exc: log.log(log.WARN, "Unable to start tor: %s" % exc)
tor-commits@lists.torproject.org