[tor-commits] [arm/release] Batch SETCONF and SET/RESETCONF in the interpretor

atagar at torproject.org atagar at torproject.org
Sun Sep 25 21:38:29 UTC 2011


commit 3b803423be0f7a3edb09999c1b7c99b615facc1d
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Sep 17 16:14:39 2011 -0700

    Batch SETCONF and SET/RESETCONF in the interpretor
    
    Supporting a batch SETCONF or RESETCONF in torTools, and better handling those
    inputs in the interpretor.
---
 src/util/torInterpretor.py |   43 ++++++++++++++++++++++++-------
 src/util/torTools.py       |   60 +++++++++++++++++++++++++++++++------------
 2 files changed, 76 insertions(+), 27 deletions(-)

diff --git a/src/util/torInterpretor.py b/src/util/torInterpretor.py
index 71080c9..1cc66bd 100644
--- a/src/util/torInterpretor.py
+++ b/src/util/torInterpretor.py
@@ -75,7 +75,7 @@ Tor commands include:
   RESOLVE - issues an asynchronous dns or rdns request over tor
   TAKEOWNERSHIP - instructs tor to quit when this control connection is closed
   PROTOCOLINFO - queries version and controller authentication information
-  QUIT - disconnect control connection
+  QUIT - disconnect the control connection
 
 For more information use '/help [OPTION]'."""
 
@@ -647,16 +647,39 @@ class ControlInterpretor:
         except Exception, exc:
           outputEntry.append((str(exc), ERROR_FORMAT))
       elif cmd == "SETCONF":
-        if "=" in arg:
-          param, value = arg.split("=", 1)
+        # arguments can either be '<param>' or '<param>="<value>"' entries
+        paramList = []
+        
+        while arg:
+          # TODO: I'm a little dubious of this for LineList values (like the
+          # ExitPolicy) since they're parsed as a single value. However, tor
+          # seems to be happy to get a single comma separated string (though it
+          # echos back faithfully rather than being parsed) so leaving this
+          # alone for now.
           
-          try:
-            conn.setOption(param.strip(), value.strip())
-          except Exception, exc:
-            outputEntry.append((str(exc), ERROR_FORMAT))
-        else:
-          # TODO: resets the attribute
-          outputEntry.append(("Not yet implemented...", ERROR_FORMAT)) # TODO: implement
+          m = re.match(r'^(\S+)=\"([^"]+)\"', arg)
+          
+          if m:
+            # we're dealing with a '<param>="<value>"' entry
+            param, value = m.groups()
+            
+            paramList.append((param, value))
+            arg = arg[len(param) + len(value) + 3:].strip()
+          else:
+            # starts with just a param
+            param = arg.split()[0]
+            paramList.append((param, None))
+            arg = arg[len(param):].strip()
+        
+        try:
+          conn.setOptions(paramList)
+        except Exception, exc:
+          outputEntry.append((str(exc), ERROR_FORMAT))
+      elif cmd == "RESETCONF":
+        try:
+          conn.setOptions([(param, None) for param in arg.split()])
+        except Exception, exc:
+          outputEntry.append((str(exc), ERROR_FORMAT))
       else:
         try:
           response = conn.getTorCtl().sendAndRecv("%s\r\n" % input)
diff --git a/src/util/torTools.py b/src/util/torTools.py
index b9d9ac8..fcd8247 100644
--- a/src/util/torTools.py
+++ b/src/util/torTools.py
@@ -725,10 +725,11 @@ class Controller(TorCtl.PostEventListener):
     elif result == []: return default
     else: return result
   
-  def setOption(self, param, value):
+  def setOption(self, param, value = None):
     """
     Issues a SETCONF to set the given option/value pair. An exeptions raised
-    if it fails to be set.
+    if it fails to be set. If no value is provided then this resets the
+    configuration option.
     
     Arguments:
       param - configuration option to be set
@@ -736,27 +737,53 @@ class Controller(TorCtl.PostEventListener):
               list of strings)
     """
     
-    isMultiple = isinstance(value, list) or isinstance(value, tuple)
+    self.setOptions(((param, value),))
+  
+  def setOptions(self, paramList):
+    """
+    Issues a SETCONF to replace a set of configuration options. This takes a
+    list of parameter/new value tuple pairs. Values can be...
+    - a string to set a single value
+    - a list of strings to set a series of values (for instance the ExitPolicy)
+    - None to reset the parameter
+    
+    Arguments:
+      paramList - list of parameter/value tuple pairs
+    """
+    
     self.connLock.acquire()
     
+    # constructs the SETCONF string
+    setConfComp = []
+    
+    for param, value in paramList:
+      if isinstance(value, list) or isinstance(value, tuple):
+        setConfComp += ["%s=\"%s\"" % (param, val.strip()) for val in value]
+      elif value:
+        setConfComp.append("%s=\"%s\"" % (param, value.strip()))
+      else:
+        setConfComp.append(param)
+    
+    setConfStr = " ".join(setConfComp)
+    
     startTime, raisedExc = time.time(), None
     if self.isAlive():
       try:
-        if isMultiple: self.conn.set_options([(param, val) for val in value])
-        else: self.conn.set_option(param, value)
+        self.conn.sendAndRecv("SETCONF %s\r\n" % setConfStr)
         
         # flushing cached values (needed until we can detect SETCONF calls)
-        for fetchType in ("str", "list", "map"):
-          entry = (param.lower(), fetchType)
+        for param, _ in paramList:
+          for fetchType in ("str", "list", "map"):
+            entry = (param.lower(), fetchType)
+            
+            if entry in self._cachedConf:
+              del self._cachedConf[entry]
           
-          if entry in self._cachedConf:
-            del self._cachedConf[entry]
-        
-        # special caches for the exit policy
-        if param.lower() == "exitpolicy":
-          self._exitPolicyChecker = self.getExitPolicy()
-          self._isExitingAllowed = self._exitPolicyChecker.isExitingAllowed()
-          self._exitPolicyLookupCache = {}
+          # special caches for the exit policy
+          if param.lower() == "exitpolicy":
+            self._exitPolicyChecker = self.getExitPolicy()
+            self._isExitingAllowed = self._exitPolicyChecker.isExitingAllowed()
+            self._exitPolicyLookupCache = {}
       except (socket.error, TorCtl.ErrorReply, TorCtl.TorCtlClosed), exc:
         if type(exc) == TorCtl.TorCtlClosed: self.close()
         elif type(exc) == TorCtl.ErrorReply:
@@ -777,9 +804,8 @@ class Controller(TorCtl.PostEventListener):
     
     self.connLock.release()
     
-    setCall = "%s %s" % (param, ", ".join(value) if isMultiple else value)
     excLabel = "failed: \"%s\", " % raisedExc if raisedExc else ""
-    msg = "SETCONF %s (%sruntime: %0.4f)" % (setCall.strip(), excLabel, time.time() - startTime)
+    msg = "SETCONF %s (%sruntime: %0.4f)" % (setConfStr, excLabel, time.time() - startTime)
     log.log(CONFIG["log.torSetConf"], msg)
     
     if raisedExc: raise raisedExc





More information about the tor-commits mailing list