[tor-commits] [stem/master] Simplify LinkSpecifier construction

atagar at torproject.org atagar at torproject.org
Sun Nov 17 23:40:39 UTC 2019


commit 938c397648003b15a44412bb0c97b5ad114ad9fa
Author: Damian Johnson <atagar at torproject.org>
Date:   Thu Oct 31 11:39:35 2019 -0700

    Simplify LinkSpecifier construction
    
    Constructing from packed values made construction of a LinkSpecifier a pita.
    Taking an address/port argument instead.
---
 stem/client/datatype.py            | 56 ++++++++++++++++++++++++++------------
 test/unit/client/link_specifier.py | 10 ++++++-
 2 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/stem/client/datatype.py b/stem/client/datatype.py
index a0e59cb0..ac417b83 100644
--- a/stem/client/datatype.py
+++ b/stem/client/datatype.py
@@ -566,6 +566,8 @@ class LinkSpecifier(Field):
   `EXTEND cell specification
   <https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt#n975>`_.
 
+  .. versionadded:: 1.8.0
+
   :var int type: numeric identifier of our type
   :var bytes value: encoded link specification destination
   """
@@ -589,9 +591,9 @@ class LinkSpecifier(Field):
     value, packed = split(packed, value_size)
 
     if link_type == 0:
-      return LinkByIPv4(value), packed
+      return LinkByIPv4.unpack(value), packed
     elif link_type == 1:
-      return LinkByIPv6(value), packed
+      return LinkByIPv6.unpack(value), packed
     elif link_type == 2:
       return LinkByFingerprint(value), packed
     elif link_type == 3:
@@ -611,46 +613,58 @@ class LinkByIPv4(LinkSpecifier):
   """
   TLS connection to an IPv4 address.
 
+  .. versionadded:: 1.8.0
+
   :var str address: relay IPv4 address
   :var int port: relay ORPort
   """
 
-  def __init__(self, value):
-    super(LinkByIPv4, self).__init__(0, value)
+  def __init__(self, address, port):
+    super(LinkByIPv4, self).__init__(0, _pack_ipv4_address(address) + Size.SHORT.pack(port))
 
+    self.address = address
+    self.port = port
+
+  @staticmethod
+  def unpack(value):
     if len(value) != 6:
       raise ValueError('IPv4 link specifiers should be six bytes, but was %i instead: %s' % (len(value), binascii.hexlify(value)))
 
-    address_bin, value = split(value, 4)
-    self.address = _unpack_ipv4_address(address_bin)
-
-    self.port, _ = Size.SHORT.pop(value)
+    addr, port = split(value, 4)
+    return LinkByIPv4(_unpack_ipv4_address(addr), Size.SHORT.unpack(port))
 
 
 class LinkByIPv6(LinkSpecifier):
   """
   TLS connection to an IPv6 address.
 
+  .. versionadded:: 1.8.0
+
   :var str address: relay IPv6 address
   :var int port: relay ORPort
   """
 
-  def __init__(self, value):
-    super(LinkByIPv6, self).__init__(1, value)
+  def __init__(self, address, port):
+    super(LinkByIPv6, self).__init__(1, _pack_ipv6_address(address) + Size.SHORT.pack(port))
 
+    self.address = address
+    self.port = port
+
+  @staticmethod
+  def unpack(value):
     if len(value) != 18:
       raise ValueError('IPv6 link specifiers should be eighteen bytes, but was %i instead: %s' % (len(value), binascii.hexlify(value)))
 
-    address_bin, value = split(value, 16)
-    self.address = _unpack_ipv6_address(address_bin)
-
-    self.port, _ = Size.SHORT.pop(value)
+    addr, port = split(value, 16)
+    return LinkByIPv6(_unpack_ipv6_address(addr), Size.SHORT.unpack(port))
 
 
 class LinkByFingerprint(LinkSpecifier):
   """
   Connection to a SHA1 identity fingerprint.
 
+  .. versionadded:: 1.8.0
+
   :var str fingerprint: relay sha1 fingerprint
   """
 
@@ -667,6 +681,8 @@ class LinkByEd25519(LinkSpecifier):
   """
   Connection to a Ed25519 identity fingerprint.
 
+  .. versionadded:: 1.8.0
+
   :var str fingerprint: relay ed25519 fingerprint
   """
 
@@ -713,15 +729,19 @@ class KDF(collections.namedtuple('KDF', ['key_hash', 'forward_digest', 'backward
     return KDF(key_hash, forward_digest, backward_digest, forward_key, backward_key)
 
 
-def _unpack_ipv4_address(value):
-  # convert bytes to a standard IPv4 address
+def _pack_ipv4_address(address):
+  return b''.join([Size.CHAR.pack(int(v)) for v in address.split('.')])
+
 
+def _unpack_ipv4_address(value):
   return '.'.join([str(Size.CHAR.unpack(value[i:i + 1])) for i in range(4)])
 
 
-def _unpack_ipv6_address(value):
-  # convert bytes to a standard IPv6 address
+def _pack_ipv6_address(address):
+  return b''.join([Size.SHORT.pack(int(v, 16)) for v in address.split(':')])
 
+
+def _unpack_ipv6_address(value):
   return ':'.join(['%04x' % Size.SHORT.unpack(value[i * 2:(i + 1) * 2]) for i in range(8)])
 
 
diff --git a/test/unit/client/link_specifier.py b/test/unit/client/link_specifier.py
index b42ea57c..181627de 100644
--- a/test/unit/client/link_specifier.py
+++ b/test/unit/client/link_specifier.py
@@ -15,7 +15,7 @@ from stem.client.datatype import (
 
 class TestLinkSpecifier(unittest.TestCase):
   def test_link_by_ipv4_address(self):
-    destination, _ = LinkSpecifier.pop(b'\x00\x06\x01\x02\x03\x04#)')
+    destination = LinkSpecifier.unpack(b'\x00\x06\x01\x02\x03\x04#)')
 
     self.assertEqual(LinkByIPv4, type(destination))
     self.assertEqual(0, destination.type)
@@ -23,6 +23,10 @@ class TestLinkSpecifier(unittest.TestCase):
     self.assertEqual('1.2.3.4', destination.address)
     self.assertEqual(9001, destination.port)
 
+    destination = LinkByIPv4('1.2.3.4', 9001)
+    self.assertEqual(b'\x00\x06\x01\x02\x03\x04#)', destination.pack())
+    self.assertEqual(b'\x01\x02\x03\x04#)', destination.value)
+
   def test_link_by_ipv6_address(self):
     destination, _ = LinkSpecifier.pop(b'\x01\x12&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01#)')
 
@@ -32,6 +36,10 @@ class TestLinkSpecifier(unittest.TestCase):
     self.assertEqual('2600:0000:0000:0000:0000:0000:0000:0001', destination.address)
     self.assertEqual(9001, destination.port)
 
+    destination = LinkByIPv6('2600:0000:0000:0000:0000:0000:0000:0001', 9001)
+    self.assertEqual(b'\x01\x12&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01#)', destination.pack())
+    self.assertEqual(b'&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01#)', destination.value)
+
   def test_link_by_fingerprint(self):
     destination, _ = LinkSpecifier.pop(b'\x02\x14CCCCCCCCCCCCCCCCCCCC')
 





More information about the tor-commits mailing list