[tor-commits] [stem/master] Support for CIRC_MINOR events
atagar at torproject.org
atagar at torproject.org
Mon Dec 3 17:06:02 UTC 2012
commit 3ba521dfa2f2a6f023e7b92fa24bcfb910f1fe78
Author: Damian Johnson <atagar at torproject.org>
Date: Mon Dec 3 09:00:49 2012 -0800
Support for CIRC_MINOR events
Implementation and testing for CIRC_MINOR events. Snagged test data by
listening for events while bootstrapping.
---
stem/__init__.py | 20 +++++++++++
stem/control.py | 1 +
stem/response/events.py | 77 ++++++++++++++++++++++++++++++++++++++++++
test/unit/response/events.py | 25 +++++++++++++
4 files changed, 123 insertions(+), 0 deletions(-)
diff --git a/stem/__init__.py b/stem/__init__.py
index d7ec4f8..cddf033 100644
--- a/stem/__init__.py
+++ b/stem/__init__.py
@@ -87,6 +87,7 @@ Library for working with the tor process.
**HS_SERVICE_REND** server side hidden service rendezvous circuit
**TESTING** testing to see if we're reachable, so we can be used as a relay
**CONTROLLER** circuit that was built by a controller
+ **MEASURE_TIMEOUT** unknown (https://trac.torproject.org/7626)
==================== ===========
.. data:: CircClosureReason (enum)
@@ -114,6 +115,18 @@ Library for working with the tor process.
**MEASUREMENT_EXPIRED** same as **TIMEOUT** except that it was left open for measurement purposes
========================= ===========
+.. data:: CircEvent (enum)
+
+ Type of change reflected in a circuit by a CIRC_MINOR event. Tor may provide
+ event types not in this enum.
+
+ ===================== ===========
+ CircEvent Description
+ ===================== ===========
+ **PURPOSE_CHANGED** circuit purpose or hidden service state has changed
+ **CANNIBALIZED** circuit connections are being reused for a different circuit
+ ===================== ===========
+
.. data:: HiddenServiceState (enum)
State that a hidden service circuit can have. These were introduced in tor
@@ -355,6 +368,7 @@ __all__ = [
"CircBuildFlag",
"CircPurpose",
"CircClosureReason",
+ "CircEvent",
"HiddenServiceState",
"StreamStatus",
"StreamClosureReason",
@@ -467,6 +481,7 @@ CircPurpose = stem.util.enum.UppercaseEnum(
"HS_SERVICE_REND",
"TESTING",
"CONTROLLER",
+ "MEASURE_TIMEOUT",
)
CircClosureReason = stem.util.enum.UppercaseEnum(
@@ -487,6 +502,11 @@ CircClosureReason = stem.util.enum.UppercaseEnum(
"MEASUREMENT_EXPIRED",
)
+CircEvent = stem.util.enum.UppercaseEnum(
+ "PURPOSE_CHANGED",
+ "CANNIBALIZED",
+)
+
HiddenServiceState = stem.util.enum.UppercaseEnum(
"HSCI_CONNECTING",
"HSCI_INTRO_SENT",
diff --git a/stem/control.py b/stem/control.py
index 43229b5..c20db12 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -83,6 +83,7 @@ providing its own for interacting at a higher level.
**BUILDTIMEOUT_SET** :class:`stem.response.events.BuildTimeoutSetEvent`
**BW** :class:`stem.response.events.BandwidthEvent`
**CIRC** :class:`stem.response.events.CircuitEvent`
+ **CIRC_MINOR** :class:`stem.response.events.CircMinorEvent`
**CLIENTS_SEEN** :class:`stem.response.events.ClientsSeenEvent`
**CONF_CHANGED** :class:`stem.response.events.ConfChangedEvent`
**DEBUG** :class:`stem.response.events.LogEvent`
diff --git a/stem/response/events.py b/stem/response/events.py
index bf74fce..1763913 100644
--- a/stem/response/events.py
+++ b/stem/response/events.py
@@ -367,6 +367,82 @@ class CircuitEvent(Event):
log_id = "event.circ.unknown_remote_reason.%s" % self.remote_reason
log.log_once(log_id, log.INFO, unrecognized_msg % ('remote reason', self.remote_reason))
+class CircMinorEvent(Event):
+ """
+ Event providing information about minor changes in our circuits. This was
+ first added in tor version 0.2.3.11.
+
+ :var str id: circuit identifier
+ :var stem.CircEvent event: type of change in the circuit
+ :var tuple path: relays involved in the circuit, these are
+ **(fingerprint, nickname)** tuples
+ :var tuple build_flags: :data:`~stem.CircBuildFlag` attributes
+ governing how the circuit is built
+ :var stem.CircPurpose purpose: purpose that the circuit is intended for
+ :var stem.HiddenServiceState hs_state: status if this is a hidden service circuit
+ :var str rend_query: circuit's rendezvous-point if this is hidden service related
+ :var datetime created: time when the circuit was created or cannibalized
+ :var stem.CircPurpose old_purpose: prior purpose for the circuit
+ :var stem.HiddenServiceState old_hs_state: prior status as a hidden service circuit
+ """
+
+ _POSITIONAL_ARGS = ("id", "event", "path")
+ _KEYWORD_ARGS = {
+ "BUILD_FLAGS": "build_flags",
+ "PURPOSE": "purpose",
+ "HS_STATE": "hs_state",
+ "REND_QUERY": "rend_query",
+ "TIME_CREATED": "created",
+ "OLD_PURPOSE": "old_purpose",
+ "OLD_HS_STATE": "old_hs_state",
+ }
+
+ def _parse(self):
+ self.path = tuple(stem.control._parse_circ_path(self.path))
+
+ if self.build_flags != None:
+ self.build_flags = tuple(self.build_flags.split(','))
+
+ if self.created != None:
+ try:
+ self.created = str_tools.parse_iso_timestamp(self.created)
+ except ValueError, exc:
+ raise stem.ProtocolError("Unable to parse create date (%s): %s" % (exc, self))
+
+ if self.id != None and not tor_tools.is_valid_circuit_id(self.id):
+ raise stem.ProtocolError("Circuit IDs must be one to sixteen alphanumeric characters, got '%s': %s" % (self.id, self))
+
+ # log if we have an unrecognized event, status, build flag, purpose, or
+ # hidden service state
+
+ unrecognized_msg = UNRECOGNIZED_ATTR_MSG % ("CIRC_MINOR", self)
+
+ if not self.event in stem.CircEvent:
+ log_id = "event.circ_minor.unknown_event.%s" % self.event
+ log.log_once(log_id, log.INFO, unrecognized_msg % ('event', self.event))
+
+ if self.build_flags:
+ for flag in self.build_flags:
+ if not flag in stem.CircBuildFlag:
+ log_id = "event.circ_minor.unknown_build_flag.%s" % flag
+ log.log_once(log_id, log.INFO, unrecognized_msg % ('build flag', flag))
+
+ if self.purpose and (not self.purpose in stem.CircPurpose):
+ log_id = "event.circ_minor.unknown_purpose.%s" % self.purpose
+ log.log_once(log_id, log.INFO, unrecognized_msg % ('purpose', self.purpose))
+
+ if self.hs_state and (not self.hs_state in stem.HiddenServiceState):
+ log_id = "event.circ_minor.unknown_hs_state.%s" % self.hs_state
+ log.log_once(log_id, log.INFO, unrecognized_msg % ('hidden service state', self.hs_state))
+
+ if self.old_purpose and (not self.old_purpose in stem.CircPurpose):
+ log_id = "event.circ_minor.unknown_purpose.%s" % self.old_purpose
+ log.log_once(log_id, log.INFO, unrecognized_msg % ('purpose', self.old_purpose))
+
+ if self.old_hs_state and (not self.old_hs_state in stem.HiddenServiceState):
+ log_id = "event.circ_minor.unknown_hs_state.%s" % self.old_hs_state
+ log.log_once(log_id, log.INFO, unrecognized_msg % ('hidden service state', self.hs_state))
+
class ClientsSeenEvent(Event):
"""
Periodic event on bridge relays that provides a summary of our users.
@@ -784,6 +860,7 @@ EVENT_TYPE_TO_CLASS = {
"BUILDTIMEOUT_SET": BuildTimeoutSetEvent,
"BW": BandwidthEvent,
"CIRC": CircuitEvent,
+ "CIRC_MINOR": CircMinorEvent,
"CLIENTS_SEEN": ClientsSeenEvent,
"CONF_CHANGED": ConfChangedEvent,
"DEBUG": LogEvent,
diff --git a/test/unit/response/events.py b/test/unit/response/events.py
index f6a4b85..a977627 100644
--- a/test/unit/response/events.py
+++ b/test/unit/response/events.py
@@ -53,6 +53,15 @@ $E57A476CD4DFBD99B4EE52A100A58610AD6E80B9,hamburgerphone"
CIRC_BUILT_OLD = "650 CIRC 1 BUILT \
$E57A476CD4DFBD99B4EE52A100A58610AD6E80B9,hamburgerphone,PrivacyRepublic14"
+# CIRC_MINOR event from tor 0.2.3.16.
+
+CIRC_MINOR_EVENT = "650 CIRC_MINOR 7 PURPOSE_CHANGED \
+$67B2BDA4264D8A189D9270E28B1D30A262838243~europa1 \
+BUILD_FLAGS=IS_INTERNAL,NEED_CAPACITY \
+PURPOSE=MEASURE_TIMEOUT \
+TIME_CREATED=2012-12-03T16:45:33.409602 \
+OLD_PURPOSE=TESTING"
+
# CLIENTS_SEEN example from the spec
CLIENTS_SEEN_EVENT = '650 CLIENTS_SEEN \
@@ -406,6 +415,22 @@ class TestEvents(unittest.TestCase):
self.assertEqual({'us': 16, 'de': 8, 'uk': 8}, event.locales)
self.assertEqual({'v4': 16, 'v6': 40}, event.ip_versions)
+ def test_circ_minor_event(self):
+ event = _get_event(CIRC_MINOR_EVENT)
+
+ self.assertTrue(isinstance(event, stem.response.events.CircMinorEvent))
+ self.assertEqual(CIRC_MINOR_EVENT.lstrip("650 "), str(event))
+ self.assertEqual("7", event.id)
+ self.assertEqual(CircEvent.PURPOSE_CHANGED, event.event)
+ self.assertEqual((("67B2BDA4264D8A189D9270E28B1D30A262838243", "europa1"),), event.path)
+ self.assertEqual((CircBuildFlag.IS_INTERNAL, CircBuildFlag.NEED_CAPACITY), event.build_flags)
+ self.assertEqual(CircPurpose.MEASURE_TIMEOUT, event.purpose)
+ self.assertEqual(None, event.hs_state)
+ self.assertEqual(None, event.rend_query)
+ self.assertEqual(datetime.datetime(2012, 12, 3, 16, 45, 33, 409602), event.created)
+ self.assertEqual(CircPurpose.TESTING, event.old_purpose)
+ self.assertEqual(None, event.old_hs_state)
+
def test_conf_changed(self):
event = _get_event(CONF_CHANGED_EVENT)
More information about the tor-commits
mailing list