commit 7f3f8722d99b2747cafd2247b14e362c743d5290 Author: Damian Johnson atagar@torproject.org Date: Sat Mar 2 22:16:20 2013 -0800
Adding get_microdescriptors() method to the Controller
Controller method to fetch all microdescriptors. This is modeled after its counterparts for server descriptors and network status documents. However, as mentioned in 'https://trac.torproject.org/8323', the controller interface presently lacks a method to get them.
In the meantime we're reading them from disk. --- stem/control.py | 52 ++++++++++++++++++++++++++++++++++++++ test/integ/control/controller.py | 20 ++++++++++++++ 2 files changed, 72 insertions(+), 0 deletions(-)
diff --git a/stem/control.py b/stem/control.py index d1025b8..a342fd0 100644 --- a/stem/control.py +++ b/stem/control.py @@ -26,6 +26,7 @@ providing its own for interacting at a higher level. |- get_protocolinfo - information about the controller interface | |- get_microdescriptor - querying the microdescriptor for a relay + |- get_microdescriptors - provides all presently available microdescriptors |- get_server_descriptor - querying the server descriptor for a relay |- get_server_descriptors - provides all presently available server descriptors |- get_network_status - querying the router status entry for a relay @@ -141,6 +142,7 @@ import threading import time
import stem.descriptor.microdescriptor +import stem.descriptor.reader import stem.descriptor.router_status_entry import stem.descriptor.server_descriptor import stem.exit_policy @@ -999,6 +1001,56 @@ class Controller(BaseController): else: return default
+ def get_microdescriptors(self, default = UNDEFINED): + """ + Provides an iterator for all of the microdescriptors that tor presently + knows about. + + **Tor does not expose this information via the control protocol (`ticket + https://trac.torproject.org/8323`_).** Until it does this reads the + microdescriptors from disk, and hence won't work remotely or if we lack + read permissions. + + :param list default: items to provide if the query fails + + :returns: iterates over + :class:`~stem.descriptor.microdescriptor.Microdescriptor` for relays in + the tor network + + :raises: :class:`stem.ControllerError` if unable to query tor and no + default was provided + """ + + try: + try: + data_directory = self.get_conf("DataDirectory") + except stem.ControllerError, exc: + raise stem.OperationFailed(message = "Unable to determine the data directory (%s)" % exc) + + cached_descriptor_path = os.path.join(data_directory, "cached-microdescs") + + if not os.path.exists(data_directory): + raise stem.OperationFailed(message = "Data directory reported by tor doesn't exist (%s)" % data_directory) + elif not os.path.exists(cached_descriptor_path): + raise stem.OperationFailed(message = "Data directory doens't contain cached microescriptors (%s)" % cached_descriptor_path) + + with stem.descriptor.reader.DescriptorReader([cached_descriptor_path]) as reader: + for desc in reader: + # It shouldn't be possible for these to be something other than + # microdescriptors but as the saying goes: trust but verify. + + if not isinstance(desc, stem.descriptor.microdescriptor.Microdescriptor): + raise stem.OperationFailed(message = "BUG: Descriptor reader provided non-microdescriptor content (%s)" % type(desc)) + + yield desc + except Exception, exc: + if default == UNDEFINED: + raise exc + else: + if default is not None: + for entry in default: + yield entry + def get_server_descriptor(self, relay, default = UNDEFINED): """ Provides the server descriptor for the relay with the given fingerprint or diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py index 42006c4..b93b802 100644 --- a/test/integ/control/controller.py +++ b/test/integ/control/controller.py @@ -827,6 +827,26 @@ class TestController(unittest.TestCase):
self.assertEqual(md_by_fingerprint, md_by_nickname)
+ def test_get_microdescriptors(self): + """ + Fetches a few descriptors via the get_microdescriptors() method. + """ + + runner = test.runner.get_runner() + + if test.runner.require_control(self): + return + + with runner.get_tor_controller() as controller: + count = 0 + + for desc in controller.get_microdescriptors(): + self.assertTrue(desc.onion_key is not None) + + count += 1 + if count > 10: + break + def test_get_server_descriptor(self): """ Basic checks for get_server_descriptor().
tor-commits@lists.torproject.org