[tor-commits] [stem/master] Split stem.client.cell into its own module

atagar at torproject.org atagar at torproject.org
Sun Jan 21 02:04:04 UTC 2018


commit 9b5c6bf74e3d6bc7a718d84c9d24e07bac460f0d
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Jan 8 11:42:46 2018 -0800

    Split stem.client.cell into its own module
---
 stem/client/__init__.py                 | 141 +----------------------------
 stem/client/cell.py                     | 151 ++++++++++++++++++++++++++++++++
 test/settings.cfg                       |   2 +-
 test/unit/client/__init__.py            |   7 ++
 test/unit/{client.py => client/cell.py} |  13 +--
 5 files changed, 169 insertions(+), 145 deletions(-)

diff --git a/stem/client/__init__.py b/stem/client/__init__.py
index a0288f52..21786835 100644
--- a/stem/client/__init__.py
+++ b/stem/client/__init__.py
@@ -31,128 +31,14 @@ a wrapper for :class:`~stem.socket.RelaySocket`, much the same way as
   Relay - Connection with a relay's ORPort.
 """
 
-import collections
-import struct
-
 from stem.util import enum
 
 ZERO = '\x00'
 
 
-class Cell(collections.namedtuple('Cell', ['name', 'value', 'fixed_size', 'for_circuit'])):
-  """
-  Metadata for ORPort cells.
-
-  :var str name: command of the cell
-  :var int value: integer value of the command on the wire
-  :var bool fixed_size: **True** if cells have a fixed length,
-    **False** if variable
-  :var bool for_circuit: **True** if command is for a circuit,
-    **False** otherwise
-  """
-
-  @staticmethod
-  def by_name(name):
-    """
-    Provides cell attributes by its name.
-
-    :parm str name: cell command to fetch
-
-    :raise: **ValueError** if cell type is invalid
-    """
-
-    for cell_type in CELL_TYPES:
-      if name == cell_type.name:
-        return cell_type
-
-    raise ValueError("'%s' isn't a valid cell type" % name)
-
-  @staticmethod
-  def by_value(value):
-    """
-    Provides cell attributes by its value.
-
-    :parm int value: cell value to fetch
-
-    :raise: **ValueError** if cell type is invalid
-    """
-
-    for cell_type in CELL_TYPES:
-      if value == cell_type.value:
-        return cell_type
-
-    raise ValueError("'%s' isn't a valid cell value" % value)
-
-  @staticmethod
-  def pack(name, link_version, payload, circ_id = None):
-    """
-    Provides bytes that can be used on the wire for these cell attributes.
-
-    :param str name: cell command
-    :param int link_version: link protocol version
-    :param bytes payload: cell payload
-    :param int circ_id: circuit id, if for a circuit
-
-    :raise: **ValueError** if...
-      * cell type or circuit id is invalid
-      * payload is too large
-    """
-
-    attr = Cell.by_name(name)
-    circ_id_len = Pack.LONG if link_version > 3 else Pack.SHORT
-
-    if attr.for_circuit and circ_id is None:
-      if name.startswith('CREATE'):
-        # Since we're initiating the circuit we pick any value from a range
-        # that's determined by our link version.
-
-        circ_id = 0x80000000 if link_version > 3 else 0x01
-      else:
-        raise ValueError('%s cells require a circ_id' % name)
-    elif not attr.for_circuit:
-      if circ_id:
-        raise ValueError("%s cells don't concern circuits, circ_id is unused" % name)
-
-      circ_id = 0  # field is still mandatory for all cells
-
-    packed_circ_id = struct.pack(circ_id_len, circ_id)
-    packed_command = struct.pack(Pack.CHAR, attr.value)
-    packed_size = b'' if attr.fixed_size else struct.pack(Pack.SHORT, len(payload))
-    cell = b''.join((packed_circ_id, packed_command, packed_size, payload))
-
-    # pad fixed sized cells to the required length
-
-    if attr.fixed_size:
-      fixed_cell_len = 514 if link_version > 3 else 512
-
-      if len(cell) > fixed_cell_len:
-        raise ValueError('Payload of %s is too large (%i bytes), must be less than %i' % (name, len(cell), fixed_cell_len))
-
-      cell += ZERO * (fixed_cell_len - len(cell))
-
-    return cell
-
-
-class VersionCell(Cell):
-  """
-  Link version negotiation cell.
-  """
-
-  @staticmethod
-  def pack(versions):
-    """
-    Provides the payload for a series of link versions.
-
-    :param list versions: link versions to serialize
-
-    :returns: **bytes** with a payload for these versions
-    """
-
-    # Used for link version negotiation so we don't have that yet. This is fine
-    # since VERSION cells avoid most version dependent attributes.
-
-    payload = b''.join([struct.pack(Pack.SHORT, v) for v in versions])
-    return Cell.pack('VERSIONS', 3, payload)
+__all__ = [
+  'cell',
+]
 
 
 class Relay(object):
@@ -168,24 +54,3 @@ Pack = enum.Enum(
   ('LONG', '!L'),       # 4 bytes
   ('LONG_LONG', '!Q'),  # 8 bytes
 )
-
-CELL_TYPES = (
-  Cell('PADDING', 0, True, False),              # Padding                  (section 7.2)
-  Cell('CREATE', 1, True, True),                # Create a circuit         (section 5.1)
-  Cell('CREATED', 2, True, True),               # Acknowledge create       (section 5.1)
-  Cell('RELAY', 3, True, True),                 # End-to-end data          (section 5.5 and 6)
-  Cell('DESTROY', 4, True, True),               # Stop using a circuit     (section 5.4)
-  Cell('CREATE_FAST', 5, True, True),           # Create a circuit, no PK  (section 5.1)
-  Cell('CREATED_FAST', 6, True, True),          # Circuit created, no PK   (section 5.1)
-  Cell('VERSIONS', 7, False, False),            # Negotiate proto version  (section 4)
-  Cell('NETINFO', 8, True, False),              # Time and address info    (section 4.5)
-  Cell('RELAY_EARLY', 9, True, True),           # End-to-end data; limited (section 5.6)
-  Cell('CREATE2', 10, True, True),              # Extended CREATE cell     (section 5.1)
-  Cell('CREATED2', 11, True, True),             # Extended CREATED cell    (section 5.1)
-  Cell('PADDING_NEGOTIATE', 12, True, False),   # Padding negotiation      (section 7.2)
-  Cell('VPADDING', 128, False, False),          # Variable-length padding  (section 7.2)
-  Cell('CERTS', 129, False, False),             # Certificates             (section 4.2)
-  Cell('AUTH_CHALLENGE', 130, False, False),    # Challenge value          (section 4.3)
-  Cell('AUTHENTICATE', 131, False, False),      # Client authentication    (section 4.5)
-  Cell('AUTHORIZE', 132, False, False),         # Client authorization     (not yet used)
-)
diff --git a/stem/client/cell.py b/stem/client/cell.py
new file mode 100644
index 00000000..5cd23c0e
--- /dev/null
+++ b/stem/client/cell.py
@@ -0,0 +1,151 @@
+# Copyright 2018, Damian Johnson and The Tor Project
+# See LICENSE for licensing information
+
+"""
+Messages communicated over a Tor relay's ORPort.
+
+.. versionadded:: 1.7.0
+"""
+
+import collections
+import struct
+
+from stem.client import ZERO, Pack
+
+
+class Cell(collections.namedtuple('Cell', ['name', 'value', 'fixed_size', 'for_circuit'])):
+  """
+  Metadata for ORPort cells.
+
+  :var str name: command of the cell
+  :var int value: integer value of the command on the wire
+  :var bool fixed_size: **True** if cells have a fixed length,
+    **False** if variable
+  :var bool for_circuit: **True** if command is for a circuit,
+    **False** otherwise
+  """
+
+  @staticmethod
+  def by_name(name):
+    """
+    Provides cell attributes by its name.
+
+    :parm str name: cell command to fetch
+
+    :raise: **ValueError** if cell type is invalid
+    """
+
+    for cell_type in CELL_TYPES:
+      if name == cell_type.name:
+        return cell_type
+
+    raise ValueError("'%s' isn't a valid cell type" % name)
+
+  @staticmethod
+  def by_value(value):
+    """
+    Provides cell attributes by its value.
+
+    :parm int value: cell value to fetch
+
+    :raise: **ValueError** if cell type is invalid
+    """
+
+    for cell_type in CELL_TYPES:
+      if value == cell_type.value:
+        return cell_type
+
+    raise ValueError("'%s' isn't a valid cell value" % value)
+
+  @staticmethod
+  def pack(name, link_version, payload, circ_id = None):
+    """
+    Provides bytes that can be used on the wire for these cell attributes.
+
+    :param str name: cell command
+    :param int link_version: link protocol version
+    :param bytes payload: cell payload
+    :param int circ_id: circuit id, if for a circuit
+
+    :raise: **ValueError** if...
+      * cell type or circuit id is invalid
+      * payload is too large
+    """
+
+    attr = Cell.by_name(name)
+    circ_id_len = Pack.LONG if link_version > 3 else Pack.SHORT
+
+    if attr.for_circuit and circ_id is None:
+      if name.startswith('CREATE'):
+        # Since we're initiating the circuit we pick any value from a range
+        # that's determined by our link version.
+
+        circ_id = 0x80000000 if link_version > 3 else 0x01
+      else:
+        raise ValueError('%s cells require a circ_id' % name)
+    elif not attr.for_circuit:
+      if circ_id:
+        raise ValueError("%s cells don't concern circuits, circ_id is unused" % name)
+
+      circ_id = 0  # field is still mandatory for all cells
+
+    packed_circ_id = struct.pack(circ_id_len, circ_id)
+    packed_command = struct.pack(Pack.CHAR, attr.value)
+    packed_size = b'' if attr.fixed_size else struct.pack(Pack.SHORT, len(payload))
+    cell = b''.join((packed_circ_id, packed_command, packed_size, payload))
+
+    # pad fixed sized cells to the required length
+
+    if attr.fixed_size:
+      fixed_cell_len = 514 if link_version > 3 else 512
+
+      if len(cell) > fixed_cell_len:
+        raise ValueError('Payload of %s is too large (%i bytes), must be less than %i' % (name, len(cell), fixed_cell_len))
+
+      cell += ZERO * (fixed_cell_len - len(cell))
+
+    return cell
+
+
+class VersionCell(Cell):
+  """
+  Link version negotiation cell.
+  """
+
+  @staticmethod
+  def pack(versions):
+    """
+    Provides the payload for a series of link versions.
+
+    :param list versions: link versions to serialize
+
+    :returns: **bytes** with a payload for these versions
+    """
+
+    # Used for link version negotiation so we don't have that yet. This is fine
+    # since VERSION cells avoid most version dependent attributes.
+
+    payload = b''.join([struct.pack(Pack.SHORT, v) for v in versions])
+    return Cell.pack('VERSIONS', 3, payload)
+
+
+CELL_TYPES = (
+  Cell('PADDING', 0, True, False),              # Padding                  (section 7.2)
+  Cell('CREATE', 1, True, True),                # Create a circuit         (section 5.1)
+  Cell('CREATED', 2, True, True),               # Acknowledge create       (section 5.1)
+  Cell('RELAY', 3, True, True),                 # End-to-end data          (section 5.5 and 6)
+  Cell('DESTROY', 4, True, True),               # Stop using a circuit     (section 5.4)
+  Cell('CREATE_FAST', 5, True, True),           # Create a circuit, no PK  (section 5.1)
+  Cell('CREATED_FAST', 6, True, True),          # Circuit created, no PK   (section 5.1)
+  Cell('VERSIONS', 7, False, False),            # Negotiate proto version  (section 4)
+  Cell('NETINFO', 8, True, False),              # Time and address info    (section 4.5)
+  Cell('RELAY_EARLY', 9, True, True),           # End-to-end data; limited (section 5.6)
+  Cell('CREATE2', 10, True, True),              # Extended CREATE cell     (section 5.1)
+  Cell('CREATED2', 11, True, True),             # Extended CREATED cell    (section 5.1)
+  Cell('PADDING_NEGOTIATE', 12, True, False),   # Padding negotiation      (section 7.2)
+  Cell('VPADDING', 128, False, False),          # Variable-length padding  (section 7.2)
+  Cell('CERTS', 129, False, False),             # Certificates             (section 4.2)
+  Cell('AUTH_CHALLENGE', 130, False, False),    # Challenge value          (section 4.3)
+  Cell('AUTHENTICATE', 131, False, False),      # Client authentication    (section 4.5)
+  Cell('AUTHORIZE', 132, False, False),         # Client authorization     (not yet used)
+)
diff --git a/test/settings.cfg b/test/settings.cfg
index 501dff9c..b4b125a8 100644
--- a/test/settings.cfg
+++ b/test/settings.cfg
@@ -229,7 +229,7 @@ test.unit_tests
 |test.unit.response.authchallenge.TestAuthChallengeResponse
 |test.unit.response.protocolinfo.TestProtocolInfoResponse
 |test.unit.response.mapaddress.TestMapAddressResponse
-|test.unit.client.TestClient
+|test.unit.client.cell.TestCell
 |test.unit.connection.authentication.TestAuthenticate
 |test.unit.connection.connect.TestConnect
 |test.unit.control.controller.TestControl
diff --git a/test/unit/client/__init__.py b/test/unit/client/__init__.py
new file mode 100644
index 00000000..e35416a8
--- /dev/null
+++ b/test/unit/client/__init__.py
@@ -0,0 +1,7 @@
+"""
+Unit tests for stem.client.* contents.
+"""
+
+__all__ = [
+  'cell',
+]
diff --git a/test/unit/client.py b/test/unit/client/cell.py
similarity index 87%
rename from test/unit/client.py
rename to test/unit/client/cell.py
index 6faa3e8e..8093b8d9 100644
--- a/test/unit/client.py
+++ b/test/unit/client/cell.py
@@ -1,15 +1,16 @@
 """
-Unit tests for the stem.client.
+Unit tests for the stem.client.cell.
 """
 
 import struct
 import unittest
 
-from stem.client import Pack, Cell
+from stem.client import Pack
+from stem.client.cell import Cell
 
 
-class TestClient(unittest.TestCase):
-  def test_cell_by_name(self):
+class TestCell(unittest.TestCase):
+  def test_by_name(self):
     cell = Cell.by_name('NETINFO')
     self.assertEqual('NETINFO', cell.name)
     self.assertEqual(8, cell.value)
@@ -20,7 +21,7 @@ class TestClient(unittest.TestCase):
     self.assertRaises(ValueError, Cell.by_name, 85)
     self.assertRaises(ValueError, Cell.by_name, None)
 
-  def test_cell_by_value(self):
+  def test_by_value(self):
     cell = Cell.by_value(8)
     self.assertEqual('NETINFO', cell.name)
     self.assertEqual(8, cell.value)
@@ -31,7 +32,7 @@ class TestClient(unittest.TestCase):
     self.assertRaises(ValueError, Cell.by_value, 85)
     self.assertRaises(ValueError, Cell.by_value, None)
 
-  def test_cell_pack(self):
+  def test_pack(self):
     version_payload = struct.pack(Pack.SHORT, 2)
 
     # basic link v2 and v4 VERSIONS cell





More information about the tor-commits mailing list