[tor-commits] [stem/master] Support padding-counts in extrainfo descriptors

atagar at torproject.org atagar at torproject.org
Wed May 17 16:55:34 UTC 2017


commit 157d9a84b53a538401b510e09b1439fdd99b8c77
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed May 17 09:54:21 2017 -0700

    Support padding-counts in extrainfo descriptors
    
    Adding support for the new addition in...
    
      https://gitweb.torproject.org/torspec.git/commit/?id=0803997
    
    Presently all values in the mapping are integers but the spec doesn't note if
    that will always be the case or not. Reached out to Mike for clarification.
---
 docs/change_log.rst                          |  1 +
 stem/descriptor/extrainfo_descriptor.py      | 38 ++++++++++++++++++++++++
 test/unit/descriptor/extrainfo_descriptor.py | 43 ++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)

diff --git a/docs/change_log.rst b/docs/change_log.rst
index cd5dcd5..c9b96af 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -60,6 +60,7 @@ The following are only available within Stem's `git repository
   * Sped descriptor reading by ~25% by deferring defaulting when validating
   * Added server descriptor's new extra_info_sha256_digest attribute (:spec:`0f03581`)
   * Added server descriptor's new protocol attribute (:spec:`eb4fb3c`)
+  * Added extrainfo descriptor's new padding_counts attributes (:spec:`0803997`)
   * Shared randomness properties weren't being read in votes (:trac:`21102`)
 
  * **Utilities**
diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py
index 2843c8a..fc4a124 100644
--- a/stem/descriptor/extrainfo_descriptor.py
+++ b/stem/descriptor/extrainfo_descriptor.py
@@ -331,6 +331,29 @@ def _parse_cell_circuits_per_decline_line(descriptor, entries):
   descriptor.cell_circuits_per_decile = int(value)
 
 
+def _parse_padding_counts_line(descriptor, entries):
+  # "padding-counts" YYYY-MM-DD HH:MM:SS (NSEC s) key=val key=val...
+
+  value = _value('padding-counts', entries)
+  timestamp, interval, remainder = _parse_timestamp_and_interval('padding-counts', value)
+  entries = {}
+
+  for entry in remainder.split(' '):
+    if '=' not in entry:
+      raise ValueError('Entries in padding-counts line should be key=value mappings: padding-counts %s' % value)
+
+    k, v = entry.split('=', 1)
+
+    if not v:
+      raise ValueError('Entry in padding-counts line had a blank value: padding-counts %s' % value)
+
+    entries[k] = int(v) if v.isdigit() else v
+
+  setattr(descriptor, 'padding_counts_end', timestamp)
+  setattr(descriptor, 'padding_counts_interval', interval)
+  setattr(descriptor, 'padding_counts', entries)
+
+
 def _parse_dirreq_line(keyword, recognized_counts_attr, unrecognized_counts_attr, descriptor, entries):
   value = _value(keyword, entries)
 
@@ -699,6 +722,12 @@ class ExtraInfoDescriptor(Descriptor):
   :var int hs_dir_onions_seen: rounded count of the identities seen
   :var int hs_dir_onions_seen_attr: **\*** attributes provided for the hs_dir_onions_seen
 
+  **Padding Count Attributes:**
+
+  :var dict padding_counts: **\*** padding parameters
+  :var datetime padding_counts_end: end of the period when padding data is being collected
+  :var int padding_counts_interval: length in seconds of the interval
+
   **Bridge Attributes:**
 
   :var datetime bridge_stats_end: end of the period when stats were gathered
@@ -715,6 +744,10 @@ class ExtraInfoDescriptor(Descriptor):
   .. versionchanged:: 1.4.0
      Added the hs_stats_end, hs_rend_cells, hs_rend_cells_attr,
      hs_dir_onions_seen, and hs_dir_onions_seen_attr attributes.
+
+  .. versionchanged:: 1.6.0
+     Added the padding_counts, padding_counts_end, and padding_counts_interval
+     attributes.
   """
 
   ATTRIBUTES = {
@@ -792,6 +825,10 @@ class ExtraInfoDescriptor(Descriptor):
     'hs_dir_onions_seen': (None, _parse_hidden_service_dir_onions_seen_line),
     'hs_dir_onions_seen_attr': ({}, _parse_hidden_service_dir_onions_seen_line),
 
+    'padding_counts': ({}, _parse_padding_counts_line),
+    'padding_counts_end': (None, _parse_padding_counts_line),
+    'padding_counts_interval': (None, _parse_padding_counts_line),
+
     'bridge_stats_end': (None, _parse_bridge_stats_end_line),
     'bridge_stats_interval': (None, _parse_bridge_stats_end_line),
     'bridge_ips': (None, _parse_bridge_ips_line),
@@ -837,6 +874,7 @@ class ExtraInfoDescriptor(Descriptor):
     'hidserv-stats-end': _parse_hidden_service_stats_end_line,
     'hidserv-rend-relayed-cells': _parse_hidden_service_rend_relayed_cells_line,
     'hidserv-dir-onions-seen': _parse_hidden_service_dir_onions_seen_line,
+    'padding-counts': _parse_padding_counts_line,
     'dirreq-v2-ips': _parse_dirreq_v2_ips_line,
     'dirreq-v3-ips': _parse_dirreq_v3_ips_line,
     'dirreq-v2-reqs': _parse_dirreq_v2_reqs_line,
diff --git a/test/unit/descriptor/extrainfo_descriptor.py b/test/unit/descriptor/extrainfo_descriptor.py
index a59d0f0..798320e 100644
--- a/test/unit/descriptor/extrainfo_descriptor.py
+++ b/test/unit/descriptor/extrainfo_descriptor.py
@@ -636,6 +636,49 @@ k0d2aofcVbHr4fPQOSST0LXDrhFl5Fqo5um296zpJGvRUeO6S44U/EfJAGShtqWw
         expect_invalid_attr(self, {keyword: entry}, stat_attr)
         expect_invalid_attr(self, {keyword: entry}, extra_attr, {})
 
+  def test_padding_counts(self):
+    """
+    Check the 'hidserv-dir-onions-seen' lines.
+    """
+
+    desc = RelayExtraInfoDescriptor.create({'padding-counts': '2017-05-17 11:02:58 (86400 s) bin-size=10000 write-drop=0 write-pad=10000 write-total=10000 read-drop=0 read-pad=10000 read-total=3780000 enabled-read-pad=0 enabled-read-total=0 enabled-write-pad=0 enabled-write-total=0 max-chanpad-timers=0 non-numeric=test'})
+
+    self.assertEqual({
+      'bin-size': 10000,
+      'write-drop': 0,
+      'write-pad': 10000,
+      'write-total': 10000,
+      'read-drop': 0,
+      'read-pad': 10000,
+      'read-total': 3780000,
+      'enabled-read-pad': 0,
+      'enabled-read-total': 0,
+      'enabled-write-pad': 0,
+      'enabled-write-total': 0,
+      'max-chanpad-timers': 0,
+      'non-numeric': 'test',  # presently all values are ints but the spec allows for anything
+    }, desc.padding_counts)
+
+    self.assertEqual(datetime.datetime(2017, 5, 17, 11, 2, 58), desc.padding_counts_end)
+    self.assertEqual(86400, desc.padding_counts_interval)
+
+    test_entries = (
+      '',
+      '2012-05-03',
+      '2012-05-03 12:07:60 (500 s)',
+      '2012-05-03 12:07:50 (500 s',
+      '2012-05-03 12:07:50 (500s)',
+      '2012-05-03 12:07:50 (500 s)bin-size=10',
+      '2012-05-03 12:07:50 (500 s) bin-size',
+      '2012-05-03 12:07:50 (500 s) bin-size=',
+    )
+
+    for entry in test_entries:
+      desc = expect_invalid_attr(self, {'padding-counts': entry})
+      self.assertEqual({}, desc.padding_counts)
+      self.assertEqual(None, desc.padding_counts_end)
+      self.assertEqual(None, desc.padding_counts_interval)
+
   def test_locale_mapping_lines(self):
     """
     Uses valid and invalid data to tests lines of the form...



More information about the tor-commits mailing list