commit 3b803423be0f7a3edb09999c1b7c99b615facc1d Author: Damian Johnson atagar@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
tor-commits@lists.torproject.org