commit 70a3d94b5f5edeaafbd1867c67fb5cd2d61ad149 Author: Arturo Filastò arturo@filasto.net Date: Wed Nov 7 21:36:06 2012 +0100
Move peculiar code to wtf directory. * Comment on tor related code and propose that it gets removed. --- ooni/utils/config.py | 121 ------------------------------------------------- ooni/utils/onion.py | 17 +++++++- ooni/utils/process.py | 73 ----------------------------- wtf/README | 9 ++++ wtf/config.py | 66 +++++++++++++++++++++++++++ wtf/process.py | 73 +++++++++++++++++++++++++++++ 6 files changed, 164 insertions(+), 195 deletions(-)
diff --git a/ooni/utils/config.py b/ooni/utils/config.py deleted file mode 100644 index 5a0782d..0000000 --- a/ooni/utils/config.py +++ /dev/null @@ -1,121 +0,0 @@ -import ConfigParser -import os - -from ooni.utils import Storage, log - -class Config(Storage): - """ - A Storage-like class which loads and store each attribute into a portable - conf file. - """ - def __init__(self, section, cfgfile="ooni-probe.conf"): - super(Config, self).__init__() - - self._cfgfile = cfgfile - # setting up confgiparser - self._cfgparser = ConfigParser.ConfigParser() - self._cfgparser.read([self._cfgfile]) - self._section = section - - def __getattr__(self, name): - if name.startswith('_'): - return self.__dict__.get(name, None) - - try: - value = self._cfgparser.get(self._section, name) - if value.isdigit(): - return int(value) - elif value.lower() in ('true', 'false'): - return value.lower() == 'true' - else: - return value - except ConfigParser.NoOptionError: - return '' # if option doesn't exists return an empty string - - def __setattr__(self, name, value): - # keep an open port with private attributes - if name.startswith('_'): - self.__dict__[name] = value - return - - try: - # XXX: Automagically discover variable type - self._cfgparser.set(self._section, name, value) - except ConfigParser.NoOptionError: - raise NameError(name) - - def commit(self): - """ - Commit changes in config file. - """ - cfgfile = open(self._cfgfile, 'w') - try: - self._cfgparser.write(cfgfile) - finally: - cfgfile.close() - -class ValueChecker(object): - """ - A class for general purpose value checks on commandline parameters - passed to subclasses of :class:`twisted.python.usage.Options`. - """ - def __init__(self, coerce_doc=None): - self.coerce_doc = coerce_doc - - def port_check(self, port, range_min=1024, range_max=65535): - """ - Check that given ports are in the allowed range for an unprivileged - user. - - :param port: - The port to check. - :param range_min: - The minimum allowable port number. - :param range_max: - The minimum allowable port number. - :param coerce_doc: - The documentation string to show in the optParameters menu, see - :class:`twisted.python.usage.Options`. - """ - if self.coerce_doc is not None: - coerceDoc = self.coerce_doc - - assert type(port) is int - if port not in range(range_min, range_max): - raise ValueError("Port out of range") - log.err() - - @staticmethod - def uid_check(error_message): - """ - Check that we're not root. If we are, setuid(1000) to normal user if - we're running on a posix-based system, and if we're on Windows just - tell the user that we can't be run as root with the specified options - and then exit. - - :param error_message: - The string to log as an error message when the uid check fails. - """ - uid, gid = os.getuid(), os.getgid() - if uid == 0 and gid == 0: - log.msg(error_message) - if os.name == 'posix': - log.msg("Dropping privileges to normal user...") - os.setgid(1000) - os.setuid(1000) - else: - sys.exit(0) - - @staticmethod - def dir_check(d): - """Check that the given directory exists.""" - if not os.path.isdir(d): - raise ValueError("%s doesn't exist, or has wrong permissions" - % d) - - @staticmethod - def file_check(f): - """Check that the given file exists.""" - if not os.path.isfile(f): - raise ValueError("%s does not exist, or has wrong permissions" - % f) diff --git a/ooni/utils/onion.py b/ooni/utils/onion.py index fe97ca3..58b4c02 100644 --- a/ooni/utils/onion.py +++ b/ooni/utils/onion.py @@ -26,7 +26,10 @@ from txtorcon import TorState, TorConfig from ooni.utils import log from ooni.utils.timer import deferred_timeout, TimeoutError
- +# XXX This can be refactored to os.path.abspath +# os.path.abspath(path) +# Return a normalized absolutized version of the pathname path. On most +# platforms, this is equivalent to normpath(join(os.getcwd(), path)). def parse_data_dir(data_dir): """ Parse a string that a has been given as a DataDirectory and determine @@ -63,6 +66,9 @@ def parse_data_dir(data_dir): else: return data_dir
+# XXX txtorcon handles this already. +# Also this function is called write_torrc but it has hardcoded inside of it +# bridget-tordata. def write_torrc(conf, data_dir=None): """ Create a torrc in our data_dir. If we don't yet have a data_dir, create a @@ -157,6 +163,8 @@ def remove_public_relays(state, bridges): log.err("Removing public relays %s from bridge list failed:\n%s" % (both, e))
+# XXX It is unclear to me how all of these functions would be reused. Why must +# hey be inside of a module? def setup_done(proto): log.msg("Setup Complete") state = TorState(proto.tor_protocol) @@ -192,6 +200,7 @@ def bootstrap(ctrl): conf.post_bootstrap.addCallback(setup_done).addErrback(setup_fail) log.msg("Tor process connected, bootstrapping ...")
+# XXX txtorcon does this already for us. def start_tor(reactor, config, control_port, tor_binary, data_dir, report=None, progress=updates, process_cb=None, process_eb=None): @@ -315,6 +324,7 @@ def start_tor_filter_nodes(reactor, config, control_port, tor_binary, filter_nodes = yield remove_public_relays(setup, bridges) defer.returnValue(filter_nodes)
+# XXX Why is this needed? @defer.inlineCallbacks def start_tor_with_timer(reactor, config, control_port, tor_binary, data_dir, bridges, timeout): @@ -366,6 +376,7 @@ def start_tor_with_timer(reactor, config, control_port, tor_binary, data_dir, state = yield remove_public_relays(setup, bridges) defer.returnValue(state)
+# XXX This is a copy and paste of the above class with just an extra argument. @defer.inlineCallbacks def start_tor_filter_nodes_with_timer(reactor, config, control_port, tor_binary, data_dir, bridges, timeout): @@ -431,6 +442,10 @@ class CustomCircuit(CircuitListenerMixin): The list of circuits which we are waiting to attach to. You shouldn't need to touch this. """ + # XXX + # 14:57 < meejah> to build a custom circuit (with no streams) in txtorcon, + # call TorState.build_circuit -- the Deferred callbacks with the circid + implements(IStreamAttacher)
def __init__(self, state, relays=None): diff --git a/ooni/utils/process.py b/ooni/utils/process.py deleted file mode 100644 index 25d6368..0000000 --- a/ooni/utils/process.py +++ /dev/null @@ -1,73 +0,0 @@ -# -# process.py -# ---------- -# OONI utilities for dealing with starting and stopping processes. -# -# :author: Isis Lovecruft -# :version: 0.1.0-pre-alpha -# :license: see include LICENSE file -# :copyright: copyright (c) 2012, Isis Lovecruft, The Tor Project Inc. -# - -from twisted.internet import defer - -@defer.inlineCallbacks -def singleton_semaphore(deferred_process_init, - callbacks=[], errbacks=[], - max_inits=1): - """ - Initialize a process only once, and do not return until - that initialization is complete. If the keyword parameter max_inits= - is given, run the process a maximum of that number of times. - - :param deferred_process_init: - A deferred which returns a connected process via - :meth:`twisted.internet.reactor.spawnProcess`. - :param callbacks: - A list of callback functions to add to the initialized processes' - deferred. - :param errbacks: - A list of errback functions to add to the initialized processes' - deferred. - :param max_inits: - An integer specifying the maximum number of allowed - initializations for :param:deferred_process_init. If no maximum - is given, only one instance (a singleton) of the process is - initialized. - :return: - The final state of the :param deferred_process_init: after the - callback chain has completed. This should be a fully initialized - process connected to a :class:`twisted.internet.reactor`. - """ - assert isinstance(callbacks, list) - assert isinstance(errbacks, list) - assert isinstance(max_inits, int) - - for cb in callbacks: - deferred_process_init.addCallback(cb) - for eb in errbacks: - deferred_process_init.addErrback(eb) - - only_this_many = defer.DeferredSemaphore(max_inits) - singleton = yield only_this_many.run(deferred_process_init) - defer.returnValue(singleton) - -class Singleton(object): - """ - Generic Class for creating Singleton subclasses. - - Subclass me to create a singleton class, which will only ever have one - instance, regardless of how many times the subclass constructor is called. - - Any subclass of me should override ``init`` rather than ``__init__``, - because the latter is called whenever the constructor is called. - """ - def __new__(cls, *args, **kwds): - it = cls.__dict__.get("__it__") - if it is not None: - return it - cls.__it__ = it = object.__new__(cls) - it.init(*args, **kwds) - return it - def init(self, *args, **kwds): - pass diff --git a/wtf/README b/wtf/README new file mode 100644 index 0000000..7696130 --- /dev/null +++ b/wtf/README @@ -0,0 +1,9 @@ +I have moved here all the pieces of code that are either not being used +anywhere or that should probably not be part of OONIProbe. + +They are very neat pieces of code, though I have not tester their +functionality, since there are no examples of how they should be called or +used in the repo. + +I believe they should go on a separate branch or on another repo called +something like "python class kung foo". diff --git a/wtf/config.py b/wtf/config.py new file mode 100644 index 0000000..25f9576 --- /dev/null +++ b/wtf/config.py @@ -0,0 +1,66 @@ +class ValueChecker(object): + """ + A class for general purpose value checks on commandline parameters + passed to subclasses of :class:`twisted.python.usage.Options`. + """ + def __init__(self, coerce_doc=None): + self.coerce_doc = coerce_doc + + def port_check(self, port, range_min=1024, range_max=65535): + """ + Check that given ports are in the allowed range for an unprivileged + user. + + :param port: + The port to check. + :param range_min: + The minimum allowable port number. + :param range_max: + The minimum allowable port number. + :param coerce_doc: + The documentation string to show in the optParameters menu, see + :class:`twisted.python.usage.Options`. + """ + if self.coerce_doc is not None: + coerceDoc = self.coerce_doc + + assert type(port) is int + if port not in range(range_min, range_max): + raise ValueError("Port out of range") + log.err() + + @staticmethod + def uid_check(error_message): + """ + Check that we're not root. If we are, setuid(1000) to normal user if + we're running on a posix-based system, and if we're on Windows just + tell the user that we can't be run as root with the specified options + and then exit. + + :param error_message: + The string to log as an error message when the uid check fails. + """ + uid, gid = os.getuid(), os.getgid() + if uid == 0 and gid == 0: + log.msg(error_message) + if os.name == 'posix': + log.msg("Dropping privileges to normal user...") + os.setgid(1000) + os.setuid(1000) + else: + sys.exit(0) + + @staticmethod + def dir_check(d): + """Check that the given directory exists.""" + if not os.path.isdir(d): + raise ValueError("%s doesn't exist, or has wrong permissions" + % d) + + @staticmethod + def file_check(f): + """Check that the given file exists.""" + if not os.path.isfile(f): + raise ValueError("%s does not exist, or has wrong permissions" + % f) + diff --git a/wtf/process.py b/wtf/process.py new file mode 100644 index 0000000..25d6368 --- /dev/null +++ b/wtf/process.py @@ -0,0 +1,73 @@ +# +# process.py +# ---------- +# OONI utilities for dealing with starting and stopping processes. +# +# :author: Isis Lovecruft +# :version: 0.1.0-pre-alpha +# :license: see include LICENSE file +# :copyright: copyright (c) 2012, Isis Lovecruft, The Tor Project Inc. +# + +from twisted.internet import defer + +@defer.inlineCallbacks +def singleton_semaphore(deferred_process_init, + callbacks=[], errbacks=[], + max_inits=1): + """ + Initialize a process only once, and do not return until + that initialization is complete. If the keyword parameter max_inits= + is given, run the process a maximum of that number of times. + + :param deferred_process_init: + A deferred which returns a connected process via + :meth:`twisted.internet.reactor.spawnProcess`. + :param callbacks: + A list of callback functions to add to the initialized processes' + deferred. + :param errbacks: + A list of errback functions to add to the initialized processes' + deferred. + :param max_inits: + An integer specifying the maximum number of allowed + initializations for :param:deferred_process_init. If no maximum + is given, only one instance (a singleton) of the process is + initialized. + :return: + The final state of the :param deferred_process_init: after the + callback chain has completed. This should be a fully initialized + process connected to a :class:`twisted.internet.reactor`. + """ + assert isinstance(callbacks, list) + assert isinstance(errbacks, list) + assert isinstance(max_inits, int) + + for cb in callbacks: + deferred_process_init.addCallback(cb) + for eb in errbacks: + deferred_process_init.addErrback(eb) + + only_this_many = defer.DeferredSemaphore(max_inits) + singleton = yield only_this_many.run(deferred_process_init) + defer.returnValue(singleton) + +class Singleton(object): + """ + Generic Class for creating Singleton subclasses. + + Subclass me to create a singleton class, which will only ever have one + instance, regardless of how many times the subclass constructor is called. + + Any subclass of me should override ``init`` rather than ``__init__``, + because the latter is called whenever the constructor is called. + """ + def __new__(cls, *args, **kwds): + it = cls.__dict__.get("__it__") + if it is not None: + return it + cls.__it__ = it = object.__new__(cls) + it.init(*args, **kwds) + return it + def init(self, *args, **kwds): + pass
tor-commits@lists.torproject.org