[tor-commits] [arm/release] Moving managed tor functions into helper

atagar at torproject.org atagar at torproject.org
Sun Jul 17 06:08:31 UTC 2011


commit 057637013e32ebf8db9e4b762077add45b4c92d7
Author: Damian Johnson <atagar at 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)
           





More information about the tor-commits mailing list