[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Function to query PROTOCOLINFO via a control port
commit 7f89ff58d2ad6ecbde7f8225e7b2c02ec400be1b
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Mon Nov 21 08:36:20 2011 -0800
Function to query PROTOCOLINFO via a control port
Implementation and integ testing to query a PROTOCOLINFO response via a control
port. Next is to do the same for control sockets.
---
run_tests.py | 2 +-
stem/connection.py | 74 ++++++++++++++++++++++++++++++++-
test/integ/connection/protocolinfo.py | 63 ++++++++++++++++++++--------
3 files changed, 120 insertions(+), 19 deletions(-)
diff --git a/run_tests.py b/run_tests.py
index 2d12a57..76e1abb 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -41,7 +41,7 @@ UNIT_TESTS = (("stem.types.ControlMessage", test.unit.types.control_message.Test
)
INTEG_TESTS = (("stem.types.ControlMessage", test.integ.types.control_message.TestControlMessage),
- ("stem.connection.ProtocolInfoResponse", test.integ.connection.protocolinfo.TestProtocolInfoResponse),
+ ("stem.connection.ProtocolInfoResponse", test.integ.connection.protocolinfo.TestProtocolInfo),
("stem.util.conf", test.integ.util.conf.TestConf),
("stem.util.system", test.integ.util.system.TestSystem),
)
diff --git a/stem/connection.py b/stem/connection.py
index 3165fba..3e97e9e 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -28,6 +28,78 @@ LOGGER = logging.getLogger("stem")
AuthMethod = stem.util.enum.Enum("NONE", "PASSWORD", "COOKIE", "UNKNOWN")
+def get_protocolinfo_port(control_addr = "127.0.0.1", control_port = 9051, keep_alive = False):
+ """
+ Issues a PROTOCOLINFO query to a control port, getting information about the
+ tor process running on it.
+
+ Arguments:
+ control_addr (str) - ip address of the controller
+ control_port (int) - port number of the controller
+ keep_alive (bool) - keeps the socket used to issue the PROTOCOLINFO query
+ open if True, closes otherwise
+
+ Returns:
+ ProtocolInfoResponse with the response given by the tor process
+
+ Raises:
+ stem.types.ProtocolError if the PROTOCOLINFO response is malformed
+ stem.types.SocketError if problems arise in establishing or using the
+ socket
+ """
+
+ control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ control_socket_file = control_socket.makefile()
+ protocolinfo_response, raised_exc = None, None
+
+ try:
+ # initiates connection
+ control_socket.connect((control_addr, control_port))
+
+ # issues the PROTOCOLINFO query
+ control_socket_file.write("PROTOCOLINFO 1\r\n")
+ control_socket_file.flush()
+
+ protocolinfo_response = stem.types.read_message(control_socket_file)
+ ProtocolInfoResponse.convert(protocolinfo_response)
+ except socket.error, exc:
+ raised_exc = stem.types.SocketError(exc)
+ except (stem.types.ProtocolError, stem.types.SocketError), exc:
+ raised_exc = exc
+
+ control_socket_file.close() # done with the linked file
+
+ if not keep_alive or raised_exc:
+ # shut down the socket we were using
+ try: control_socket.shutdown(socket.SHUT_RDWR)
+ except socket.error: pass
+
+ control_socket.close()
+ else:
+ # if we're keeping the socket open then attach it to the response
+ protocolinfo_response.socket = control_socket
+
+ if raised_exc:
+ raise raised_exc
+ else:
+ # if we have an unresolved cookie path then try to expand it again, using
+ # our port to infer a pid
+
+ cookie_path = protocolinfo_response.cookie_file
+ if cookie_path and control_addr == "127.0.0.1" and stem.util.system.is_relative_path(cookie_path):
+ try:
+ tor_pid = stem.util.system.get_pid_by_port(control_port)
+ if not tor_pid: raise IOError("pid lookup failed")
+
+ tor_cwd = stem.util.system.get_cwd(tor_pid)
+ if not tor_cwd: raise IOError("cwd lookup failed")
+
+ protocolinfo_response.cookie_file = stem.util.system.expand_path(cookie_path, tor_cwd)
+ except IOError, exc:
+ LOGGER.debug("unable to expand relative tor cookie path by port: %s" % exc)
+
+ return protocolinfo_response
+
class ProtocolInfoResponse(stem.types.ControlMessage):
"""
Version one PROTOCOLINFO query response.
@@ -166,7 +238,7 @@ class ProtocolInfoResponse(stem.types.ControlMessage):
self.cookie_file = stem.util.system.expand_path(self.cookie_file, tor_cwd)
except IOError, exc:
- LOGGER.debug("unable to expand relative tor cookie path: %s" % exc)
+ LOGGER.debug("unable to expand relative tor cookie path by name: %s" % exc)
elif line_type == "VERSION":
# Line format:
# VersionLine = "250-VERSION" SP "Tor=" TorVersion OptArguments CRLF
diff --git a/test/integ/connection/protocolinfo.py b/test/integ/connection/protocolinfo.py
index 27b5f1f..73a7884 100644
--- a/test/integ/connection/protocolinfo.py
+++ b/test/integ/connection/protocolinfo.py
@@ -1,20 +1,21 @@
"""
-Integration tests for the stem.connections.ProtocolInfoResponse class.
+Integration tests for the stem.connections.ProtocolInfoResponse class and
+related functions.
"""
-import socket
import unittest
import test.runner
import stem.types
import stem.connection
-class TestProtocolInfoResponse(unittest.TestCase):
+class TestProtocolInfo(unittest.TestCase):
"""
- Processes a ProtocolInfo query for a variety of setups.
+ Queries and parses PROTOCOLINFO. This should be run with the 'CONNECTION'
+ integ target to exercise the widest range of use cases.
"""
- def testProtocolInfoResponse(self):
+ def test_parsing(self):
"""
Makes a PROTOCOLINFO query and processes the response for our control
connection.
@@ -29,7 +30,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
control_socket = runner.get_tor_socket(False)
control_socket_file = control_socket.makefile()
- control_socket_file.write("PROTOCOLINFO\r\n")
+ control_socket_file.write("PROTOCOLINFO 1\r\n")
control_socket_file.flush()
protocolinfo_response = stem.types.read_message(control_socket_file)
@@ -42,24 +43,52 @@ class TestProtocolInfoResponse(unittest.TestCase):
self.assertNotEqual(None, protocolinfo_response.tor_version)
self.assertNotEqual(None, protocolinfo_response.auth_methods)
- self.assertEqual((), protocolinfo_response.unknown_auth_methods)
self.assertEqual(None, protocolinfo_response.socket)
+ self.assert_protocolinfo_attr(protocolinfo_response, connection_type)
+
+ def test_get_protocolinfo_port(self):
+ """
+ Exercises the stem.connection.get_protocolinfo_port function.
+ """
+
+ connection_type = test.runner.get_runner().get_connection_type()
+
+ if test.runner.OPT_PORT in test.runner.CONNECTION_OPTS[connection_type]:
+ protocolinfo_response = stem.connection.get_protocolinfo_port(control_port = test.runner.CONTROL_PORT)
+ self.assertEqual(None, protocolinfo_response.socket)
+ self.assert_protocolinfo_attr(protocolinfo_response, connection_type)
+ else:
+ # we don't have a control port
+ self.assertRaises(stem.types.SocketError, stem.connection.get_protocolinfo_port, "127.0.0.1", test.runner.CONTROL_PORT)
+
+ def assert_protocolinfo_attr(self, protocolinfo_response, connection_type):
+ """
+ Makes assertions that the protocolinfo response's attributes match those of
+ a given connection type.
+ """
+
+ # This should never have test.runner.TorConnection.NONE. If we somehow got
+ # a protocolinfo_response from that config then we have an issue. :)
if connection_type == test.runner.TorConnection.NO_AUTH:
- self.assertEqual((stem.connection.AuthMethod.NONE,), protocolinfo_response.auth_methods)
- self.assertEqual(None, protocolinfo_response.cookie_file)
+ auth_methods = (stem.connection.AuthMethod.NONE,)
elif connection_type == test.runner.TorConnection.PASSWORD:
- self.assertEqual((stem.connection.AuthMethod.PASSWORD,), protocolinfo_response.auth_methods)
- self.assertEqual(None, protocolinfo_response.cookie_file)
+ auth_methods = (stem.connection.AuthMethod.PASSWORD,)
elif connection_type == test.runner.TorConnection.COOKIE:
- self.assertEqual((stem.connection.AuthMethod.COOKIE,), protocolinfo_response.auth_methods)
- self.assertEqual(runner.get_auth_cookie_path(), protocolinfo_response.cookie_file)
+ auth_methods = (stem.connection.AuthMethod.COOKIE,)
elif connection_type == test.runner.TorConnection.MULTIPLE:
- self.assertEqual((stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.PASSWORD), protocolinfo_response.auth_methods)
- self.assertEqual(runner.get_auth_cookie_path(), protocolinfo_response.cookie_file)
+ auth_methods = (stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.PASSWORD)
elif connection_type == test.runner.TorConnection.SOCKET:
- self.assertEqual((stem.connection.AuthMethod.NONE,), protocolinfo_response.auth_methods)
- self.assertEqual(None, protocolinfo_response.cookie_file)
+ auth_methods = (stem.connection.AuthMethod.NONE,)
else:
self.fail("Unrecognized connection type: %s" % connection_type)
+
+ self.assertEqual((), protocolinfo_response.unknown_auth_methods)
+ self.assertEqual(auth_methods, protocolinfo_response.auth_methods)
+
+ if test.runner.OPT_COOKIE in test.runner.CONNECTION_OPTS[connection_type]:
+ auth_cookie_path = test.runner.get_runner().get_auth_cookie_path()
+ self.assertEqual(auth_cookie_path, protocolinfo_response.cookie_file)
+ else:
+ self.assertEqual(None, protocolinfo_response.cookie_file)
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits