commit dcf2092607c8be29d065def1cb104290709bef87 Author: Ravi Chandra Padmala neenaoffline@gmail.com Date: Thu Aug 9 17:21:09 2012 +0530
RouterDescriptor objects store a list of flags --- stem/descriptor/networkstatus.py | 83 ++++++++++---------------------- test/integ/descriptor/networkstatus.py | 7 +-- 2 files changed, 29 insertions(+), 61 deletions(-)
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py index b1dc4dd..214a33c 100644 --- a/stem/descriptor/networkstatus.py +++ b/stem/descriptor/networkstatus.py @@ -49,6 +49,7 @@ except: import stem.descriptor import stem.version import stem.exit_policy +import stem.util.enum
from stem.descriptor import _read_until_keywords, _skip_until_keywords, _peek_keyword, _strptime from stem.descriptor import _read_keyword_line, _read_keyword_line_str, _get_pseudo_pgp_block, _peek_line @@ -58,6 +59,8 @@ _bandwidth_weights_regex = re.compile(" ".join(["W%s=\d+" % weight for weight in
_router_desc_end_kws = ["r", "bandwidth-weights", "directory-footer", "directory-signature"]
+Flag = stem.util.enum.Enum(*[(flag.upper(), flag) for flag in ["Authority", "BadExit", "Exit", "Fast", "Guard", "HSDir", "Named", "Running", "Stable", "Unnamed", "V2Dir", "Valid"]]) + def parse_file(document_file, validate = True): """ Iterates over the router descriptors in a network status document. @@ -82,13 +85,13 @@ def parse_file(document_file, validate = True): document_data = document_data + document_file.read() document = NetworkStatusDocument(document_data, validate) document_file.seek(r_offset) - document.router_descriptors = _router_desc_generator(document_file, document.vote_status == "vote", validate) + document.router_descriptors = _router_desc_generator(document_file, document.vote_status == "vote", validate, document.known_flags) return document.router_descriptors
-def _router_desc_generator(document_file, vote, validate): +def _router_desc_generator(document_file, vote, validate, known_flags): while _peek_keyword(document_file) == "r": desc_content = "".join(_read_until_keywords(_router_desc_end_kws, document_file, False, True)) - yield RouterDescriptor(desc_content, vote, validate) + yield RouterDescriptor(desc_content, vote, validate, known_flags)
class NetworkStatusDocument(stem.descriptor.Descriptor): """ @@ -156,8 +159,8 @@ class NetworkStatusDocument(stem.descriptor.Descriptor):
self._parse(raw_content)
- def _generate_router(self, raw_content, vote, validate): - return RouterDescriptor(raw_content, vote, validate) + def _generate_router(self, raw_content, vote, validate, known_flags): + return RouterDescriptor(raw_content, vote, validate, known_flags)
def _validate_network_status_version(self): return self.network_status_version == "3" @@ -220,7 +223,7 @@ class NetworkStatusDocument(stem.descriptor.Descriptor): # router descriptors if _peek_keyword(content) == "r": router_descriptors_data = "".join(_read_until_keywords(["bandwidth-weights", "directory-footer", "directory-signature"], content, False, True)) - self.router_descriptors = _router_desc_generator(StringIO(router_descriptors_data), vote, validate) + self.router_descriptors = _router_desc_generator(StringIO(router_descriptors_data), vote, validate, self.known_flags)
# footer section if self.consensus_method > 9 or vote and filter(lambda x: x >= 9, self.consensus_methods): @@ -366,20 +369,8 @@ class RouterDescriptor(stem.descriptor.Descriptor): :var int orport: ***** router's ORPort :var int dirport: ***** router's DirPort
- :var bool is_valid: ***** router is valid - :var bool is_guard: ***** router is suitable for use as an entry guard - :var bool is_named: ***** router is named - :var bool is_unnamed: ***** router is unnamed - :var bool is_running: ***** router is running and currently usable - :var bool is_stable: ***** router is stable, i.e., it's suitable for for long-lived circuits - :var bool is_exit: ***** router is an exit router - :var bool is_fast: ***** router is Fast, i.e., it's usable for high-bandwidth circuits - :var bool is_authority: ***** router is a directory authority - :var bool supports_v2dir: ***** router supports v2dir - :var bool supports_v3dir: ***** router supports v3dir - :var bool is_hsdir: ***** router is a hidden status - :var bool is_badexit: ***** router is marked a bad exit - :var bool is_baddirectory: ***** router is a bad directory + :var list flags: ***** list of status flags + :var list unknown_flags: ***** list of unidentified status flags
:var :class:`stem.version.Version`,str version: Version of the Tor protocol this router is running
@@ -394,13 +385,17 @@ class RouterDescriptor(stem.descriptor.Descriptor): | exit_policy appears only in votes """
- def __init__(self, raw_contents, vote = True, validate = True): + def __init__(self, raw_contents, vote = True, validate = True, known_flags = Flag): """ Parse a router descriptor in a v3 network status document and provide a new RouterDescriptor object.
:param str raw_content: router descriptor content to be parsed + :param bool vote: True if the descriptor is from a vote document :param bool validate: whether the router descriptor should be validated + :param bool known_flags: list of known router status flags + + :raises: ValueError if the descriptor data is invalid """
super(RouterDescriptor, self).__init__(raw_contents) @@ -413,20 +408,8 @@ class RouterDescriptor(stem.descriptor.Descriptor): self.orport = None self.dirport = None
- self.is_valid = False - self.is_guard = False - self.is_named = False - self.is_unnamed = False - self.is_running = False - self.is_stable = False - self.is_exit = False - self.is_fast = False - self.is_authority = False - self.supports_v2dir = False - self.supports_v3dir = False - self.is_hsdir = False - self.is_badexit = False - self.is_baddirectory = False + self.flags = [] + self.unknown_flags = []
self.version = None
@@ -437,12 +420,14 @@ class RouterDescriptor(stem.descriptor.Descriptor):
self.microdescriptor_hashes = []
- self._parse(raw_contents, vote, validate) + self._parse(raw_contents, vote, validate, known_flags)
- def _parse(self, raw_content, vote, validate): + def _parse(self, raw_content, vote, validate, known_flags): """ :param dict raw_content: iptor contents to be applied + :param bool vote: True if the descriptor is from a vote document :param bool validate: checks the validity of descriptor content if True + :param bool known_flags: list of known router status flags
:raises: ValueError if an error occures in validation """ @@ -471,27 +456,11 @@ class RouterDescriptor(stem.descriptor.Descriptor): seen_keywords.add("s") # s Named Running Stable Valid #A series of space-separated status flags, in *lexical order* - flags = line.split(" ") - flag_map = { - "Valid": "is_valid", - "Guard": "is_guard", - "Named": "is_named", - "Unnamed": "is_unnamed", - "Running": "is_running", - "Stable": "is_stable", - "Exit": "is_exit", - "Fast": "is_fast", - "Authority": "is_authority", - "V2Dir": "supports_v2dir", - "V3Dir": "supports_v3dir", - "HSDir": "is_hsdir", - "BadExit": "is_badexit", - "BadDirectory": "is_baddirectory", - } - map(lambda flag: setattr(self, flag_map[flag], True), flags) + self.flags = line.split(" ")
- if self.is_unnamed: self.is_named = False - elif self.is_named: self.is_unnamed = False + self.unknown_flags = filter(lambda f: not f in known_flags, self.flags) + if validate and self.unknown_flags: + raise ValueError("Router contained unknown flags: %s", " ".join(self.unknown_flags))
elif peek_check_kw("v"): if "v" in seen_keywords: raise ValueError("Invalid router descriptor: 'v' line appears twice") diff --git a/test/integ/descriptor/networkstatus.py b/test/integ/descriptor/networkstatus.py index f5d8942..07414c3 100644 --- a/test/integ/descriptor/networkstatus.py +++ b/test/integ/descriptor/networkstatus.py @@ -98,8 +98,7 @@ class TestNetworkStatusDocument(unittest.TestCase): "0.2.3.18-rc", "0.2.3.19-rc"]] self.assertEquals(expected_client_versions, desc.client_versions) self.assertEquals(expected_server_versions, desc.server_versions) - known_flags = ["Authority", "BadExit", "Exit", "Fast", "Guard", "HSDir", "Named", "Running", "Stable", "Unnamed", "V2Dir", "Valid"] - self.assertEquals(known_flags, desc.known_flags) + self.assertEquals(set(desc.known_flags), set(["Authority", "BadExit", "Exit", "Fast", "Guard", "HSDir", "Named", "Running", "Stable", "Unnamed", "V2Dir", "Valid"])) expected_params = {"CircuitPriorityHalflifeMsec": 30000, "bwauthpid": 1} self.assertEquals(expected_params, desc.params) router1 = next(desc.router_descriptors) @@ -110,6 +109,7 @@ class TestNetworkStatusDocument(unittest.TestCase): self.assertEquals("178.218.213.229", router1.ip) self.assertEquals(80, router1.orport) self.assertEquals(None, router1.dirport) + self.assertEquals(set(["Exit", "Fast", "Named", "Running", "Valid"]), set(router1.flags))
self.assertEquals(8, len(desc.directory_authorities)) self.assertEquals("tor26", desc.directory_authorities[0].nickname) @@ -182,8 +182,7 @@ I/TJmV928na7RLZe2mGHCAW3VQOvV+QkCfj05VZ8CsY= self.assertEquals(300, desc.dist_delay) self.assertEquals([], desc.client_versions) self.assertEquals([], desc.server_versions) - known_flags = ["Authority", "BadExit", "Exit", "Fast", "Guard", "HSDir", "Running", "Stable", "V2Dir", "Valid"] - self.assertEquals(known_flags, desc.known_flags) + self.assertEquals(set(desc.known_flags), set(["Authority", "BadExit", "Exit", "Fast", "Guard", "HSDir", "Running", "Stable", "V2Dir", "Valid"])) expected_params = {"CircuitPriorityHalflifeMsec": 30000, "bwauthpid": 1} self.assertEquals(expected_params, desc.params) router1 = next(desc.router_descriptors)
tor-commits@lists.torproject.org