commit db52d5fcf38127c107399065768e710b297378c8 Author: Damian Johnson atagar@torproject.org Date: Sat Feb 3 14:03:00 2018 -0800
Initial Relay class
Clearly from all the todos just a start. --- stem/__init__.py | 2 ++ stem/client/__init__.py | 9 ++++--- stem/control.py | 2 +- stem/relay.py | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 5 deletions(-)
diff --git a/stem/__init__.py b/stem/__init__.py index 2741cee7..2d2e1c6d 100644 --- a/stem/__init__.py +++ b/stem/__init__.py @@ -485,6 +485,7 @@ __url__ = 'https://stem.torproject.org/' __license__ = 'LGPLv3'
__all__ = [ + 'client', 'descriptor', 'response', 'util', @@ -493,6 +494,7 @@ __all__ = [ 'exit_policy', 'prereq', 'process', + 'relay', 'socket', 'version', 'ControllerError', diff --git a/stem/client/__init__.py b/stem/client/__init__.py index cbeed403..9f4217c5 100644 --- a/stem/client/__init__.py +++ b/stem/client/__init__.py @@ -2,10 +2,11 @@ # See LICENSE for licensing information
""" -Interaction with a Tor relay's ORPort. :class:`~stem.client.Relay` is -a wrapper for :class:`~stem.socket.RelaySocket`, much the same way as -:class:`~stem.control.Controller` provides higher level functions for -:class:`~stem.socket.ControlSocket`. +Support for `Tor's ORPort protocol +https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt`_. + +**This module only consists of low level components, and is not intended for +users.** See our :class:`~stem.relay.Relay` the API you probably want.
.. versionadded:: 1.7.0
diff --git a/stem/control.py b/stem/control.py index 94ad5eaf..123e3b20 100644 --- a/stem/control.py +++ b/stem/control.py @@ -989,7 +989,7 @@ class BaseController(object):
class Controller(BaseController): """ - Communicates with a control socket. This is built on top of the + Connection with Tor's control socket. This is built on top of the BaseController and provides a more user friendly API for library users. """
diff --git a/stem/relay.py b/stem/relay.py new file mode 100644 index 00000000..7d1e8282 --- /dev/null +++ b/stem/relay.py @@ -0,0 +1,71 @@ +# Copyright 2018, Damian Johnson and The Tor Project +# See LICENSE for licensing information + +""" +Interaction with a Tor relay's ORPort. :class:`~stem.relay.Relay` is +a wrapper for :class:`~stem.socket.RelaySocket`, much the same way as +:class:`~stem.control.Controller` provides higher level functions for +:class:`~stem.socket.ControlSocket`. + +.. versionadded:: 1.7.0 + +:: + + Relay - Connection with a tor relay's ORPort. + | +- connect - Establishes a connection with a relay. +""" + +import stem.client +import stem.client.cell +import stem.socket +import stem.util.connection + +DEFAULT_LINK_VERSIONS = (3, 4, 5) + + +class Relay(object): + """ + Connection with a Tor relay's ORPort. + """ + + def __init__(self, orport): + self._orport = orport + + @staticmethod + def connect(address, port, link_versions = DEFAULT_LINK_VERSIONS): + """ + Establishes a connection with the given ORPort. + + :param str address: ip address of the relay + :param int port: ORPort of the relay + :param tuple link_versions: acceptable link protocol versions + + :raises: + * **ValueError** if address or port are invalid + * :class:`stem.SocketError` if we're unable to establish a connection + """ + + if stem.util.connection.is_valid_ipv4_address(address): + addr_type = stem.client.AddrType.IPv4 + elif stem.util.connection.is_valid_ipv6_address(address): + addr_type = stem.client.AddrType.IPv6 + else: + raise ValueError("'%s' isn't an IPv4 or IPv6 address" % address) + + if not stem.util.connection.is_port(port): + raise ValueError("'%s' isn't a valid port" % port) + + conn = stem.socket.RelaySocket(address, port) + conn.send(stem.client.cell.VersionsCell(link_versions).pack()) + versions_reply = stem.client.cell.Cell.pop(conn.recv(), 2)[0] + + # TODO: determine the highest common link versions + # TODO: we should fill in our address, right? + # TODO: what happens if we skip the NETINFO? + + link_version = 3 + conn.send(stem.client.cell.NetinfoCell(stem.client.Address(address, addr_type), []).pack(link_version)) + + # TODO: what if no link protocol versions are acceptable? + + return Relay(conn)