tor-commits
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2012
- 18 participants
- 1508 discussions

06 Nov '12
commit f4b9a440ccb01490f0596c0857506d89378a9ea4
Author: Steven Murdoch <Steven.Murdoch(a)cl.cam.ac.uk>
Date: Tue Nov 6 18:35:16 2012 +0000
Various updates to the design paper
- Stream isolation
- Mention about Torbutton
- Node hibernation
- EWMA
- DHT and authorization for hidden services
- Path length limitations
- Abuse management (DNSBL and ExoneraTor)
---
tor-design-2012.tex | 173 +++++++++++++++++++++++++++++++++++----------------
1 files changed, 120 insertions(+), 53 deletions(-)
diff --git a/tor-design-2012.tex b/tor-design-2012.tex
index 66b6ad4..e00d963 100644
--- a/tor-design-2012.tex
+++ b/tor-design-2012.tex
@@ -756,12 +756,21 @@ open many TCP streams.
In Tor, each circuit can be shared by many TCP streams. To
avoid delays, users construct circuits preemptively.
% Clarify: OPs construct circuits preemptively, not users. -NM
-To limit
-linkability among their streams, users' OPs build a new circuit
-periodically if the previous ones have been used, and expire old
-used circuits that no longer have any open streams.
+To limit linkability among their streams, the user's OP will not
+assign a new stream to a circuit if the circuit has previously
+carried a stream which the user has indicated should be separate
+from the new one. By default, a user signals that two streams
+should not be linkable by making SOCKS connections to different
+ports, from a different IP address, or with different SOCKS
+authentication credentials. Even when a stream would otherwise
+be permitted to be carried by a circuit, if the circuit's first
+stream was created more than 10 minutes (by default) ago, that
+circuit will not be considered for re-use and closed once there
+are no remaining streams, then the OP will build a new circuit
+preemptively.
% Also mention that there are mechanisms that applications can use
% to signal that streams shouldn't be sent over the same circuit. -NM
+% Believed done -SJM
OPs
consider rotating to a new circuit once a minute: thus even
heavy users spend negligible time building circuits, but a
@@ -939,24 +948,40 @@ resolve it into an IP address first and then pass the IP address
to the Tor client. If the application does DNS resolution first,
Alice thereby reveals her destination to the remote DNS server,
rather than sending the hostname through the Tor network to be
-resolved at the far end. Common applications like Mozilla and
-SSH have this flaw.
+resolved at the far end. Common applications like Firefox and
+SSH need to be configured to use SOCKS4A or SOCKS5 (with the
+option to send hostnames rather than IP address) to avoid this
+vulnerability.
% No longer true wrt mozilla and SSH. -NM
+% Believed done -SJM
-With Mozilla, the flaw is easy to address: the filtering HTTP
-proxy called Privoxy gives a hostname to the Tor client, so
-Alice's computer never does DNS resolution. But a portable
-general solution, such as is needed for SSH, is an open
-problem. Modifying or replacing the local nameserver can be
-invasive, brittle, and unportable. Forcing the resolver library
-to prefer TCP rather than UDP is hard, and also has portability
-problems. Dynamically intercepting system calls to the resolver
-library seems a promising direction. We could also provide a
-tool similar to \emph{dig} to perform a private lookup through
-the Tor network. Currently, we encourage the use of
-privacy-aware proxies like Privoxy wherever possible.
+With Firefox, the Torbutton add-on ensures that the browser
+sends requests via Tor by configuring Firefox to correctly use a
+SOCKS proxy. However, this is not in itself sufficient to
+provide private web browsing, because the browser provides many
+ways for a malicious site to link separate accesses to being
+from the from the same user. Therefore Torbutton and patches
+applied to the version of Firefox delivered with Tor also
+restrict tracking capabilities -- both intended ones (such as
+cookies, and more modern variants like DOM storage) and
+unintended channels (such as TLS session IDs), normalizes
+browser characteristics accessible from Javascript (such as
+screen size and system colors), and blocks plugins which may
+leak identifying information. Previously the Privoxy filtering
+proxy was used for this purpose, but its major weakness is that
+it is unable to protect the user from being tracked over HTTPS
+because a proxy sees only encrypted content.
+
+Other applications, which can be configured to use SOCKS (and
+send the proxy a hostname rather than IP address), may be
+connected directly to Tor. Other options available are to
+intercept calls to the resolver and sockets libraries with
+\emph{torsocks} or to use a firewall (Tor supports BSD and
+Linux's in-built firewall) to intercept outgoing DNS requests
+and TCP connections, sending them via Tor.
% We don't recommend privoxy any more. Proxies are one solution though. But
% for web, we think you need a custom browser. -NM
+% Believed done -SJM
Closing a Tor stream is analogous to closing a TCP stream: it
uses a two-step handshake for normal operation, or a one-step
@@ -1042,6 +1067,11 @@ their bandwidth usage. To accommodate them, Tor servers use a
token bucket approach~\cite{tannenbaum96} to
enforce a long-term average rate of incoming bytes, while still
permitting short-term bursts above the allowed bandwidth.
+To accommodate volunteers who are charged when their daily,
+weekly, or monthly bandwidth usage exceeds a limit, Tor servers
+can be configured to ``hibernate'', closing existing connections
+and refusing new ones, once the limit has been reached. The
+server will become usable again at the start of the next period.
Because the Tor protocol outputs about the same number of bytes
as it takes in, it is sufficient in practice to limit only
@@ -1052,19 +1082,20 @@ because the local application may be awaiting a reply.)
Therefore, we treat this case as if the entire cell size had
been read, regardless of the cell's fullness.
-Further, inspired by Rennhard et al's design in~\cite{anonnet},
-a circuit's edges can heuristically distinguish interactive
-streams from bulk streams by comparing the frequency with which
-they supply cells. We can provide good latency for interactive
-streams by giving them preferential service, while still giving
-good overall throughput to the bulk streams. Such preferential
-treatment presents a possible end-to-end attack, but an
-adversary observing both ends of the stream can already learn
-this information through timing attacks.
-% I don't think we do anything like what we had in mind when we wrote the
-% above paragraph. -NM
+To provide good latency for interactive service, Tor chooses
+which cells to deliver favouring circuits that had been quiet
+recently. Specifically, when Tor is about to put a cell on an
+outgoing connection it chooses the circuit which has sent the
+lowest total exponentially-decaying number of cells so far.
+Currently each cell has a 30-second half-life. Such
+preferential treatment presents a possible end-to-end attack,
+but an adversary observing both ends of the stream can already
+learn this information through timing attacks.
+% I don't think we do anything like what we had in mind when we
+% wrote the above paragraph. -NM
% We should mention EWMA in this section. -NM
+% Believed done -SJM
\subsection{Congestion control}
\label{subsec:congestion}
@@ -1153,15 +1184,21 @@ not require them to modify their applications.
We provide location-hiding for Bob by allowing him to advertise
several onion routers (his \emph{introduction points}) as
-contact points. He may do this on any robust efficient key-value
-lookup system with authenticated updates, such as a distributed
-hash table (DHT) like CFS~\cite{cfs:sosp01}.\footnote{ Rather
- than rely on an external infrastructure, the Onion Routing
- network can run the lookup service itself. Our current
- implementation provides a simple lookup system on the
- directory servers.}
+contact points, in a distributed hash table (DHT). He does this
+by publishing the hidden service descriptor (containing
+introduction point's addresses) to the ORs whose identity keys
+are closest to a hash of the location-hidden service's identity
+key, the current date, and a replica number. Optionally, the
+hidden service descriptor can be encrypted under a key shared
+with authorized users of the hidden service. Therefore not only
+can unauthorized users not connect to the hidden service or its
+introduction points (the descriptor contains an authentication
+credential), they also cannot discover whether the hidden
+service is online.
% We eventually went and built a distributed directory in Tor to deal with
% this. -NM
+% Believed done -SJM
+
Alice, the client, chooses an OR as her
\emph{rendezvous point}. She connects to one of Bob's
introduction points, informs him of her rendezvous point, and
@@ -1175,6 +1212,7 @@ also allows Bob to respond to some requests and ignore others.
% Mention that the list of introduction points can now be encrypted. -NM
% Mention user authentication? -NM
+% Believed done -SJM
\subsection{Rendezvous points in Tor}
@@ -1344,6 +1382,31 @@ other users when they build new circuits.
% What about link-to-link rate limiting?
+The Tor network itself can be exploited as a DoS amplifier,
+because for every relay cell sent into an OP, a cell is
+generated at each hop on the circuit. An adversary could create
+a long path, potentially going through the same node many times,
+and overload CPU or network resources with only a small
+investment of both. To resist this attack, the length of a path
+is limited to 8, enforced by the distinction between
+\emph{relay} and \emph{relay\_early} cells. Incoming
+\emph{relay\_early} cells may contain any type of relay cell but
+if they are not destined for the OR which receives them, result
+in a further \emph{relay\_early} cell being generated.
+Only 8 \emph{Relay\_early} cells are permitted to be sent on a
+circuit. Similarly \emph{relay} cells result in a \emph{relay}
+cell being created, and may be sent without limit, but
+\emph{relay} cells cannot contain an extend request. In this
+way, intermediate ORs cannot know how long the path length is
+(they always see up to 8 \emph{relay\_early} cells, and don't
+know what they contain) but an OP cannot send more than 8 extend
+requests and so cannot generate a path of longer than 8 hops.
+This does not however prevent an adversary tunneling Tor over
+Tor, and connecting from an exit node back to the Tor network.
+
+% Mention long-path defense -NM
+% Believed done -SJM
+
Adversaries can also attack the Tor network's hosts and network
links. Disrupting a single circuit or link breaks all streams
passing along that part of the circuit. Users similarly lose
@@ -1357,8 +1420,6 @@ require more buffering at the network edges, however, and the
performance and anonymity implications from this extra
complexity still require investigation.
-% Mention long-path defense -NM
-
% Mention asymmetries in protocols, where a little effort from an attacker
% can make Tor do more calculation. That's bad. -NM
@@ -1412,22 +1473,28 @@ limited set of services, such as HTTP, SSH, or AIM. This is not
a complete solution, of course, since abuse opportunities for
these protocols are still well known.
-We have not yet encountered any abuse in the deployed network,
-but if we do we should consider using proxies to clean traffic
-for certain protocols as it leaves the network. For example,
-much abusive HTTP behavior (such as exploiting buffer overflows
-or well-known script vulnerabilities) can be detected in a
-straightforward manner. Similarly, one could run automatic spam
-filtering software (such as SpamAssassin) on email exiting the
-OR network.
+%We have not yet encountered any abuse in the deployed network,
+%but if we do we should consider using proxies to clean traffic
+%for certain protocols as it leaves the network. For example,
+%much abusive HTTP behavior (such as exploiting buffer overflows
+%or well-known script vulnerabilities) can be detected in a
+%straightforward manner. Similarly, one could run automatic spam
+%filtering software (such as SpamAssassin) on email exiting the
+%OR network.
% Above paragraph is no longer true at all even a little -NM
-
-ORs may also rewrite exiting traffic to append headers or other
-information indicating that the traffic has passed through an
-anonymity service. This approach is commonly used by email-only
-anonymity systems. ORs can also run on servers with hostnames
-like {\tt anonymous} to further alert abuse targets to the
-nature of the anonymous traffic.
+% Removed for now -SJM
+
+To manage the abuse potential, The Tor Project operates a DNS
+blacklist system, allowing service operators to easily identify
+whether a particular incoming connection may have arrived over
+the Tor network. The service may then choose to block the
+connection, subject it to extra scrutiny, or restrict the rights
+of the user who is connecting via Tor (such as giving read-only,
+rather than read-write, access to a wiki). A similar service
+also allows retrospective queries over the list of exit nodes to
+allow exit-node operators to show that their computer was an
+exit node at the time an abusive connection was made, and
+therefore that they should not be liable for any harm cause.
A mixture of open and restricted exit nodes allows the most
flexibility for volunteers running servers. But while having
1
0

[ooni-probe/master] Refactor DNS Tamper test to use twisted.name.client.queryUDP
by art@torproject.org 06 Nov '12
by art@torproject.org 06 Nov '12
06 Nov '12
commit 769cd3cbbd8521af505f2b740af8468b1a347f2f
Author: Arturo Filastò <arturo(a)filasto.net>
Date: Tue Nov 6 18:48:57 2012 +0100
Refactor DNS Tamper test to use twisted.name.client.queryUDP
* Add a "Error: " prefix to utils/log.py
* Make some changes to before_i_commit script
---
before_i_commit.sh | 10 +++++
nettests/core/dnstamper.py | 87 +++++++++++++++++++++++++++-----------------
ooni/reporter.py | 1 +
ooni/runner.py | 3 ++
ooni/utils/log.py | 2 +-
5 files changed, 69 insertions(+), 34 deletions(-)
diff --git a/before_i_commit.sh b/before_i_commit.sh
index 2816ea5..1bf96a3 100755
--- a/before_i_commit.sh
+++ b/before_i_commit.sh
@@ -10,6 +10,8 @@
# rm *.yamloo; rm before_i_commit.log
#
+rm before_i_commit.log
+
find . -type f -name "*.py[co]" -delete
./bin/ooniprobe -l before_i_commit.log -o url_lists.yamloo nettests/core/url_list.py -f test_inputs/url_lists_file.txt
@@ -24,4 +26,12 @@ find . -type f -name "*.py[co]" -delete
./bin/ooniprobe -l before_i_commit.log -o url_lists.yamloo nettests/core/url_list.py -f test_inputs/url_lists_file.txt
+echo "Below you should not see anything"
+echo "---------------------------------"
+grep "Error: " before_i_commit.log
+echo "---------------------------------"
+echo "If you do, it means something is wrong."
+echo "Read through the log file and fix it."
+echo "If you are having some problems fixing some things that have to do with"
+echo "the core of OONI, let's first discuss it on IRC, or open a ticket"
diff --git a/nettests/core/dnstamper.py b/nettests/core/dnstamper.py
index da1878c..b25167f 100644
--- a/nettests/core/dnstamper.py
+++ b/nettests/core/dnstamper.py
@@ -15,12 +15,16 @@
# :authors: Arturo Filastò, Isis Lovecruft
# :licence: see LICENSE
-from ooni import nettest
-from ooni.utils import log
+import pdb
+
from twisted.internet import defer
-from twisted.names import client
+from twisted.names import client, dns
+from twisted.names.client import Resolver
from twisted.names.error import DNSQueryRefusedError
+from ooni import nettest
+from ooni.utils import log
+
class DNSTamperTest(nettest.NetTestCase):
name = "DNS tamper"
@@ -32,10 +36,13 @@ class DNSTamperTest(nettest.NetTestCase):
inputFile = ['file', 'f', None,
'Input file of list of hostnames to attempt to resolve']
- optParameters = [['controlresolver', 'c', '8.8.8.8',
- 'Known good DNS server'],
+ optParameters = [['controlresolver', 'b', '8.8.8.8',
+ 'The OONI backend that runs the DNS resolver'],
+ ['controlresolver-port', 'p', 53,
+ 'The port of the good DNS resolver'],
['testresolvers', 't', None,
- 'file containing list of DNS resolvers to test against']]
+ 'file containing list of DNS resolvers to test against']
+ ]
def setUp(self):
self.report['test_lookups'] = {}
@@ -63,31 +70,36 @@ class DNSTamperTest(nettest.NetTestCase):
self.test_resolvers = [x.strip() for x in fp.readlines()]
fp.close()
- def process_a_answers(self, answers, resolver):
- log.msg("Processing A answers for %s" % resolver)
+ def process_a_answers(self, message, resolver_address):
+ log.msg("Processing A answers for %s" % resolver_address)
+ log.debug("These are the answers I got %s" % message.answers)
+
all_a = []
a_a = []
- for answer in answers[0]:
+
+ for answer in message.answers:
if answer.type is 1:
# A type query
r = answer.payload.dottedQuad()
- self.report['a_lookups'][resolver] = r
+ self.report['a_lookups'][resolver_address] = r
a_a.append(r)
lookup = str(answer.payload)
all_a.append(lookup)
- if resolver == 'control':
+ if resolver_address == 'control':
self.report['control_server'] = self.localOptions['controlresolver']
self.report['control_lookup'] = all_a
self.control_a_lookups = a_a
else:
- self.test_a_lookups[resolver] = a_a
- self.report['test_lookups'][resolver] = all_a
+ self.test_a_lookups[resolver_address] = a_a
+ self.report['test_lookups'][resolver_address] = all_a
+
log.msg("Done")
def process_ptr_answers(self, answers, resolver):
log.msg("Processing PTR answers for %s" % resolver)
name = None
+
for answer in answers[0]:
if answer.type is 12:
# PTR type
@@ -101,9 +113,9 @@ class DNSTamperTest(nettest.NetTestCase):
self.report['test_reverse'][resolver] = name
def ptr_lookup_error(self, failure, resolver):
- #def ptr_lookup_error(self, *arg, **kw):
log.msg("There was an error in PTR lookup %s" % resolver)
- log.msg(failure)
+ log.err(failure)
+
if resolver == 'control':
self.report['control_reverse'] = None
else:
@@ -111,6 +123,7 @@ class DNSTamperTest(nettest.NetTestCase):
def a_lookup_error(self, failure, resolver):
log.msg("There was an error in A lookup %s" % resolver)
+ log.err(failure)
if failure.type is DNSQueryRefusedError:
self.report['tampering'][resolver] = 'connection-refused'
@@ -145,34 +158,40 @@ class DNSTamperTest(nettest.NetTestCase):
log.msg("Doing the test lookups on %s" % self.input)
list_of_ds = []
hostname = self.input
+ dns_query = [dns.Query(hostname, dns.IN, dns.A)]
+ dns_server = [(self.localOptions['controlresolver'],
+ self.localOptions['controlresolver-port'])]
- resolver = [(self.localOptions['controlresolver'], 53)]
- res = client.createResolver(servers=resolver, resolvconf='')
+ resolver = Resolver(servers=dns_server)
- control_r = res.lookupAddress(hostname, timeout=self.lookupTimeout)
- control_r.addCallback(self.process_a_answers, 'control')
- control_r.addErrback(self.a_lookup_error, 'control')
+ control_d = resolver.queryUDP(dns_query, timeout=self.lookupTimeout)
+ control_d.addCallback(self.process_a_answers, 'control')
+ control_d.addErrback(self.a_lookup_error, 'control')
for test_resolver in self.test_resolvers:
log.msg("Going for %s" % test_resolver)
- resolver = [(test_resolver, 53)]
- res = client.createResolver(servers=resolver, resolvconf='')
- #res = self.createResolver(servers=resolver)
+ dns_server = [(test_resolver, 53)]
+
+ resolver = Resolver(servers=dns_server)
- d = res.lookupAddress(hostname, timeout=self.lookupTimeout)
+ d = resolver.queryUDP(dns_query, timeout=self.lookupTimeout)
d.addCallback(self.process_a_answers, test_resolver)
d.addErrback(self.a_lookup_error, test_resolver)
+
+ # This is required to cancel the delayed calls of the
+ # twisted.names.client resolver
list_of_ds.append(d)
- list_of_ds.append(control_r)
+ list_of_ds.append(control_d)
dl = defer.DeferredList(list_of_ds)
dl.addCallback(self.do_reverse_lookups)
dl.addBoth(self.compare_results)
return dl
def reverse_lookup(self, address, resolver):
+ query = [dns.Query(hostname, dns.IN, dns.PTR)]
ptr = '.'.join(address.split('.')[::-1]) + '.in-addr.arpa'
- r = resolver.lookupPointer(ptr, self.lookupTimeout)
+ r = resolver.queryUDP(query, timeout=self.lookupTimeout)
return r
def do_reverse_lookups(self, result):
@@ -186,12 +205,14 @@ class DNSTamperTest(nettest.NetTestCase):
"""
log.msg("Doing the reverse lookups %s" % self.input)
list_of_ds = []
+ dns_server = [(self.localOptions['controlresolver'],
+ self.localOptions['controlresolver-port'])]
- resolver = [(self.localOptions['controlresolver'], 53)]
- res = self.createResolver(servers=resolver)
+ resolver = Resolver(servers=dns_server)
- test_reverse = self.reverse_lookup(self.control_a_lookups[0], res,
+ test_reverse = self.reverse_lookup(self.control_a_lookups[0], resolver,
timeout=self.lookupTimeout)
+
test_reverse.addCallback(self.process_ptr_answers, 'control')
test_reverse.addErrback(self.ptr_lookup_error, 'control')
@@ -228,17 +249,17 @@ class DNSTamperTest(nettest.NetTestCase):
continue
if set(test_a_lookups) & set(self.control_a_lookups):
- # Address has not tampered with on DNS server
+ log.msg("Address has not tampered with on DNS server")
self.report['tampering'][test] = False
elif self.control_reverse and set([self.control_reverse]) \
& set([self.report['test_reverse'][test]]):
- # Further testing has eliminated false positives
+ log.msg("Further testing has eliminated false positives")
self.report['tampering'][test] = 'reverse-match'
else:
- # Reverse DNS on the results returned by returned
- # which does not match the expected domainname
+ log.msg("Reverse DNS on the results returned by returned")
+ log.msg("which does not match the expected domainname")
self.report['tampering'][test] = True
if len(self.test_a_lookups) == len(self.test_resolvers):
diff --git a/ooni/reporter.py b/ooni/reporter.py
index 8c0b593..ad7956d 100644
--- a/ooni/reporter.py
+++ b/ooni/reporter.py
@@ -209,6 +209,7 @@ class ReporterFactory(OReporter):
'test_name': options['name'],
'test_version': options['version'],
}
+
self.writeYamlLine(test_details)
self._writeln('')
diff --git a/ooni/runner.py b/ooni/runner.py
index 97b4003..fa50840 100644
--- a/ooni/runner.py
+++ b/ooni/runner.py
@@ -19,9 +19,12 @@ from twisted.trial.runner import filenameToModule
from ooni.inputunit import InputUnitFactory
from ooni.nettest import InputTestSuite
+
from ooni.plugoo import tests as oonitests
+
from ooni.reporter import ReporterFactory
from ooni.utils import log, date
+
from ooni.utils.legacy import LegacyOONITest
from ooni.utils.legacy import start_legacy_test, adapt_legacy_test
diff --git a/ooni/utils/log.py b/ooni/utils/log.py
index 771bad8..d1f308e 100644
--- a/ooni/utils/log.py
+++ b/ooni/utils/log.py
@@ -48,7 +48,7 @@ def debug(msg, *arg, **kw):
txlog.msg(msg, logLevel=logging.DEBUG, *arg, **kw)
def err(msg, *arg, **kw):
- txlog.err(msg, logLevel=logging.ERROR, *arg, **kw)
+ txlog.err("Error: " + msg, logLevel=logging.ERROR, *arg, **kw)
def exception(*msg):
logging.exception(msg)
1
0
commit 142450fc68d8df967bc99b632154f43d4b2e3451
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Nov 6 08:56:44 2012 -0800
Including exceptions in api docs
Moving the exceptions to stem/__init__.py meant that they were no longer
covered my any of our automodule declarations. Adding a special 'Exceptions'
section to the controller's api page.
---
docs/api/control.rst | 5 +++++
stem/__init__.py | 8 ++++++++
2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/docs/api/control.rst b/docs/api/control.rst
index 45a3439..0a17d9e 100644
--- a/docs/api/control.rst
+++ b/docs/api/control.rst
@@ -3,3 +3,8 @@ Controller
.. automodule:: stem.control
+Exceptions
+----------
+
+.. automodule:: stem
+
diff --git a/stem/__init__.py b/stem/__init__.py
index 4146dff..dd0061f 100644
--- a/stem/__init__.py
+++ b/stem/__init__.py
@@ -32,6 +32,14 @@ __all__ = [
"process",
"socket",
"version",
+ "ControllerError",
+ "ProtocolError",
+ "OperationFailed",
+ "UnsatisfiableRequest",
+ "InvalidRequest",
+ "InvalidArguments",
+ "SocketError",
+ "SocketClosed",
]
class ControllerError(Exception):
1
0

06 Nov '12
commit 2a597415c0a8ca8203ee0282103ef0c606f1d887
Author: Eoin o Fearghail <eoin.o.fearghail(a)gmail.com>
Date: Mon Nov 5 22:54:02 2012 +0000
Squashed all my spelling changes into one commit
---
stem/connection.py | 5 ++---
stem/control.py | 6 +++---
stem/descriptor/extrainfo_descriptor.py | 4 ++--
stem/descriptor/networkstatus.py | 4 ++--
stem/descriptor/reader.py | 4 ++--
stem/descriptor/router_status_entry.py | 2 +-
stem/descriptor/server_descriptor.py | 6 +++---
stem/response/__init__.py | 8 ++++----
stem/response/getconf.py | 2 +-
stem/util/conf.py | 4 ++--
stem/util/enum.py | 2 +-
stem/util/system.py | 2 +-
test/prompt.py | 2 +-
test/unit/descriptor/server_descriptor.py | 2 +-
14 files changed, 26 insertions(+), 27 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index fa41c67..6264be4 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -4,7 +4,7 @@ Functions for connecting and authenticating to the tor process.
The :func:`~stem.connection.connect_port` and
:func:`~stem.connection.connect_socket_file` functions give an easy, one line
method for getting an authenticated control connection. This is handy for CLI
-applications and the python interactive interpretor, but does several things
+applications and the python interactive interpreter, but does several things
that makes it undesirable for applications (uses stdin/stdout, suppresses
exceptions, etc).
@@ -489,8 +489,7 @@ def authenticate_password(controller, password, suppress_ctl_errors = True):
except: pass
# all we have to go on is the error message from tor...
- # Password did not match HashedControlPassword value value from configuration...
- # Password did not match HashedControlPassword *or*...
+ # ...Password did not match HashedControlPassword.
if "Password did not match HashedControlPassword" in str(auth_response):
raise IncorrectPassword(str(auth_response), auth_response)
diff --git a/stem/control.py b/stem/control.py
index af5c8ee..02afa33 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -79,7 +79,7 @@ State = stem.util.enum.Enum("INIT", "RESET", "CLOSED")
UNDEFINED = "<Undefined_ >"
# Configuration options that are fetched by a special key. The keys are
-# lowercase to make case insensetive lookups easier.
+# lowercase to make case insensitive lookups easier.
MAPPED_CONFIG_KEYS = {
"hiddenservicedir": "HiddenServiceOptions",
@@ -107,9 +107,9 @@ CACHEABLE_GETINFO_PARAMS = (
# is unavailable
GEOIP_FAILURE_THRESHOLD = 5
-# TODO: The Thread's isAlive() method and theading's currentThread() was
+# TODO: The Thread's isAlive() method and threading's currentThread() was
# changed to the more conventional is_alive() and current_thread() in python
-# 2.6 and above. We should use that when dropping python 2.5 compatability.
+# 2.6 and above. We should use that when dropping python 2.5 compatibility.
class BaseController(object):
"""
diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py
index 2bf76e3..76adfbf 100644
--- a/stem/descriptor/extrainfo_descriptor.py
+++ b/stem/descriptor/extrainfo_descriptor.py
@@ -280,7 +280,7 @@ class ExtraInfoDescriptor(stem.descriptor.Descriptor):
def __init__(self, raw_contents, validate = True):
"""
Extra-info descriptor constructor. By default this validates the
- descriptor's content as it's parsed. This validation can be disables to
+ descriptor's content as it's parsed. This validation can be disabled to
either improve performance or be accepting of malformed data.
:param str raw_contents: extra-info content provided by the relay
@@ -419,7 +419,7 @@ class ExtraInfoDescriptor(stem.descriptor.Descriptor):
if not stem.util.tor_tools.is_valid_nickname(extra_info_comp[0]):
raise ValueError("Extra-info line entry isn't a valid nickname: %s" % extra_info_comp[0])
elif not stem.util.tor_tools.is_valid_fingerprint(extra_info_comp[1]):
- raise ValueError("Tor relay fingerprints consist of fourty hex digits: %s" % extra_info_comp[1])
+ raise ValueError("Tor relay fingerprints consist of forty hex digits: %s" % extra_info_comp[1])
self.nickname = extra_info_comp[0]
self.fingerprint = extra_info_comp[1]
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 893129b..5649d53 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -14,8 +14,8 @@ dir-spec. Documents can be obtained from a few sources...
* document footer
Of these, the router status entry section can be quite large (on the order of
-hundreds of kilobytes). As such we provide a couple methods of reading network
-status documents...
+hundreds of kilobytes). As such we provide a couple of methods for reading
+network status documents...
* :class:`stem.descriptor.networkstatus.NetworkStatusDocumentV3` constructor
diff --git a/stem/descriptor/reader.py b/stem/descriptor/reader.py
index c03b996..5ded34d 100644
--- a/stem/descriptor/reader.py
+++ b/stem/descriptor/reader.py
@@ -35,7 +35,7 @@ and picks up where it left off if ran again...
try:
processed_files = load_processed_files("/tmp/used_descriptors")
reader.set_processed_files(processed_files)
- except: pass # could not load, mabye this is the first run
+ except: pass # could not load, maybe this is the first run
start_time = time.time()
@@ -89,7 +89,7 @@ FINISHED = "DONE"
# TODO: The threading.Event's isSet() method was changed to the more
# conventional is_set() in python 2.6 and above. We should use that when
-# dropping python 2.5 compatability...
+# dropping python 2.5 compatibility...
# http://docs.python.org/library/threading.html#threading.Event.is_set
class FileSkipped(Exception):
diff --git a/stem/descriptor/router_status_entry.py b/stem/descriptor/router_status_entry.py
index 95f955b..239e6bb 100644
--- a/stem/descriptor/router_status_entry.py
+++ b/stem/descriptor/router_status_entry.py
@@ -29,7 +29,7 @@ def parse_file(document_file, validate, entry_class, entry_keyword = "r", start_
first line (entry_keyword). When finished the document is left at the
end_position.
- Either a end_position or section_end_keywords must be provided.
+ Either an end_position or section_end_keywords must be provided.
:param file document_file: file with network status document content
:param bool validate: checks the validity of the document's contents if
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index f8cdb00..68b2da3 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -400,7 +400,7 @@ class ServerDescriptor(stem.descriptor.Descriptor):
if validate:
raise ValueError("Published line's time wasn't parseable: %s" % line)
elif keyword == "fingerprint":
- # This is fourty hex digits split into space separated groups of four.
+ # This is forty hex digits split into space separated groups of four.
# Checking that we match this pattern.
fingerprint = value.replace(" ", "")
@@ -426,11 +426,11 @@ class ServerDescriptor(stem.descriptor.Descriptor):
elif keyword == "caches-extra-info":
self.extra_info_cache = True
elif keyword == "extra-info-digest":
- # this is fourty hex digits which just so happens to be the same a
+ # this is forty hex digits which just so happens to be the same a
# fingerprint
if validate and not stem.util.tor_tools.is_valid_fingerprint(value):
- raise ValueError("Extra-info digests should consist of fourty hex digits: %s" % value)
+ raise ValueError("Extra-info digests should consist of forty hex digits: %s" % value)
self.extra_info_digest = value
elif keyword == "hidden-service-dir":
diff --git a/stem/response/__init__.py b/stem/response/__init__.py
index bd73f85..fb6c63f 100644
--- a/stem/response/__init__.py
+++ b/stem/response/__init__.py
@@ -266,7 +266,7 @@ class ControlLine(str):
:returns: **True** if the next entry can be parsed as a quoted value, **False** otherwise
"""
- start_quote, end_quote = _get_quote_indeces(self._remainder, escaped)
+ start_quote, end_quote = _get_quote_indices(self._remainder, escaped)
return start_quote == 0 and end_quote != -1
def is_next_mapping(self, key = None, quoted = False, escaped = False):
@@ -290,7 +290,7 @@ class ControlLine(str):
if quoted:
# checks that we have a quoted value and that it comes after the 'key='
- start_quote, end_quote = _get_quote_indeces(remainder, escaped)
+ start_quote, end_quote = _get_quote_indices(remainder, escaped)
return start_quote == key_match.end() and end_quote != -1
else:
return True # we just needed to check for the key
@@ -399,7 +399,7 @@ def _parse_entry(line, quoted, escaped):
if quoted:
# validate and parse the quoted value
- start_quote, end_quote = _get_quote_indeces(remainder, escaped)
+ start_quote, end_quote = _get_quote_indices(remainder, escaped)
if start_quote != 0 or end_quote == -1:
raise ValueError("the next entry isn't a quoted value: " + line)
@@ -416,7 +416,7 @@ def _parse_entry(line, quoted, escaped):
return (next_entry, remainder.lstrip())
-def _get_quote_indeces(line, escaped):
+def _get_quote_indices(line, escaped):
"""
Provides the indices of the next two quotes in the given content.
diff --git a/stem/response/getconf.py b/stem/response/getconf.py
index 72bfc34..6d396b8 100644
--- a/stem/response/getconf.py
+++ b/stem/response/getconf.py
@@ -42,7 +42,7 @@ class GetConfResponse(stem.response.ControlMessage):
if line.is_next_mapping(quoted = False):
key, value = line.split("=", 1) # TODO: make this part of the ControlLine?
elif line.is_next_mapping(quoted = True):
- # TODO: doesn't seem to occure yet in practice...
+ # TODO: doesn't seem to occur yet in practice...
# https://trac.torproject.org/6172
key, value = line.pop_mapping(True).items()[0]
diff --git a/stem/util/conf.py b/stem/util/conf.py
index 9c15973..cc80cb8 100644
--- a/stem/util/conf.py
+++ b/stem/util/conf.py
@@ -16,7 +16,7 @@ For instance...
# This is my sample config
user.name Galen
user.password yabba1234 # here's an inline comment
- user.notes takes a fancy to pepperjack chese
+ user.notes takes a fancy to pepperjack cheese
blankEntry.example
msg.greeting
@@ -30,7 +30,7 @@ For instance...
config = {
"user.name": "Galen",
"user.password": "yabba1234",
- "user.notes": "takes a fancy to pepperjack chese",
+ "user.notes": "takes a fancy to pepperjack cheese",
"blankEntry.example": "",
"msg.greeting": "Multi-line message exclaiming of the\\nwonder and awe that is pepperjack!",
}
diff --git a/stem/util/enum.py b/stem/util/enum.py
index 42ca7ea..f120e5c 100644
--- a/stem/util/enum.py
+++ b/stem/util/enum.py
@@ -30,7 +30,7 @@ constructed as simple type listings...
Enum - Provides a basic, ordered enumeration
|- keys - string representation of our enum keys
- |- index_of - indice of an enum value
+ |- index_of - index of an enum value
|- next - provides the enum after a given enum value
|- previous - provides the enum before a given value
|- __getitem__ - provides the value for an enum key
diff --git a/stem/util/system.py b/stem/util/system.py
index 85c8faf..2b8eb14 100644
--- a/stem/util/system.py
+++ b/stem/util/system.py
@@ -415,7 +415,7 @@ def get_pid_by_open_file(path):
def get_cwd(pid):
"""
- Provices the working directory of the given process.
+ Provides the working directory of the given process.
:param int pid: process id of the process to be queried
:returns: **str** with the absolute path for the process' present working
diff --git a/test/prompt.py b/test/prompt.py
index 91ad6d3..290cd6e 100644
--- a/test/prompt.py
+++ b/test/prompt.py
@@ -1,5 +1,5 @@
"""
-Simple helper methods to make troubleshooting with the python interpretor
+Simple helper methods to make troubleshooting with the python interpreter
easier.
::
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index 39be157..fc81851 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -161,7 +161,7 @@ class TestServerDescriptor(unittest.TestCase):
def test_read_and_write_history(self):
"""
- Parses a read-history and write-history entry. This is now a depricated
+ Parses a read-history and write-history entry. This is now a deprecated
field for relay server descriptors but is still found in archives and
extra-info descriptors.
"""
1
0

06 Nov '12
commit a5c5ae8c3af4409b8fcac10a38b21a37723237c9
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Nov 6 08:09:06 2012 -0800
Reverting comment change about tor error messages
The prior spelling fixes condensed a comment that we had about the error
message tor will provide when we use the wrong controller password. The change
makes sense, but these lines are here to tell us the exact error message tor
provides (after which it's hopefully reasonably obvious why we check for the
"Password did not match HashedControlPassword" part of it).
---
stem/connection.py | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index 6264be4..20f0d84 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -489,7 +489,8 @@ def authenticate_password(controller, password, suppress_ctl_errors = True):
except: pass
# all we have to go on is the error message from tor...
- # ...Password did not match HashedControlPassword.
+ # Password did not match HashedControlPassword value value from configuration...
+ # Password did not match HashedControlPassword *or*...
if "Password did not match HashedControlPassword" in str(auth_response):
raise IncorrectPassword(str(auth_response), auth_response)
1
0

[stem/master] Changing spelling of parseable to parsable, also one tiny whitespace fix.
by atagar@torproject.org 06 Nov '12
by atagar@torproject.org 06 Nov '12
06 Nov '12
commit bb0a3ace259e4f23eb53837908a3163c1c19e305
Author: Eoin o Fearghail <eoin.o.fearghail(a)gmail.com>
Date: Tue Nov 6 00:00:51 2012 +0000
Changing spelling of parseable to parsable, also one tiny whitespace fix.
---
stem/descriptor/extrainfo_descriptor.py | 4 ++--
stem/descriptor/networkstatus.py | 10 +++++-----
stem/descriptor/router_status_entry.py | 2 +-
stem/descriptor/server_descriptor.py | 2 +-
test/unit/descriptor/networkstatus/document_v3.py | 2 +-
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py
index 76adfbf..1bb8dac 100644
--- a/stem/descriptor/extrainfo_descriptor.py
+++ b/stem/descriptor/extrainfo_descriptor.py
@@ -173,7 +173,7 @@ def _parse_timestamp_and_interval(keyword, content):
timestamp = datetime.datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S")
return timestamp, int(interval), remainder
except ValueError:
- raise ValueError("%s line's timestamp wasn't parseable: %s" % (keyword, line))
+ raise ValueError("%s line's timestamp wasn't parsable: %s" % (keyword, line))
class ExtraInfoDescriptor(stem.descriptor.Descriptor):
"""
@@ -589,7 +589,7 @@ class ExtraInfoDescriptor(stem.descriptor.Descriptor):
self.geoip_start_time = timestamp
except ValueError:
if validate:
- raise ValueError("Timestamp on %s line wasn't parseable: %s" % (keyword, line))
+ raise ValueError("Timestamp on %s line wasn't parsable: %s" % (keyword, line))
elif keyword in ("cell-stats-end", "entry-stats-end", "exit-stats-end", "bridge-stats-end", "dirreq-stats-end"):
# "<keyword>" YYYY-MM-DD HH:MM:SS (NSEC s)
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 5649d53..0c08611 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -14,7 +14,7 @@ dir-spec. Documents can be obtained from a few sources...
* document footer
Of these, the router status entry section can be quite large (on the order of
-hundreds of kilobytes). As such we provide a couple of methods for reading
+hundreds of kilobytes). As such we provide a couple of methods for reading
network status documents...
* :class:`stem.descriptor.networkstatus.NetworkStatusDocumentV3` constructor
@@ -366,7 +366,7 @@ class NetworkStatusDocumentV2(NetworkStatusDocument):
self.published = datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
except ValueError:
if validate:
- raise ValueError("Version 2 network status document's 'published' time wasn't parseable: %s" % value)
+ raise ValueError("Version 2 network status document's 'published' time wasn't parsable: %s" % value)
elif keyword == "dir-options":
self.options = value.split()
elif keyword == "directory-signature":
@@ -628,7 +628,7 @@ class _DocumentHeader(object):
self.valid_until = date_value
except ValueError:
if validate:
- raise ValueError("Network status document's '%s' time wasn't parseable: %s" % (keyword, value))
+ raise ValueError("Network status document's '%s' time wasn't parsable: %s" % (keyword, value))
elif keyword == "voting-delay":
# "voting-delay" VoteSeconds DistSeconds
@@ -650,7 +650,7 @@ class _DocumentHeader(object):
self.server_versions.append(version_value)
except ValueError:
if validate:
- raise ValueError("Network status document's '%s' line had '%s', which isn't a parseable tor version: %s" % (keyword, entry, line))
+ raise ValueError("Network status document's '%s' line had '%s', which isn't a parsable tor version: %s" % (keyword, entry, line))
elif keyword == "known-flags":
# "known-flags" FlagList
@@ -1192,7 +1192,7 @@ class KeyCertificate(stem.descriptor.Descriptor):
self.expires = date_value
except ValueError:
if validate:
- raise ValueError("Key certificate's '%s' time wasn't parseable: %s" % (keyword, value))
+ raise ValueError("Key certificate's '%s' time wasn't parsable: %s" % (keyword, value))
elif keyword in ('dir-identity-key', 'dir-signing-key', 'dir-key-crosscert', 'dir-key-certification'):
# "dir-identity-key" NL a public key in PEM format
# "dir-signing-key" NL a key in PEM format
diff --git a/stem/descriptor/router_status_entry.py b/stem/descriptor/router_status_entry.py
index 239e6bb..61f03e8 100644
--- a/stem/descriptor/router_status_entry.py
+++ b/stem/descriptor/router_status_entry.py
@@ -425,7 +425,7 @@ def _parse_r_line(desc, value, validate, include_digest = True):
desc.published = datetime.datetime.strptime(published, "%Y-%m-%d %H:%M:%S")
except ValueError:
if validate:
- raise ValueError("Publication time time wasn't parseable: r %s" % value)
+ raise ValueError("Publication time time wasn't parsable: r %s" % value)
def _parse_s_line(desc, value, validate):
# "s" Flags
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index 68b2da3..046dfe1 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -398,7 +398,7 @@ class ServerDescriptor(stem.descriptor.Descriptor):
self.published = datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
except ValueError:
if validate:
- raise ValueError("Published line's time wasn't parseable: %s" % line)
+ raise ValueError("Published line's time wasn't parsable: %s" % line)
elif keyword == "fingerprint":
# This is forty hex digits split into space separated groups of four.
# Checking that we match this pattern.
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index 47ce4a9..11c9a9f 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -687,7 +687,7 @@ class TestNetworkStatusDocument(unittest.TestCase):
content = get_network_status_document_v3({"directory-signature": "%s %s\n%s" % tuple(attrs)}, content = True)
self.assertRaises(ValueError, NetworkStatusDocumentV3, content)
- NetworkStatusDocumentV3(content, False) # checks that it's still parseable without validation
+ NetworkStatusDocumentV3(content, False) # checks that it's still parsable without validation
def test_with_router_status_entries(self):
"""
1
0

06 Nov '12
commit 82747342cac4a7204b42928fe3a3f32fadea62c6
Author: Ravi Chandra Padmala <neenaoffline(a)gmail.com>
Date: Tue Nov 6 19:08:03 2012 +0530
Moving exceptions to stem's toplevel module
Fixing #6357
---
stem/__init__.py | 63 +++++++++++++++
stem/connection.py | 40 +++++-----
stem/control.py | 130 +++++++++++++++---------------
stem/response/__init__.py | 16 ++--
stem/response/authchallenge.py | 14 ++--
stem/response/getconf.py | 4 +-
stem/response/getinfo.py | 12 ++--
stem/response/mapaddress.py | 12 ++--
stem/response/protocolinfo.py | 14 ++--
stem/socket.py | 121 +++++++---------------------
test/integ/connection/authentication.py | 2 +-
test/integ/control/base_controller.py | 4 +-
test/integ/control/controller.py | 46 ++++++------
test/integ/socket/control_message.py | 14 ++--
test/integ/socket/control_socket.py | 10 +-
test/unit/connection/authentication.py | 10 +-
test/unit/response/authchallenge.py | 2 +-
test/unit/response/control_message.py | 8 +-
test/unit/response/getconf.py | 6 +-
test/unit/response/getinfo.py | 8 +-
test/unit/response/mapaddress.py | 6 +-
test/unit/response/protocolinfo.py | 2 +-
test/unit/response/singleline.py | 2 +-
test/util.py | 4 +-
24 files changed, 277 insertions(+), 273 deletions(-)
diff --git a/stem/__init__.py b/stem/__init__.py
index c05fcda..4146dff 100644
--- a/stem/__init__.py
+++ b/stem/__init__.py
@@ -1,5 +1,18 @@
"""
Library for working with the tor process.
+
+**Module Overview:**
+
+::
+
+ ControllerError - Base exception raised when using the controller.
+ |- ProtocolError - Malformed socket data.
+ |- OperationFailed - Tor was unable to successfully complete the operation.
+ | |- UnsatisfiableRequest - Tor was unable to satisfy a valid request.
+ | +- InvalidRequest - Invalid request.
+ | +- InvalidArguments - Invalid request parameters.
+ +- SocketError - Communication with the socket failed.
+ +- SocketClosed - Socket has been shut down.
"""
__version__ = '0.0.1'
@@ -21,3 +34,53 @@ __all__ = [
"version",
]
+class ControllerError(Exception):
+ "Base error for controller communication issues."
+
+class ProtocolError(ControllerError):
+ "Malformed content from the control socket."
+
+class OperationFailed(ControllerError):
+ """
+ Base exception class for failed operations that return an error code
+
+ :var str code: error code returned by Tor
+ :var str message: error message returned by Tor or a human readable error
+ message
+ """
+
+ def __init__(self, code = None, message = None):
+ super(ControllerError, self).__init__(message)
+ self.code = code
+ self.message = message
+
+class UnsatisfiableRequest(OperationFailed):
+ """
+ Exception raised if Tor was unable to process our request.
+ """
+
+class InvalidRequest(OperationFailed):
+ """
+ Exception raised when the request was invalid or malformed.
+ """
+
+class InvalidArguments(InvalidRequest):
+ """
+ Exception class for requests which had invalid arguments.
+
+ :var str code: error code returned by Tor
+ :var str message: error message returned by Tor or a human readable error
+ message
+ :var list arguments: a list of arguments which were invalid
+ """
+
+ def __init__(self, code = None, message = None, arguments = None):
+ super(InvalidArguments, self).__init__(code, message)
+ self.arguments = arguments
+
+class SocketError(ControllerError):
+ "Error arose while communicating with the control socket."
+
+class SocketClosed(SocketError):
+ "Control socket was closed before completing the message."
+
diff --git a/stem/connection.py b/stem/connection.py
index 20f0d84..e4971fa 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -20,7 +20,7 @@ fine-grained control over the authentication process. For instance...
try:
control_socket = stem.socket.ControlPort(control_port = 9051)
- except stem.socket.SocketError, exc:
+ except stem.SocketError, exc:
print "Unable to connect to port 9051 (%s)" % exc
sys.exit(1)
@@ -131,7 +131,7 @@ def connect_port(control_addr = "127.0.0.1", control_port = 9051, password = Non
try:
control_port = stem.socket.ControlPort(control_addr, control_port)
- except stem.socket.SocketError, exc:
+ except stem.SocketError, exc:
print exc
return None
@@ -153,7 +153,7 @@ def connect_socket_file(socket_path = "/var/run/tor/control", password = None, c
try:
control_socket = stem.socket.ControlSocketFile(socket_path)
- except stem.socket.SocketError, exc:
+ except stem.SocketError, exc:
print exc
return None
@@ -303,9 +303,9 @@ def authenticate(controller, password = None, chroot_path = None, protocolinfo_r
if not protocolinfo_response:
try:
protocolinfo_response = get_protocolinfo(controller)
- except stem.socket.ProtocolError:
+ except stem.ProtocolError:
raise IncorrectSocketType("unable to use the control socket")
- except stem.socket.SocketError, exc:
+ except stem.SocketError, exc:
raise AuthenticationFailure("socket connection failed (%s)" % exc)
auth_methods = list(protocolinfo_response.auth_methods)
@@ -384,7 +384,7 @@ def authenticate(controller, password = None, chroot_path = None, protocolinfo_r
log.debug("The %s method raised a CookieAuthRejected when cookie auth should be available. Stem may need to be corrected to recognize this response: %s" % (auth_func, exc))
auth_exceptions.append(IncorrectCookieValue(str(exc), exc.cookie_path, exc.is_safecookie))
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
auth_exceptions.append(AuthenticationFailure(str(exc)))
# All authentication attempts failed. Raise the exception that takes priority
@@ -418,7 +418,7 @@ def authenticate_none(controller, suppress_ctl_errors = True):
:param controller: tor controller or socket to be authenticated
:param bool suppress_ctl_errors: reports raised
- :class:`~stem.socket.ControllerError` as authentication rejection if
+ :class:`~stem.ControllerError` as authentication rejection if
**True**, otherwise they're re-raised
:raises: :class:`stem.connection.OpenAuthRejected` if the empty authentication credentials aren't accepted
@@ -433,7 +433,7 @@ def authenticate_none(controller, suppress_ctl_errors = True):
except: pass
raise OpenAuthRejected(str(auth_response), auth_response)
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
try: controller.connect()
except: pass
@@ -464,7 +464,7 @@ def authenticate_password(controller, password, suppress_ctl_errors = True):
:param controller: tor controller or socket to be authenticated
:param str password: passphrase to present to the socket
:param bool suppress_ctl_errors: reports raised
- :class:`~stem.socket.ControllerError` as authentication rejection if
+ :class:`~stem.ControllerError` as authentication rejection if
**True**, otherwise they're re-raised
:raises:
@@ -496,7 +496,7 @@ def authenticate_password(controller, password, suppress_ctl_errors = True):
raise IncorrectPassword(str(auth_response), auth_response)
else:
raise PasswordAuthRejected(str(auth_response), auth_response)
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
try: controller.connect()
except: pass
@@ -534,7 +534,7 @@ def authenticate_cookie(controller, cookie_path, suppress_ctl_errors = True):
:param controller: tor controller or socket to be authenticated
:param str cookie_path: path of the authentication cookie to send to tor
:param bool suppress_ctl_errors: reports raised
- :class:`~stem.socket.ControllerError` as authentication rejection if
+ :class:`~stem.ControllerError` as authentication rejection if
**True**, otherwise they're re-raised
:raises:
@@ -568,7 +568,7 @@ def authenticate_cookie(controller, cookie_path, suppress_ctl_errors = True):
raise IncorrectCookieValue(str(auth_response), cookie_path, False, auth_response)
else:
raise CookieAuthRejected(str(auth_response), cookie_path, False, auth_response)
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
try: controller.connect()
except: pass
@@ -613,7 +613,7 @@ def authenticate_safecookie(controller, cookie_path, suppress_ctl_errors = True)
:param controller: tor controller or socket to be authenticated
:param str cookie_path: path of the authentication cookie to send to tor
:param bool suppress_ctl_errors: reports raised
- :class:`~stem.socket.ControllerError` as authentication rejection if
+ :class:`~stem.ControllerError` as authentication rejection if
**True**, otherwise they're re-raised
:raises:
@@ -657,7 +657,7 @@ def authenticate_safecookie(controller, cookie_path, suppress_ctl_errors = True)
raise CookieAuthRejected(authchallenge_response_str, cookie_path, True)
else:
raise AuthChallengeFailed(authchallenge_response, cookie_path)
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
try: controller.connect()
except: pass
@@ -666,7 +666,7 @@ def authenticate_safecookie(controller, cookie_path, suppress_ctl_errors = True)
try:
stem.response.convert("AUTHCHALLENGE", authchallenge_response)
- except stem.socket.ProtocolError, exc:
+ except stem.ProtocolError, exc:
if not suppress_ctl_errors: raise exc
else: raise AuthChallengeFailed("Unable to parse AUTHCHALLENGE response: %s" % exc, cookie_path)
@@ -680,7 +680,7 @@ def authenticate_safecookie(controller, cookie_path, suppress_ctl_errors = True)
client_hash = stem.util.connection.hmac_sha256(CLIENT_HASH_CONSTANT,
cookie_data + client_nonce + authchallenge_response.server_nonce)
auth_response = _msg(controller, "AUTHENTICATE %s" % (binascii.b2a_hex(client_hash)))
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
try: controller.connect()
except: pass
@@ -721,9 +721,9 @@ def get_protocolinfo(controller):
:returns: :class:`~stem.response.protocolinfo.ProtocolInfoResponse` provided by tor
:raises:
- * :class:`stem.socket.ProtocolError` if the PROTOCOLINFO response is
+ * :class:`stem.ProtocolError` if the PROTOCOLINFO response is
malformed
- * :class:`stem.socket.SocketError` if problems arise in establishing or
+ * :class:`stem.SocketError` if problems arise in establishing or
using the socket
"""
@@ -740,8 +740,8 @@ def get_protocolinfo(controller):
try:
protocolinfo_response = _msg(controller, "PROTOCOLINFO 1")
- except stem.socket.SocketClosed, exc:
- raise stem.socket.SocketError(exc)
+ except stem.SocketClosed, exc:
+ raise stem.SocketError(exc)
stem.response.convert("PROTOCOLINFO", protocolinfo_response)
diff --git a/stem/control.py b/stem/control.py
index 02afa33..a2d408b 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -162,11 +162,11 @@ class BaseController(object):
:returns: :class:`~stem.response.ControlMessage` with the response
:raises:
- * :class:`stem.socket.ProtocolError` the content from the socket is
+ * :class:`stem.ProtocolError` the content from the socket is
malformed
- * :class:`stem.socket.SocketError` if a problem arises in using the
+ * :class:`stem.SocketError` if a problem arises in using the
socket
- * :class:`stem.socket.SocketClosed` if the socket is shut down
+ * :class:`stem.SocketClosed` if the socket is shut down
"""
with self._msg_lock:
@@ -191,11 +191,11 @@ class BaseController(object):
try:
response = self._reply_queue.get_nowait()
- if isinstance(response, stem.socket.SocketClosed):
+ if isinstance(response, stem.SocketClosed):
pass # this is fine
- elif isinstance(response, stem.socket.ProtocolError):
+ elif isinstance(response, stem.ProtocolError):
log.info("Tor provided a malformed message (%s)" % response)
- elif isinstance(response, stem.socket.ControllerError):
+ elif isinstance(response, stem.ControllerError):
log.info("Socket experienced a problem (%s)" % response)
elif isinstance(response, stem.response.ControlMessage):
log.notice("BUG: the msg() function failed to deliver a response: %s" % response)
@@ -212,11 +212,11 @@ class BaseController(object):
# If the message we received back had an exception then re-raise it to the
# caller. Otherwise return the response.
- if isinstance(response, stem.socket.ControllerError):
+ if isinstance(response, stem.ControllerError):
raise response
else:
return response
- except stem.socket.SocketClosed, exc:
+ except stem.SocketClosed, exc:
# If the recv() thread caused the SocketClosed then we could still be
# in the process of closing. Calling close() here so that we can
# provide an assurance to the caller that when we raise a SocketClosed
@@ -240,7 +240,7 @@ class BaseController(object):
Reconnects our control socket. This is a pass-through for our socket's
:func:`~stem.socket.ControlSocket.connect` method.
- :raises: :class:`stem.socket.SocketError` if unable to make a socket
+ :raises: :class:`stem.SocketError` if unable to make a socket
"""
self._socket.connect()
@@ -432,7 +432,7 @@ class BaseController(object):
else:
# response to a msg() call
self._reply_queue.put(control_message)
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
# Assume that all exceptions belong to the reader. This isn't always
# true, but the msg() call can do a better job of sorting it out.
#
@@ -473,7 +473,7 @@ class Controller(BaseController):
:returns: :class:`~stem.control.Controller` attached to the given port
- :raises: :class:`stem.socket.SocketError` if we're unable to establish a connection
+ :raises: :class:`stem.SocketError` if we're unable to establish a connection
"""
if not stem.util.connection.is_valid_ip_address(control_addr):
@@ -492,7 +492,7 @@ class Controller(BaseController):
:returns: :class:`~stem.control.Controller` attached to the given socket file
- :raises: :class:`stem.socket.SocketError` if we're unable to establish a connection
+ :raises: :class:`stem.SocketError` if we're unable to establish a connection
"""
control_socket = stem.socket.ControlSocketFile(socket_path)
@@ -573,9 +573,9 @@ class Controller(BaseController):
* default if one was provided and our call failed
:raises:
- * :class:`stem.socket.ControllerError` if the call fails and we weren't
+ * :class:`stem.ControllerError` if the call fails and we weren't
provided a default response
- * :class:`stem.socket.InvalidArguments` if the 'param' requested was
+ * :class:`stem.InvalidArguments` if the 'param' requested was
invalid
"""
@@ -599,7 +599,7 @@ class Controller(BaseController):
params.remove(param)
elif param.startswith('ip-to-country/') and self.is_geoip_unavailable():
# the geoip database aleady looks to be unavailable - abort the request
- raise stem.socket.ProtocolError("Tor geoip database is unavailable")
+ raise stem.ProtocolError("Tor geoip database is unavailable")
# if everything was cached then short circuit making the query
if not params:
@@ -631,7 +631,7 @@ class Controller(BaseController):
return reply
else:
return reply.values()[0]
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
# bump geoip failure count if...
# * we're caching results
# * this was soley a geoip lookup
@@ -656,7 +656,7 @@ class Controller(BaseController):
connected to
:raises:
- * :class:`stem.socket.ControllerError` if unable to query the version
+ * :class:`stem.ControllerError` if unable to query the version
* **ValueError** if unable to parse the version
"""
@@ -679,7 +679,7 @@ class Controller(BaseController):
:returns: :class:`~stem.descriptor.server_descriptor.RelayDescriptor` for the given relay
:raises:
- * :class:`stem.socket.ControllerError` if unable to query the descriptor
+ * :class:`stem.ControllerError` if unable to query the descriptor
* **ValueError** if **relay** doesn't conform with the pattern for being
a fingerprint or nickname
"""
@@ -703,7 +703,7 @@ class Controller(BaseController):
:class:`~stem.descriptor.server_descriptor.RelayDescriptor` for relays in
the tor network
- :raises: :class:`stem.socket.ControllerError` if unable to query tor
+ :raises: :class:`stem.ControllerError` if unable to query tor
"""
# TODO: We should iterate over the descriptors as they're read from the
@@ -726,7 +726,7 @@ class Controller(BaseController):
for the given relay
:raises:
- * :class:`stem.socket.ControllerError` if unable to query the descriptor
+ * :class:`stem.ControllerError` if unable to query the descriptor
* **ValueError** if **relay** doesn't conform with the patter for being a
fingerprint or nickname
"""
@@ -750,7 +750,7 @@ class Controller(BaseController):
:class:`~stem.descriptor.router_status_entry.RouterStatusEntryV2` for
relays in the tor network
- :raises: :class:`stem.socket.ControllerError` if unable to query tor
+ :raises: :class:`stem.ControllerError` if unable to query tor
"""
# TODO: We should iterate over the descriptors as they're read from the
@@ -783,9 +783,9 @@ class Controller(BaseController):
:returns: :class:`~stem.response.protocolinfo.ProtocolInfoResponse` provided by tor
:raises:
- * :class:`stem.socket.ProtocolError` if the PROTOCOLINFO response is
+ * :class:`stem.ProtocolError` if the PROTOCOLINFO response is
malformed
- * :class:`stem.socket.SocketError` if problems arise in establishing or
+ * :class:`stem.SocketError` if problems arise in establishing or
using the socket
"""
@@ -814,9 +814,9 @@ class Controller(BaseController):
* default if one was provided and our call failed
:raises:
- * :class:`stem.socket.ControllerError` if the call fails and we weren't
+ * :class:`stem.ControllerError` if the call fails and we weren't
provided a default response
- * :class:`stem.socket.InvalidArguments` if the configuration option
+ * :class:`stem.InvalidArguments` if the configuration option
requested was invalid
"""
@@ -874,8 +874,8 @@ class Controller(BaseController):
* default if one was provided and our call failed
:raises:
- * :class:`stem.socket.ControllerError` if the call fails and we weren't provided a default response
- * :class:`stem.socket.InvalidArguments` if the configuration option requested was invalid
+ * :class:`stem.ControllerError` if the call fails and we weren't provided a default response
+ * :class:`stem.InvalidArguments` if the configuration option requested was invalid
"""
start_time = time.time()
@@ -941,7 +941,7 @@ class Controller(BaseController):
return reply
else:
return dict([(entry[0], entry[1][0]) for entry in reply.items()])
- except stem.socket.ControllerError, exc:
+ except stem.ControllerError, exc:
log.debug("GETCONF %s (failed: %s)" % (" ".join(lookup_params), exc))
if default != UNDEFINED: return default
@@ -960,10 +960,10 @@ class Controller(BaseController):
:param str,list value: value to set the parameter to
:raises:
- * :class:`stem.socket.ControllerError` if the call fails
- * :class:`stem.socket.InvalidArguments` if configuration options
+ * :class:`stem.ControllerError` if the call fails
+ * :class:`stem.InvalidArguments` if configuration options
requested was invalid
- * :class:`stem.socket.InvalidRequest` if the configuration setting is
+ * :class:`stem.InvalidRequest` if the configuration setting is
impossible or if there's a syntax error in the configuration values
"""
@@ -976,9 +976,9 @@ class Controller(BaseController):
:param str params: configuration option to be reset
:raises:
- * :class:`stem.socket.ControllerError` if the call fails
- * :class:`stem.socket.InvalidArguments` if configuration options requested was invalid
- * :class:`stem.socket.InvalidRequest` if the configuration setting is
+ * :class:`stem.ControllerError` if the call fails
+ * :class:`stem.InvalidArguments` if configuration options requested was invalid
+ * :class:`stem.InvalidRequest` if the configuration setting is
impossible or if there's a syntax error in the configuration values
"""
@@ -1011,10 +1011,10 @@ class Controller(BaseController):
defaults if **True**
:raises:
- * :class:`stem.socket.ControllerError` if the call fails
- * :class:`stem.socket.InvalidArguments` if configuration options
+ * :class:`stem.ControllerError` if the call fails
+ * :class:`stem.InvalidArguments` if configuration options
requested was invalid
- * :class:`stem.socket.InvalidRequest` if the configuration setting is
+ * :class:`stem.InvalidRequest` if the configuration setting is
impossible or if there's a syntax error in the configuration values
"""
@@ -1058,12 +1058,12 @@ class Controller(BaseController):
if response.code == "552":
if response.message.startswith("Unrecognized option: Unknown option '"):
key = response.message[37:response.message.find("\'", 37)]
- raise stem.socket.InvalidArguments(response.code, response.message, [key])
- raise stem.socket.InvalidRequest(response.code, response.message)
+ raise stem.InvalidArguments(response.code, response.message, [key])
+ raise stem.InvalidRequest(response.code, response.message)
elif response.code in ("513", "553"):
- raise stem.socket.InvalidRequest(response.code, response.message)
+ raise stem.InvalidRequest(response.code, response.message)
else:
- raise stem.socket.ProtocolError("Returned unexpected status code: %s" % response.code)
+ raise stem.ProtocolError("Returned unexpected status code: %s" % response.code)
def load_conf(self, configtext):
"""
@@ -1072,7 +1072,7 @@ class Controller(BaseController):
:param str configtext: the configuration text
- :raises: :class:`stem.socket.ControllerError` if the call fails
+ :raises: :class:`stem.ControllerError` if the call fails
"""
response = self.msg("LOADCONF\n%s" % configtext)
@@ -1080,18 +1080,18 @@ class Controller(BaseController):
if response.code in ("552", "553"):
if response.code == "552" and response.message.startswith("Invalid config file: Failed to parse/validate config: Unknown option"):
- raise stem.socket.InvalidArguments(response.code, response.message, [response.message[70:response.message.find('.', 70) - 1]])
- raise stem.socket.InvalidRequest(response.code, response.message)
+ raise stem.InvalidArguments(response.code, response.message, [response.message[70:response.message.find('.', 70) - 1]])
+ raise stem.InvalidRequest(response.code, response.message)
elif not response.is_ok():
- raise stem.socket.ProtocolError("+LOADCONF Received unexpected response\n%s" % str(response))
+ raise stem.ProtocolError("+LOADCONF Received unexpected response\n%s" % str(response))
def save_conf(self):
"""
Saves the current configuration options into the active torrc file.
:raises:
- * :class:`stem.socket.ControllerError` if the call fails
- * :class:`stem.socket.OperationFailed` if the client is unable to save
+ * :class:`stem.ControllerError` if the call fails
+ * :class:`stem.OperationFailed` if the client is unable to save
the configuration file
"""
@@ -1101,9 +1101,9 @@ class Controller(BaseController):
if response.is_ok():
return True
elif response.code == "551":
- raise stem.socket.OperationFailed(response.code, response.message)
+ raise stem.OperationFailed(response.code, response.message)
else:
- raise stem.socket.ProtocolError("SAVECONF returned unexpected response code")
+ raise stem.ProtocolError("SAVECONF returned unexpected response code")
def is_feature_enabled(self, feature):
"""
@@ -1148,8 +1148,8 @@ class Controller(BaseController):
:param str,list features: a single feature or a list of features to be enabled
:raises:
- * :class:`stem.socket.ControllerError` if the call fails
- * :class:`stem.socket.InvalidArguments` if features passed were invalid
+ * :class:`stem.ControllerError` if the call fails
+ * :class:`stem.InvalidArguments` if features passed were invalid
"""
if type(features) == str: features = [features]
@@ -1161,9 +1161,9 @@ class Controller(BaseController):
invalid_feature = []
if response.message.startswith("Unrecognized feature \""):
invalid_feature = [response.message[22:response.message.find("\"", 22)]]
- raise stem.socket.InvalidArguments(response.code, response.message, invalid_feature)
+ raise stem.InvalidArguments(response.code, response.message, invalid_feature)
- raise stem.socket.ProtocolError("USEFEATURE provided an invalid response code: %s" % response.code)
+ raise stem.ProtocolError("USEFEATURE provided an invalid response code: %s" % response.code)
self.enabled_features += [entry.upper() for entry in features]
@@ -1184,7 +1184,7 @@ class Controller(BaseController):
share any circuits with old ones (this also clears our DNS cache)
* **CLEARDNSCACHE** - clears cached DNS results
- :raises: :class:`stem.socket.InvalidArguments` if signal provided wasn't recognized
+ :raises: :class:`stem.InvalidArguments` if signal provided wasn't recognized
"""
response = self.msg("SIGNAL %s" % signal)
@@ -1192,9 +1192,9 @@ class Controller(BaseController):
if not response.is_ok():
if response.code == "552":
- raise stem.socket.InvalidArguments(response.code, response.message, [signal])
+ raise stem.InvalidArguments(response.code, response.message, [signal])
- raise stem.socket.ProtocolError("SIGNAL response contained unrecognized status code: %s" % response.code)
+ raise stem.ProtocolError("SIGNAL response contained unrecognized status code: %s" % response.code)
def repurpose_circuit(self, circuit_id, purpose):
"""
@@ -1205,7 +1205,7 @@ class Controller(BaseController):
:param int circuit_id: id of the circuit whose purpose is to be changed
:param str purpose: purpose (either "general" or "controller")
- :raises: :class:`stem.socket.InvalidArguments` if the circuit doesn't exist or if the purpose was invalid
+ :raises: :class:`stem.InvalidArguments` if the circuit doesn't exist or if the purpose was invalid
"""
response = self.msg("SETCIRCUITPURPOSE %s purpose=%s" % (str(circuit_id), purpose))
@@ -1213,9 +1213,9 @@ class Controller(BaseController):
if not response.is_ok():
if response.code == "552":
- raise stem.socket.InvalidRequest(response.code, response.message)
+ raise stem.InvalidRequest(response.code, response.message)
else:
- raise stem.socket.ProtocolError("SETCIRCUITPURPOSE returned unexpected response code: %s" % response.code)
+ raise stem.ProtocolError("SETCIRCUITPURPOSE returned unexpected response code: %s" % response.code)
def new_circuit(self, path = None, purpose = "general"):
"""
@@ -1244,7 +1244,7 @@ class Controller(BaseController):
:returns: int of the circuit id of the created or extended circuit
- :raises: :class:`stem.socket.InvalidRequest` if one of the parameters were invalid
+ :raises: :class:`stem.InvalidRequest` if one of the parameters were invalid
"""
args = [str(circuit)]
@@ -1260,11 +1260,11 @@ class Controller(BaseController):
extended, new_circuit = response.message.split(" ")
assert extended == "EXTENDED"
except:
- raise stem.socket.ProtocolError("EXTENDCIRCUIT response invalid:\n%s", str(response))
+ raise stem.ProtocolError("EXTENDCIRCUIT response invalid:\n%s", str(response))
elif response.code == '552':
- raise stem.socket.InvalidRequest(response.code, response.message)
+ raise stem.InvalidRequest(response.code, response.message)
else:
- raise stem.socket.ProtocolError("EXTENDCIRCUIT returned unexpected response code: %s" % response.code)
+ raise stem.ProtocolError("EXTENDCIRCUIT returned unexpected response code: %s" % response.code)
return int(new_circuit)
@@ -1281,8 +1281,8 @@ class Controller(BaseController):
:param dict mapping: mapping of original addresses to replacement addresses
:raises:
- * :class:`stem.socket.InvalidRequest` if the addresses are malformed
- * :class:`stem.socket.OperationFailed` if Tor couldn't fulfill the request
+ * :class:`stem.InvalidRequest` if the addresses are malformed
+ * :class:`stem.OperationFailed` if Tor couldn't fulfill the request
:returns: **dict** with 'original -> replacement' address mappings
"""
diff --git a/stem/response/__init__.py b/stem/response/__init__.py
index fb6c63f..050ba02 100644
--- a/stem/response/__init__.py
+++ b/stem/response/__init__.py
@@ -66,20 +66,20 @@ def convert(response_type, message, **kwargs):
* AUTHCHALLENGE
* SINGLELINE
- * **\*** can raise a :class:`stem.socket.InvalidArguments` exception
- * **^** can raise a :class:`stem.socket.InvalidRequest` exception
- * **&** can raise a :class:`stem.socket.OperationFailed` exception
+ * **\*** can raise a :class:`stem.InvalidArguments` exception
+ * **^** can raise a :class:`stem.InvalidRequest` exception
+ * **&** can raise a :class:`stem.OperationFailed` exception
:param str response_type: type of tor response to convert to
:param stem.response.ControlMessage message: message to be converted
:param kwargs: optional keyword arguments to be passed to the parser method
:raises:
- * :class:`stem.socket.ProtocolError` the message isn't a proper response of
+ * :class:`stem.ProtocolError` the message isn't a proper response of
that type
- * :class:`stem.socket.InvalidArguments` the arguments given as input are
+ * :class:`stem.InvalidArguments` the arguments given as input are
invalid
- * :class:`stem.socket.InvalidRequest` the arguments given as input are
+ * :class:`stem.InvalidRequest` the arguments given as input are
invalid
* **TypeError** if argument isn't a :class:`~stem.response.ControlMessage`
or response_type isn't supported
@@ -471,9 +471,9 @@ class SingleLineResponse(ControlMessage):
content = self.content()
if len(content) > 1:
- raise stem.socket.ProtocolError("Received multi-line response")
+ raise stem.ProtocolError("Received multi-line response")
elif len(content) == 0:
- raise stem.socket.ProtocolError("Received empty response")
+ raise stem.ProtocolError("Received empty response")
else:
self.code, _, self.message = content[0]
diff --git a/stem/response/authchallenge.py b/stem/response/authchallenge.py
index fa60339..6cc22f9 100644
--- a/stem/response/authchallenge.py
+++ b/stem/response/authchallenge.py
@@ -20,33 +20,33 @@ class AuthChallengeResponse(stem.response.ControlMessage):
self.server_nonce = None
if not self.is_ok():
- raise stem.socket.ProtocolError("AUTHCHALLENGE response didn't have an OK status:\n%s" % self)
+ raise stem.ProtocolError("AUTHCHALLENGE response didn't have an OK status:\n%s" % self)
elif len(self) > 1:
- raise stem.socket.ProtocolError("Received multiline AUTHCHALLENGE response:\n%s" % self)
+ raise stem.ProtocolError("Received multiline AUTHCHALLENGE response:\n%s" % self)
line = self[0]
# sanity check that we're a AUTHCHALLENGE response
if not line.pop() == "AUTHCHALLENGE":
- raise stem.socket.ProtocolError("Message is not an AUTHCHALLENGE response (%s)" % self)
+ raise stem.ProtocolError("Message is not an AUTHCHALLENGE response (%s)" % self)
if line.is_next_mapping("SERVERHASH"):
value = line.pop_mapping()[1]
if not stem.util.tor_tools.is_hex_digits(value, 64):
- raise stem.socket.ProtocolError("SERVERHASH has an invalid value: %s" % value)
+ raise stem.ProtocolError("SERVERHASH has an invalid value: %s" % value)
self.server_hash = binascii.a2b_hex(value)
else:
- raise stem.socket.ProtocolError("Missing SERVERHASH mapping: %s" % line)
+ raise stem.ProtocolError("Missing SERVERHASH mapping: %s" % line)
if line.is_next_mapping("SERVERNONCE"):
value = line.pop_mapping()[1]
if not stem.util.tor_tools.is_hex_digits(value, 64):
- raise stem.socket.ProtocolError("SERVERNONCE has an invalid value: %s" % value)
+ raise stem.ProtocolError("SERVERNONCE has an invalid value: %s" % value)
self.server_nonce = binascii.a2b_hex(value)
else:
- raise stem.socket.ProtocolError("Missing SERVERNONCE mapping: %s" % line)
+ raise stem.ProtocolError("Missing SERVERNONCE mapping: %s" % line)
diff --git a/stem/response/getconf.py b/stem/response/getconf.py
index 6d396b8..889a587 100644
--- a/stem/response/getconf.py
+++ b/stem/response/getconf.py
@@ -31,10 +31,10 @@ class GetConfResponse(stem.response.ControlMessage):
unrecognized_keywords.append(line[32:-1])
if unrecognized_keywords:
- raise stem.socket.InvalidArguments("552", "GETCONF request contained unrecognized keywords: %s" \
+ raise stem.InvalidArguments("552", "GETCONF request contained unrecognized keywords: %s" \
% ', '.join(unrecognized_keywords), unrecognized_keywords)
else:
- raise stem.socket.ProtocolError("GETCONF response contained a non-OK status code:\n%s" % self)
+ raise stem.ProtocolError("GETCONF response contained a non-OK status code:\n%s" % self)
while remaining_lines:
line = remaining_lines.pop(0)
diff --git a/stem/response/getinfo.py b/stem/response/getinfo.py
index ddedc34..fb967d7 100644
--- a/stem/response/getinfo.py
+++ b/stem/response/getinfo.py
@@ -31,23 +31,23 @@ class GetInfoResponse(stem.response.ControlMessage):
unrecognized_keywords.append(line[18:-1])
if unrecognized_keywords:
- raise stem.socket.InvalidArguments("552", "GETINFO request contained unrecognized keywords: %s\n" \
+ raise stem.InvalidArguments("552", "GETINFO request contained unrecognized keywords: %s\n" \
% ', '.join(unrecognized_keywords), unrecognized_keywords)
else:
- raise stem.socket.ProtocolError("GETINFO response didn't have an OK status:\n%s" % self)
+ raise stem.ProtocolError("GETINFO response didn't have an OK status:\n%s" % self)
while remaining_lines:
try:
key, value = remaining_lines.pop(0).split("=", 1)
except ValueError:
- raise stem.socket.ProtocolError("GETINFO replies should only contain parameter=value mappings:\n%s" % self)
+ raise stem.ProtocolError("GETINFO replies should only contain parameter=value mappings:\n%s" % self)
# if the value is a multiline value then it *must* be of the form
# '<key>=\n<value>'
if "\n" in value:
if not value.startswith("\n"):
- raise stem.socket.ProtocolError("GETINFO response contained a multi-line value that didn't start with a newline:\n%s" % self)
+ raise stem.ProtocolError("GETINFO response contained a multi-line value that didn't start with a newline:\n%s" % self)
value = value[1:]
@@ -60,7 +60,7 @@ class GetInfoResponse(stem.response.ControlMessage):
:param set params: parameters to assert that we contain
:raises:
- * :class:`stem.socket.ProtocolError` if parameters don't match this response
+ * :class:`stem.ProtocolError` if parameters don't match this response
"""
reply_params = set(self.entries.keys())
@@ -69,5 +69,5 @@ class GetInfoResponse(stem.response.ControlMessage):
requested_label = ", ".join(params)
reply_label = ", ".join(reply_params)
- raise stem.socket.ProtocolError("GETINFO reply doesn't match the parameters that we requested. Queried '%s' but got '%s'." % (requested_label, reply_label))
+ raise stem.ProtocolError("GETINFO reply doesn't match the parameters that we requested. Queried '%s' but got '%s'." % (requested_label, reply_label))
diff --git a/stem/response/mapaddress.py b/stem/response/mapaddress.py
index d4e33de..b2be32e 100644
--- a/stem/response/mapaddress.py
+++ b/stem/response/mapaddress.py
@@ -9,8 +9,8 @@ class MapAddressResponse(stem.response.ControlMessage):
:var dict entries: mapping between the original and replacement addresses
:raises:
- * :class:`stem.socket.OperationFailed` if Tor was unable to satisfy the request
- * :class:`stem.socket.InvalidRequest` if the addresses provided were invalid
+ * :class:`stem.OperationFailed` if Tor was unable to satisfy the request
+ * :class:`stem.InvalidRequest` if the addresses provided were invalid
"""
def _parse_message(self):
@@ -21,11 +21,11 @@ class MapAddressResponse(stem.response.ControlMessage):
if not self.is_ok():
for code, _, message in self.content():
if code == "512":
- raise stem.socket.InvalidRequest(code, message)
+ raise stem.InvalidRequest(code, message)
elif code == "451":
- raise stem.socket.OperationFailed(code, message)
+ raise stem.OperationFailed(code, message)
else:
- raise stem.socket.ProtocolError("MAPADDRESS returned unexpected response code: %s", code)
+ raise stem.ProtocolError("MAPADDRESS returned unexpected response code: %s", code)
self.entries = {}
@@ -35,5 +35,5 @@ class MapAddressResponse(stem.response.ControlMessage):
key, value = message.split("=", 1)
self.entries[key] = value
except ValueError:
- raise stem.socket.ProtocolError(None, "MAPADDRESS returned '%s', which isn't a mapping" % message)
+ raise stem.ProtocolError(None, "MAPADDRESS returned '%s', which isn't a mapping" % message)
diff --git a/stem/response/protocolinfo.py b/stem/response/protocolinfo.py
index 258c5b6..d696a4d 100644
--- a/stem/response/protocolinfo.py
+++ b/stem/response/protocolinfo.py
@@ -36,11 +36,11 @@ class ProtocolInfoResponse(stem.response.ControlMessage):
remaining_lines = list(self)
if not self.is_ok() or not remaining_lines.pop() == "OK":
- raise stem.socket.ProtocolError("PROTOCOLINFO response didn't have an OK status:\n%s" % self)
+ raise stem.ProtocolError("PROTOCOLINFO response didn't have an OK status:\n%s" % self)
# sanity check that we're a PROTOCOLINFO response
if not remaining_lines[0].startswith("PROTOCOLINFO"):
- raise stem.socket.ProtocolError("Message is not a PROTOCOLINFO response:\n%s" % self)
+ raise stem.ProtocolError("Message is not a PROTOCOLINFO response:\n%s" % self)
while remaining_lines:
line = remaining_lines.pop(0)
@@ -52,12 +52,12 @@ class ProtocolInfoResponse(stem.response.ControlMessage):
# PIVERSION = 1*DIGIT
if line.is_empty():
- raise stem.socket.ProtocolError("PROTOCOLINFO response's initial line is missing the protocol version: %s" % line)
+ raise stem.ProtocolError("PROTOCOLINFO response's initial line is missing the protocol version: %s" % line)
try:
self.protocol_version = int(line.pop())
except ValueError:
- raise stem.socket.ProtocolError("PROTOCOLINFO response version is non-numeric: %s" % line)
+ raise stem.ProtocolError("PROTOCOLINFO response version is non-numeric: %s" % line)
# The piversion really should be "1" but, according to the spec, tor
# does not necessarily need to provide the PROTOCOLINFO version that we
@@ -75,7 +75,7 @@ class ProtocolInfoResponse(stem.response.ControlMessage):
# parse AuthMethod mapping
if not line.is_next_mapping("METHODS"):
- raise stem.socket.ProtocolError("PROTOCOLINFO response's AUTH line is missing its mandatory 'METHODS' mapping: %s" % line)
+ raise stem.ProtocolError("PROTOCOLINFO response's AUTH line is missing its mandatory 'METHODS' mapping: %s" % line)
for method in line.pop_mapping()[1].split(","):
if method == "NULL":
@@ -105,12 +105,12 @@ class ProtocolInfoResponse(stem.response.ControlMessage):
# TorVersion = QuotedString
if not line.is_next_mapping("Tor", True):
- raise stem.socket.ProtocolError("PROTOCOLINFO response's VERSION line is missing its mandatory tor version mapping: %s" % line)
+ raise stem.ProtocolError("PROTOCOLINFO response's VERSION line is missing its mandatory tor version mapping: %s" % line)
try:
self.tor_version = stem.version.Version(line.pop_mapping(True)[1])
except ValueError, exc:
- raise stem.socket.ProtocolError(exc)
+ raise stem.ProtocolError(exc)
else:
log.debug("Unrecognized PROTOCOLINFO line type '%s', ignoring it: %s" % (line_type, line))
diff --git a/stem/socket.py b/stem/socket.py
index 2b13466..6528f97 100644
--- a/stem/socket.py
+++ b/stem/socket.py
@@ -25,15 +25,6 @@ as instances of the :class:`~stem.response.ControlMessage` class.
send_message - Writes a message to a control socket.
recv_message - Reads a ControlMessage from a control socket.
send_formatting - Performs the formatting expected from sent messages.
-
- ControllerError - Base exception raised when using the controller.
- |- ProtocolError - Malformed socket data.
- |- OperationFailed - Tor was unable to successfully complete the operation.
- | |- UnsatisfiableRequest - Tor was unable to satisfy a valid request.
- | +- InvalidRequest - Invalid request.
- | +- InvalidArguments - Invalid request parameters.
- +- SocketError - Communication with the socket failed.
- +- SocketClosed - Socket has been shut down.
"""
from __future__ import with_statement
@@ -77,15 +68,15 @@ class ControlSocket(object):
:param bool raw: leaves the message formatting untouched, passing it to the socket as-is
:raises:
- * :class:`stem.socket.SocketError` if a problem arises in using the socket
- * :class:`stem.socket.SocketClosed` if the socket is known to be shut down
+ * :class:`stem.SocketError` if a problem arises in using the socket
+ * :class:`stem.SocketClosed` if the socket is known to be shut down
"""
with self._send_lock:
try:
- if not self.is_alive(): raise SocketClosed()
+ if not self.is_alive(): raise stem.SocketClosed()
send_message(self._socket_file, message, raw)
- except SocketClosed, exc:
+ except stem.SocketClosed, exc:
# if send_message raises a SocketClosed then we should properly shut
# everything down
if self.is_alive(): self.close()
@@ -99,8 +90,8 @@ class ControlSocket(object):
:returns: :class:`~stem.response.ControlMessage` for the message received
:raises:
- * :class:`stem.socket.ProtocolError` the content from the socket is malformed
- * :class:`stem.socket.SocketClosed` if the socket closes before we receive a complete message
+ * :class:`stem.ProtocolError` the content from the socket is malformed
+ * :class:`stem.SocketClosed` if the socket closes before we receive a complete message
"""
with self._recv_lock:
@@ -110,9 +101,9 @@ class ControlSocket(object):
socket_file = self._socket_file
- if not socket_file: raise SocketClosed()
+ if not socket_file: raise stem.SocketClosed()
return recv_message(socket_file)
- except SocketClosed, exc:
+ except stem.SocketClosed, exc:
# If recv_message raises a SocketClosed then we should properly shut
# everything down. However, there's a couple cases where this will
# cause deadlock...
@@ -159,7 +150,7 @@ class ControlSocket(object):
Connects to a new socket, closing our previous one if we're already
attached.
- :raises: :class:`stem.socket.SocketError` if unable to make a socket
+ :raises: :class:`stem.SocketError` if unable to make a socket
"""
with self._send_lock:
@@ -181,7 +172,7 @@ class ControlSocket(object):
try:
self._connect()
- except SocketError:
+ except stem.SocketError:
self._connect() # single retry
def close(self):
@@ -261,7 +252,7 @@ class ControlSocket(object):
:returns: **socket.socket** for our configuration
:raises:
- * :class:`stem.socket.SocketError` if unable to make a socket
+ * :class:`stem.SocketError` if unable to make a socket
* **NotImplementedError** if not implemented by a subclass
"""
@@ -281,7 +272,7 @@ class ControlPort(ControlSocket):
:param int control_port: port number of the controller
:param bool connect: connects to the socket if True, leaves it unconnected otherwise
- :raises: :class:`stem.socket.SocketError` if connect is **True** and we're
+ :raises: :class:`stem.SocketError` if connect is **True** and we're
unable to establish a connection
"""
@@ -315,7 +306,7 @@ class ControlPort(ControlSocket):
control_socket.connect((self._control_addr, self._control_port))
return control_socket
except socket.error, exc:
- raise SocketError(exc)
+ raise stem.SocketError(exc)
class ControlSocketFile(ControlSocket):
"""
@@ -330,7 +321,7 @@ class ControlSocketFile(ControlSocket):
:param str socket_path: path where the control socket is located
:param bool connect: connects to the socket if True, leaves it unconnected otherwise
- :raises: :class:`stem.socket.SocketError` if connect is **True** and we're
+ :raises: :class:`stem.SocketError` if connect is **True** and we're
unable to establish a connection
"""
@@ -354,7 +345,7 @@ class ControlSocketFile(ControlSocket):
control_socket.connect(self._socket_path)
return control_socket
except socket.error, exc:
- raise SocketError(exc)
+ raise stem.SocketError(exc)
def send_message(control_file, message, raw = False):
"""
@@ -384,8 +375,8 @@ def send_message(control_file, message, raw = False):
socket as-is
:raises:
- * :class:`stem.socket.SocketError` if a problem arises in using the socket
- * :class:`stem.socket.SocketClosed` if the socket is known to be shut down
+ * :class:`stem.SocketError` if a problem arises in using the socket
+ * :class:`stem.SocketClosed` if the socket is known to be shut down
"""
if not raw: message = send_formatting(message)
@@ -404,15 +395,15 @@ def send_message(control_file, message, raw = False):
# Just accounting for known disconnection responses.
if str(exc) == "[Errno 32] Broken pipe":
- raise SocketClosed(exc)
+ raise stem.SocketClosed(exc)
else:
- raise SocketError(exc)
+ raise stem.SocketError(exc)
except AttributeError:
# if the control_file has been closed then flush will receive:
# AttributeError: 'NoneType' object has no attribute 'sendall'
log.info("Failed to send message: file has been closed")
- raise SocketClosed("file has been closed")
+ raise stem.SocketClosed("file has been closed")
def recv_message(control_file):
"""
@@ -425,8 +416,8 @@ def recv_message(control_file):
:returns: :class:`~stem.response.ControlMessage` read from the socket
:raises:
- * :class:`stem.socket.ProtocolError` the content from the socket is malformed
- * :class:`stem.socket.SocketClosed` if the socket closes before we receive
+ * :class:`stem.ProtocolError` the content from the socket is malformed
+ * :class:`stem.SocketClosed` if the socket closes before we receive
a complete message
"""
@@ -441,14 +432,14 @@ def recv_message(control_file):
prefix = logging_prefix % "SocketClosed"
log.info(prefix + "socket file has been closed")
- raise SocketClosed("socket file has been closed")
+ raise stem.SocketClosed("socket file has been closed")
except socket.error, exc:
# when disconnected we get...
# socket.error: [Errno 107] Transport endpoint is not connected
prefix = logging_prefix % "SocketClosed"
log.info(prefix + "received exception \"%s\"" % exc)
- raise SocketClosed(exc)
+ raise stem.SocketClosed(exc)
raw_content += line
@@ -461,19 +452,19 @@ def recv_message(control_file):
prefix = logging_prefix % "SocketClosed"
log.info(prefix + "empty socket content")
- raise SocketClosed("Received empty socket content.")
+ raise stem.SocketClosed("Received empty socket content.")
elif len(line) < 4:
prefix = logging_prefix % "ProtocolError"
log.info(prefix + "line too short, \"%s\"" % log.escape(line))
- raise ProtocolError("Badly formatted reply line: too short")
+ raise stem.ProtocolError("Badly formatted reply line: too short")
elif not re.match(r'^[a-zA-Z0-9]{3}[-+ ]', line):
prefix = logging_prefix % "ProtocolError"
log.info(prefix + "malformed status code/divider, \"%s\"" % log.escape(line))
- raise ProtocolError("Badly formatted reply line: beginning is malformed")
+ raise stem.ProtocolError("Badly formatted reply line: beginning is malformed")
elif not line.endswith("\r\n"):
prefix = logging_prefix % "ProtocolError"
log.info(prefix + "no CRLF linebreak, \"%s\"" % log.escape(line))
- raise ProtocolError("All lines should end with CRLF")
+ raise stem.ProtocolError("All lines should end with CRLF")
line = line[:-2] # strips off the CRLF
status_code, divider, content = line[:3], line[3], line[4:]
@@ -498,14 +489,14 @@ def recv_message(control_file):
except socket.error, exc:
prefix = logging_prefix % "SocketClosed"
log.info(prefix + "received an exception while mid-way through a data reply (exception: \"%s\", read content: \"%s\")" % (exc, log.escape(raw_content)))
- raise SocketClosed(exc)
+ raise stem.SocketClosed(exc)
raw_content += line
if not line.endswith("\r\n"):
prefix = logging_prefix % "ProtocolError"
log.info(prefix + "CRLF linebreaks missing from a data reply, \"%s\"" % log.escape(raw_content))
- raise ProtocolError("All lines should end with CRLF")
+ raise stem.ProtocolError("All lines should end with CRLF")
elif line == ".\r\n":
break # data block termination
@@ -527,7 +518,7 @@ def recv_message(control_file):
# be safe...
prefix = logging_prefix % "ProtocolError"
log.warn(prefix + "\"%s\" isn't a recognized divider type" % line)
- raise ProtocolError("Unrecognized divider type '%s': %s" % (divider, line))
+ raise stem.ProtocolError("Unrecognized divider type '%s': %s" % (divider, line))
def send_formatting(message):
"""
@@ -557,53 +548,3 @@ def send_formatting(message):
else:
return message + "\r\n"
-class ControllerError(Exception):
- "Base error for controller communication issues."
-
-class ProtocolError(ControllerError):
- "Malformed content from the control socket."
-
-class OperationFailed(ControllerError):
- """
- Base exception class for failed operations that return an error code
-
- :var str code: error code returned by Tor
- :var str message: error message returned by Tor or a human readable error
- message
- """
-
- def __init__(self, code = None, message = None):
- super(ControllerError, self).__init__(message)
- self.code = code
- self.message = message
-
-class UnsatisfiableRequest(OperationFailed):
- """
- Exception raised if Tor was unable to process our request.
- """
-
-class InvalidRequest(OperationFailed):
- """
- Exception raised when the request was invalid or malformed.
- """
-
-class InvalidArguments(InvalidRequest):
- """
- Exception class for requests which had invalid arguments.
-
- :var str code: error code returned by Tor
- :var str message: error message returned by Tor or a human readable error
- message
- :var list arguments: a list of arguments which were invalid
- """
-
- def __init__(self, code = None, message = None, arguments = None):
- super(InvalidArguments, self).__init__(code, message)
- self.arguments = arguments
-
-class SocketError(ControllerError):
- "Error arose while communicating with the control socket."
-
-class SocketClosed(SocketError):
- "Control socket was closed before completing the message."
-
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py
index 8c5c06d..f811917 100644
--- a/test/integ/connection/authentication.py
+++ b/test/integ/connection/authentication.py
@@ -137,7 +137,7 @@ class TestAuthenticate(unittest.TestCase):
try:
control_socket = stem.socket.ControlPort(control_port = test.runner.CONTROL_PORT)
- except stem.socket.SocketError:
+ except stem.SocketError:
# assert that we didn't have a socket to connect to
self.assertFalse(test.runner.Torrc.PORT in tor_options)
return
diff --git a/test/integ/control/base_controller.py b/test/integ/control/base_controller.py
index 22cd7a8..eebb788 100644
--- a/test/integ/control/base_controller.py
+++ b/test/integ/control/base_controller.py
@@ -108,7 +108,7 @@ class TestBaseController(unittest.TestCase):
controller.msg("GETINFO version")
controller.msg("GETINFO blarg")
controller.msg("blarg")
- except stem.socket.ControllerError:
+ except stem.ControllerError:
pass
message_threads = []
@@ -213,7 +213,7 @@ class TestBaseController(unittest.TestCase):
# cause the socket to shut down without calling close()
controller.msg("Blarg!")
- self.assertRaises(stem.socket.SocketClosed, controller.msg, "blarg")
+ self.assertRaises(stem.SocketClosed, controller.msg, "blarg")
self.assertEquals(controller, state_observer.controller)
self.assertEquals(stem.control.State.CLOSED, state_observer.state)
self.assertTrue(state_observer.timestamp < time.time())
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index 2f7d15c..c1bdda8 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -32,7 +32,7 @@ class TestController(unittest.TestCase):
with stem.control.Controller.from_port(control_port = test.runner.CONTROL_PORT) as controller:
self.assertTrue(isinstance(controller, stem.control.Controller))
else:
- self.assertRaises(stem.socket.SocketError, stem.control.Controller.from_port, "127.0.0.1", test.runner.CONTROL_PORT)
+ self.assertRaises(stem.SocketError, stem.control.Controller.from_port, "127.0.0.1", test.runner.CONTROL_PORT)
def test_from_socket_file(self):
"""
@@ -45,7 +45,7 @@ class TestController(unittest.TestCase):
with stem.control.Controller.from_socket_file(socket_path = test.runner.CONTROL_SOCKET_PATH) as controller:
self.assertTrue(isinstance(controller, stem.control.Controller))
else:
- self.assertRaises(stem.socket.SocketError, stem.control.Controller.from_socket_file, test.runner.CONTROL_SOCKET_PATH)
+ self.assertRaises(stem.SocketError, stem.control.Controller.from_socket_file, test.runner.CONTROL_SOCKET_PATH)
def test_getinfo(self):
"""
@@ -75,12 +75,12 @@ class TestController(unittest.TestCase):
# non-existant option
- self.assertRaises(stem.socket.ControllerError, controller.get_info, "blarg")
+ self.assertRaises(stem.ControllerError, controller.get_info, "blarg")
self.assertEqual("ho hum", controller.get_info("blarg", "ho hum"))
# empty input
- self.assertRaises(stem.socket.ControllerError, controller.get_info, "")
+ self.assertRaises(stem.ControllerError, controller.get_info, "")
self.assertEqual("ho hum", controller.get_info("", "ho hum"))
self.assertEqual({}, controller.get_info([]))
@@ -175,12 +175,12 @@ class TestController(unittest.TestCase):
self.assertEqual(set(request_params), set(reply_params))
# non-existant option(s)
- self.assertRaises(stem.socket.InvalidArguments, controller.get_conf, "blarg")
+ self.assertRaises(stem.InvalidArguments, controller.get_conf, "blarg")
self.assertEqual("la-di-dah", controller.get_conf("blarg", "la-di-dah"))
- self.assertRaises(stem.socket.InvalidArguments, controller.get_conf_map, "blarg")
+ self.assertRaises(stem.InvalidArguments, controller.get_conf_map, "blarg")
self.assertEqual("la-di-dah", controller.get_conf_map("blarg", "la-di-dah"))
- self.assertRaises(stem.socket.InvalidRequest, controller.get_conf_map, ["blarg", "huadf"], multiple = True)
+ self.assertRaises(stem.InvalidRequest, controller.get_conf_map, ["blarg", "huadf"], multiple = True)
self.assertEqual("la-di-dah", controller.get_conf_map(["erfusdj", "afiafj"], "la-di-dah", multiple = True))
# multivalue configuration keys
@@ -227,7 +227,7 @@ class TestController(unittest.TestCase):
try:
controller.set_conf("invalidkeyboo", "abcde")
self.fail()
- except stem.socket.InvalidArguments, exc:
+ except stem.InvalidArguments, exc:
self.assertEqual(["invalidkeyboo"], exc.arguments)
# resets configuration parameters
@@ -251,7 +251,7 @@ class TestController(unittest.TestCase):
"bombay": "vadapav",
})
self.fail()
- except stem.socket.InvalidArguments, exc:
+ except stem.InvalidArguments, exc:
self.assertEqual(["bombay"], exc.arguments)
# context-sensitive keys (the only retched things for which order matters)
@@ -289,11 +289,11 @@ class TestController(unittest.TestCase):
try:
# invalid requests
- self.assertRaises(stem.socket.InvalidRequest, controller.load_conf, "ContactInfo confloaded")
+ self.assertRaises(stem.InvalidRequest, controller.load_conf, "ContactInfo confloaded")
try:
controller.load_conf("Blahblah blah")
self.fail()
- except stem.socket.InvalidArguments, exc:
+ except stem.InvalidArguments, exc:
self.assertEqual(["Blahblah"], exc.arguments)
# valid config
@@ -345,10 +345,10 @@ class TestController(unittest.TestCase):
self.assertTrue(re.match("\$[0-9a-fA-F]{40}[~=].*", controller.get_info('orconn-status').split()[0]))
self.assertTrue("VERBOSE_NAMES" in controller.enabled_features)
- self.assertRaises(stem.socket.InvalidArguments, controller.enable_feature, ["NOT", "A", "FEATURE"])
+ self.assertRaises(stem.InvalidArguments, controller.enable_feature, ["NOT", "A", "FEATURE"])
try:
controller.enable_feature(["NOT", "A", "FEATURE"])
- except stem.socket.InvalidArguments, exc:
+ except stem.InvalidArguments, exc:
self.assertEqual(["NOT"], exc.arguments)
else: self.fail()
@@ -364,7 +364,7 @@ class TestController(unittest.TestCase):
controller.signal("CLEARDNSCACHE")
# invalid signals
- self.assertRaises(stem.socket.InvalidArguments, controller.signal, "FOOBAR")
+ self.assertRaises(stem.InvalidArguments, controller.signal, "FOOBAR")
def test_extendcircuit(self):
if test.runner.require_control(self): return
@@ -377,9 +377,9 @@ class TestController(unittest.TestCase):
circ_id = controller.new_circuit()
self.assertTrue(filter(lambda x: int(x.split()[0]) == circ_id, controller.get_info('circuit-status').splitlines()))
- self.assertRaises(stem.socket.InvalidRequest, controller.extend_circuit, "foo")
- self.assertRaises(stem.socket.InvalidRequest, controller.extend_circuit, 0, "thisroutershouldntexistbecausestemexists!@##$%#")
- self.assertRaises(stem.socket.InvalidRequest, controller.extend_circuit, 0, "thisroutershouldntexistbecausestemexists!@##$%#", "foo")
+ self.assertRaises(stem.InvalidRequest, controller.extend_circuit, "foo")
+ self.assertRaises(stem.InvalidRequest, controller.extend_circuit, 0, "thisroutershouldntexistbecausestemexists!@##$%#")
+ self.assertRaises(stem.InvalidRequest, controller.extend_circuit, 0, "thisroutershouldntexistbecausestemexists!@##$%#", "foo")
def test_repurpose_circuit(self):
"""
@@ -403,8 +403,8 @@ class TestController(unittest.TestCase):
circ = filter(re.compile("^%i " % circ_id).match, circuit_output.splitlines())[0]
self.assertTrue("PURPOSE=GENERAL" in circ)
- self.assertRaises(stem.socket.InvalidRequest, controller.repurpose_circuit, 'f934h9f3h4', "fooo")
- self.assertRaises(stem.socket.InvalidRequest, controller.repurpose_circuit, '4', "fooo")
+ self.assertRaises(stem.InvalidRequest, controller.repurpose_circuit, 'f934h9f3h4', "fooo")
+ self.assertRaises(stem.InvalidRequest, controller.repurpose_circuit, '4', "fooo")
def test_mapaddress(self):
if test.runner.require_control(self): return
@@ -448,8 +448,8 @@ class TestController(unittest.TestCase):
self.assertRaises(ValueError, controller.get_server_descriptor, "z" * 30)
# try with a relay that doesn't exist
- self.assertRaises(stem.socket.ControllerError, controller.get_server_descriptor, "blargg")
- self.assertRaises(stem.socket.ControllerError, controller.get_server_descriptor, "5" * 40)
+ self.assertRaises(stem.ControllerError, controller.get_server_descriptor, "blargg")
+ self.assertRaises(stem.ControllerError, controller.get_server_descriptor, "5" * 40)
first_descriptor = None
with stem.descriptor.reader.DescriptorReader([descriptor_path]) as reader:
@@ -505,8 +505,8 @@ class TestController(unittest.TestCase):
self.assertRaises(ValueError, controller.get_network_status, "z" * 30)
# try with a relay that doesn't exist
- self.assertRaises(stem.socket.ControllerError, controller.get_network_status, "blargg")
- self.assertRaises(stem.socket.ControllerError, controller.get_network_status, "5" * 40)
+ self.assertRaises(stem.ControllerError, controller.get_network_status, "blargg")
+ self.assertRaises(stem.ControllerError, controller.get_network_status, "5" * 40)
# our cached consensus is v3 but the control port can only be queried for
# v2 or v1 network status information
diff --git a/test/integ/socket/control_message.py b/test/integ/socket/control_message.py
index cb2fe52..af6af16 100644
--- a/test/integ/socket/control_message.py
+++ b/test/integ/socket/control_message.py
@@ -36,23 +36,23 @@ class TestControlMessage(unittest.TestCase):
# checked in more depth by the ControlSocket integ tests.
self.assertTrue(control_socket.is_alive())
- self.assertRaises(stem.socket.SocketClosed, control_socket.recv)
+ self.assertRaises(stem.SocketClosed, control_socket.recv)
self.assertFalse(control_socket.is_alive())
# Additional socket usage should fail, and pulling more responses will fail
# with more closed exceptions.
- self.assertRaises(stem.socket.SocketError, control_socket.send, "GETINFO version")
- self.assertRaises(stem.socket.SocketClosed, control_socket.recv)
- self.assertRaises(stem.socket.SocketClosed, control_socket.recv)
- self.assertRaises(stem.socket.SocketClosed, control_socket.recv)
+ self.assertRaises(stem.SocketError, control_socket.send, "GETINFO version")
+ self.assertRaises(stem.SocketClosed, control_socket.recv)
+ self.assertRaises(stem.SocketClosed, control_socket.recv)
+ self.assertRaises(stem.SocketClosed, control_socket.recv)
# The socket connection is already broken so calling close shouldn't have
# an impact.
control_socket.close()
- self.assertRaises(stem.socket.SocketClosed, control_socket.send, "GETINFO version")
- self.assertRaises(stem.socket.SocketClosed, control_socket.recv)
+ self.assertRaises(stem.SocketClosed, control_socket.send, "GETINFO version")
+ self.assertRaises(stem.SocketClosed, control_socket.recv)
def test_invalid_command(self):
"""
diff --git a/test/integ/socket/control_socket.py b/test/integ/socket/control_socket.py
index ad253d1..a775b20 100644
--- a/test/integ/socket/control_socket.py
+++ b/test/integ/socket/control_socket.py
@@ -49,7 +49,7 @@ class TestControlSocket(unittest.TestCase):
control_socket.close()
self.assertFalse(control_socket.is_alive())
- self.assertRaises(stem.socket.SocketClosed, control_socket.send, "blarg")
+ self.assertRaises(stem.SocketClosed, control_socket.send, "blarg")
def test_send_disconnected(self):
"""
@@ -75,7 +75,7 @@ class TestControlSocket(unittest.TestCase):
control_socket.send("blarg")
self.assertTrue(control_socket.is_alive())
else:
- self.assertRaises(stem.socket.SocketClosed, control_socket.send, "blarg")
+ self.assertRaises(stem.SocketClosed, control_socket.send, "blarg")
self.assertFalse(control_socket.is_alive())
def test_recv_closed(self):
@@ -90,7 +90,7 @@ class TestControlSocket(unittest.TestCase):
control_socket.close()
self.assertFalse(control_socket.is_alive())
- self.assertRaises(stem.socket.SocketClosed, control_socket.recv)
+ self.assertRaises(stem.SocketClosed, control_socket.recv)
def test_recv_disconnected(self):
"""
@@ -109,7 +109,7 @@ class TestControlSocket(unittest.TestCase):
# however.
self.assertTrue(control_socket.is_alive())
- self.assertRaises(stem.socket.SocketClosed, control_socket.recv)
+ self.assertRaises(stem.SocketClosed, control_socket.recv)
self.assertFalse(control_socket.is_alive())
def test_connect_repeatedly(self):
@@ -125,6 +125,6 @@ class TestControlSocket(unittest.TestCase):
stem.connection.get_protocolinfo(control_socket)
control_socket.close()
- self.assertRaises(stem.socket.SocketClosed, control_socket.send, "PROTOCOLINFO 1")
+ self.assertRaises(stem.SocketClosed, control_socket.send, "PROTOCOLINFO 1")
control_socket.connect()
diff --git a/test/unit/connection/authentication.py b/test/unit/connection/authentication.py
index 2efcab8..a99651a 100644
--- a/test/unit/connection/authentication.py
+++ b/test/unit/connection/authentication.py
@@ -40,11 +40,11 @@ class TestAuthenticate(unittest.TestCase):
stem.connection.authenticate(None)
# tests where get_protocolinfo raises an exception
- raised_exc = stem.socket.ProtocolError(None)
+ raised_exc = stem.ProtocolError(None)
mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(raised_exc))
self.assertRaises(stem.connection.IncorrectSocketType, stem.connection.authenticate, None)
- raised_exc = stem.socket.SocketError(None)
+ raised_exc = stem.SocketError(None)
mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(raised_exc))
self.assertRaises(stem.connection.AuthenticationFailure, stem.connection.authenticate, None)
@@ -82,9 +82,9 @@ class TestAuthenticate(unittest.TestCase):
# 'suppress_ctl_errors' is False, so including those
control_exc = (
- stem.socket.ProtocolError(None),
- stem.socket.SocketError(None),
- stem.socket.SocketClosed(None))
+ stem.ProtocolError(None),
+ stem.SocketError(None),
+ stem.SocketClosed(None))
all_auth_none_exc += control_exc
all_auth_password_exc += control_exc
diff --git a/test/unit/response/authchallenge.py b/test/unit/response/authchallenge.py
index f85856b..5560b03 100644
--- a/test/unit/response/authchallenge.py
+++ b/test/unit/response/authchallenge.py
@@ -50,5 +50,5 @@ class TestAuthChallengeResponse(unittest.TestCase):
remaining_comp = auth_challenge_comp[:i] + auth_challenge_comp[i + 1:]
control_message = mocking.get_message(' '.join(remaining_comp))
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "AUTHCHALLENGE", control_message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "AUTHCHALLENGE", control_message)
diff --git a/test/unit/response/control_message.py b/test/unit/response/control_message.py
index b86fc41..68a5c42 100644
--- a/test/unit/response/control_message.py
+++ b/test/unit/response/control_message.py
@@ -111,7 +111,7 @@ class TestControlMessage(unittest.TestCase):
# replace the CRLF for the line
infonames_lines[i] = infonames_lines[i].rstrip("\r\n") + "\n"
test_socket_file = StringIO.StringIO("".join(infonames_lines))
- self.assertRaises(stem.socket.ProtocolError, stem.socket.recv_message, test_socket_file)
+ self.assertRaises(stem.ProtocolError, stem.socket.recv_message, test_socket_file)
# puts the CRLF back
infonames_lines[i] = infonames_lines[i].rstrip("\n") + "\r\n"
@@ -136,8 +136,8 @@ class TestControlMessage(unittest.TestCase):
# - this is part of the message prefix
# - this is disrupting the line ending
- self.assertRaises(stem.socket.ProtocolError, stem.socket.recv_message, StringIO.StringIO(removal_test_input))
- self.assertRaises(stem.socket.ProtocolError, stem.socket.recv_message, StringIO.StringIO(replacement_test_input))
+ self.assertRaises(stem.ProtocolError, stem.socket.recv_message, StringIO.StringIO(removal_test_input))
+ self.assertRaises(stem.ProtocolError, stem.socket.recv_message, StringIO.StringIO(replacement_test_input))
else:
# otherwise the data will be malformed, but this goes undetected
self._assert_message_parses(removal_test_input)
@@ -151,7 +151,7 @@ class TestControlMessage(unittest.TestCase):
control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
control_socket_file = control_socket.makefile()
- self.assertRaises(stem.socket.SocketClosed, stem.socket.recv_message, control_socket_file)
+ self.assertRaises(stem.SocketClosed, stem.socket.recv_message, control_socket_file)
def _assert_message_parses(self, controller_reply):
"""
diff --git a/test/unit/response/getconf.py b/test/unit/response/getconf.py
index 58e80d6..70d1239 100644
--- a/test/unit/response/getconf.py
+++ b/test/unit/response/getconf.py
@@ -96,11 +96,11 @@ class TestGetConfResponse(unittest.TestCase):
"""
control_message = mocking.get_message(UNRECOGNIZED_KEY_RESPONSE)
- self.assertRaises(stem.socket.InvalidArguments, stem.response.convert, "GETCONF", control_message)
+ self.assertRaises(stem.InvalidArguments, stem.response.convert, "GETCONF", control_message)
try:
stem.response.convert("GETCONF", control_message)
- except stem.socket.InvalidArguments, exc:
+ except stem.InvalidArguments, exc:
self.assertEqual(exc.arguments, ["brickroad", "submarine"])
def test_invalid_content(self):
@@ -111,5 +111,5 @@ class TestGetConfResponse(unittest.TestCase):
"""
control_message = mocking.get_message(INVALID_RESPONSE)
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "GETCONF", control_message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "GETCONF", control_message)
diff --git a/test/unit/response/getinfo.py b/test/unit/response/getinfo.py
index 6d21faf..2a51693 100644
--- a/test/unit/response/getinfo.py
+++ b/test/unit/response/getinfo.py
@@ -111,7 +111,7 @@ class TestGetInfoResponse(unittest.TestCase):
"""
control_message = mocking.get_message(NON_KEY_VALUE_ENTRY)
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "GETINFO", control_message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "GETINFO", control_message)
def test_unrecognized_key_response(self):
"""
@@ -119,11 +119,11 @@ class TestGetInfoResponse(unittest.TestCase):
"""
control_message = mocking.get_message(UNRECOGNIZED_KEY_ENTRY)
- self.assertRaises(stem.socket.InvalidArguments, stem.response.convert, "GETINFO", control_message)
+ self.assertRaises(stem.InvalidArguments, stem.response.convert, "GETINFO", control_message)
try:
stem.response.convert("GETINFO", control_message)
- except stem.socket.InvalidArguments, exc:
+ except stem.InvalidArguments, exc:
self.assertEqual(exc.arguments, ["blackhole"])
def test_invalid_multiline_content(self):
@@ -134,5 +134,5 @@ class TestGetInfoResponse(unittest.TestCase):
"""
control_message = mocking.get_message(MISSING_MULTILINE_NEWLINE)
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "GETINFO", control_message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "GETINFO", control_message)
diff --git a/test/unit/response/mapaddress.py b/test/unit/response/mapaddress.py
index 3c2a372..2f9949b 100644
--- a/test/unit/response/mapaddress.py
+++ b/test/unit/response/mapaddress.py
@@ -61,7 +61,7 @@ class TestMapAddressResponse(unittest.TestCase):
"""
control_message = mocking.get_message(UNRECOGNIZED_KEYS_RESPONSE)
- self.assertRaises(stem.socket.InvalidRequest, stem.response.convert, "MAPADDRESS", control_message)
+ self.assertRaises(stem.InvalidRequest, stem.response.convert, "MAPADDRESS", control_message)
expected = { "23": "324" }
control_message = mocking.get_message(PARTIAL_FAILURE_RESPONSE)
@@ -76,8 +76,8 @@ class TestMapAddressResponse(unittest.TestCase):
"""
control_message = mocking.get_message(INVALID_EMPTY_RESPONSE)
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "MAPADDRESS", control_message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "MAPADDRESS", control_message)
control_message = mocking.get_message(INVALID_RESPONSE)
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "MAPADDRESS", control_message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "MAPADDRESS", control_message)
diff --git a/test/unit/response/protocolinfo.py b/test/unit/response/protocolinfo.py
index 09d4414..7d16075 100644
--- a/test/unit/response/protocolinfo.py
+++ b/test/unit/response/protocolinfo.py
@@ -72,7 +72,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
# attempt to convert a different message type
bw_event_control_message = mocking.get_message("650 BW 32326 2856")
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "PROTOCOLINFO", bw_event_control_message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "PROTOCOLINFO", bw_event_control_message)
def test_no_auth(self):
"""
diff --git a/test/unit/response/singleline.py b/test/unit/response/singleline.py
index aa9c915..0a4e13f 100644
--- a/test/unit/response/singleline.py
+++ b/test/unit/response/singleline.py
@@ -31,5 +31,5 @@ class TestSingleLineResponse(unittest.TestCase):
def test_multi_line_response(self):
message = mocking.get_message(MULTILINE_RESPONSE)
- self.assertRaises(stem.socket.ProtocolError, stem.response.convert, "SINGLELINE", message)
+ self.assertRaises(stem.ProtocolError, stem.response.convert, "SINGLELINE", message)
diff --git a/test/util.py b/test/util.py
index ddc96f0..90a5551 100644
--- a/test/util.py
+++ b/test/util.py
@@ -1,7 +1,7 @@
import struct
import socket
-from stem.socket import ProtocolError
+from stem import ProtocolError
import test.runner
error_msgs = {
@@ -48,7 +48,7 @@ def negotiate_socks(sock, host, port):
:param str host: host to connect to
:param int port: port to connect to
- :raises: :class:`stem.socket.ProtocolError` if the socks server doesn't grant our request
+ :raises: :class:`stem.ProtocolError` if the socks server doesn't grant our request
:returns: a list with the IP address and the port that the proxy connected to
"""
1
0

[translation/vidalia_alpha_completed] Update translations for vidalia_alpha_completed
by translation@torproject.org 06 Nov '12
by translation@torproject.org 06 Nov '12
06 Nov '12
commit 929ccd1349f1d609def6b24bb0257c5f1d6c536a
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Nov 6 16:15:24 2012 +0000
Update translations for vidalia_alpha_completed
---
es/vidalia_es.po | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/es/vidalia_es.po b/es/vidalia_es.po
index ea54535..ee281c1 100644
--- a/es/vidalia_es.po
+++ b/es/vidalia_es.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: https://trac.torproject.org/projects/tor\n"
"POT-Creation-Date: 2012-03-21 17:46+0000\n"
-"PO-Revision-Date: 2012-11-06 14:38+0000\n"
+"PO-Revision-Date: 2012-11-06 15:55+0000\n"
"Last-Translator: strel <strelnic(a)gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/projects/p/torproject/language/es/)\n"
"MIME-Version: 1.0\n"
@@ -166,7 +166,7 @@ msgstr "NOTA: esto será editado mientras torrc se carga"
msgctxt "AdvancedPage"
msgid "ControlSocket path doesn't exist."
-msgstr "La ruta de ControlSocket de no existe."
+msgstr "La ruta de ControlSocket no existe."
msgctxt "AdvancedPage"
msgid ""
1
0

[translation/vidalia_alpha] Update translations for vidalia_alpha
by translation@torproject.org 06 Nov '12
by translation@torproject.org 06 Nov '12
06 Nov '12
commit 5fa580f95e16b8f5b5340e8c485b210c0f8d6377
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Nov 6 16:15:22 2012 +0000
Update translations for vidalia_alpha
---
es/vidalia_es.po | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/es/vidalia_es.po b/es/vidalia_es.po
index ea54535..ee281c1 100644
--- a/es/vidalia_es.po
+++ b/es/vidalia_es.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: https://trac.torproject.org/projects/tor\n"
"POT-Creation-Date: 2012-03-21 17:46+0000\n"
-"PO-Revision-Date: 2012-11-06 14:38+0000\n"
+"PO-Revision-Date: 2012-11-06 15:55+0000\n"
"Last-Translator: strel <strelnic(a)gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/projects/p/torproject/language/es/)\n"
"MIME-Version: 1.0\n"
@@ -166,7 +166,7 @@ msgstr "NOTA: esto será editado mientras torrc se carga"
msgctxt "AdvancedPage"
msgid "ControlSocket path doesn't exist."
-msgstr "La ruta de ControlSocket de no existe."
+msgstr "La ruta de ControlSocket no existe."
msgctxt "AdvancedPage"
msgid ""
1
0

[ooni-probe/master] Add script that verifys proper functionality of basic tests
by art@torproject.org 06 Nov '12
by art@torproject.org 06 Nov '12
06 Nov '12
commit 0b9e1629186a081dac4a72046caa8f1244c20154
Author: Arturo Filastò <arturo(a)filasto.net>
Date: Tue Nov 6 16:34:34 2012 +0100
Add script that verifys proper functionality of basic tests
* As suggested by Jake
* There is a subset of inputs that will run with the tests to avoid having to
wait loads of time for the test running.
* This should not require more than 30 seconds on a decent network
---
before_i_commit.sh | 27 +++++++++
ooni/oonicli.py | 7 +--
ooni/utils/log.py | 14 +++--
oonib/oonibackend.py | 12 +++-
oonib/report/api.py | 63 ++++------------------
oonib/report/db/models.py | 83 -----------------------------
test_inputs/README | 48 +++++++++++++++++
test_inputs/dns_tamper_file.txt | 3 +
test_inputs/dns_tamper_test_resolvers.txt | 2 +
test_inputs/http_host_file.txt | 2 +
test_inputs/keyword_filtering_file.txt | 2 +
test_inputs/url_lists_file.txt | 2 +
12 files changed, 118 insertions(+), 147 deletions(-)
diff --git a/before_i_commit.sh b/before_i_commit.sh
new file mode 100755
index 0000000..2816ea5
--- /dev/null
+++ b/before_i_commit.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# This script should be run before you commit to verify that the basic tests
+# are working as they should
+# Once you have run it you can inspect the log file via
+#
+# $ less before_i_commit.log
+# To clean up everything that is left by the running of this tool, do as
+# following:
+#
+# rm *.yamloo; rm before_i_commit.log
+#
+
+find . -type f -name "*.py[co]" -delete
+
+./bin/ooniprobe -l before_i_commit.log -o url_lists.yamloo nettests/core/url_list.py -f test_inputs/url_lists_file.txt
+
+./bin/ooniprobe -l before_i_commit.log -o dns_tamper_test.yamloo nettests/core/dnstamper.py -t test_inputs/dns_tamper_test_resolvers.txt -f test_inputs/dns_tamper_file.txt
+
+./bin/ooniprobe -l before_i_commit.log -o captive_portal_test.yamloo nettests/core/captiveportal.py
+
+./bin/ooniprobe -l before_i_commit.log -o http_host.yamloo nettests/core/http_host.py -b http://ooni.nu/test -f test_inputs/http_host_file.txt
+
+./bin/ooniprobe -l before_i_commit.log -o keyword_filtering.yamloo nettests/core/keyword_filtering.py -b http://ooni.nu/test/ -f test_inputs/keyword_filtering_file.txt
+
+./bin/ooniprobe -l before_i_commit.log -o url_lists.yamloo nettests/core/url_list.py -f test_inputs/url_lists_file.txt
+
+
diff --git a/ooni/oonicli.py b/ooni/oonicli.py
index aa3cdc0..1988652 100644
--- a/ooni/oonicli.py
+++ b/ooni/oonicli.py
@@ -46,7 +46,7 @@ class Options(usage.Options, app.ReactorSelectionMixin):
optParameters = [
["reportfile", "o", None, "report file name"],
- ["logfile", "l", "test.log", "log file name"],
+ ["logfile", "l", None, "log file name"],
['temp-directory', None, '_ooni_temp',
'Path to use as working directory for tests.']
]
@@ -87,9 +87,6 @@ class Options(usage.Options, app.ReactorSelectionMixin):
def run():
- log.start()
- log.debug("Started logging")
-
if len(sys.argv) == 1:
sys.argv.append("--help")
config = Options()
@@ -101,6 +98,8 @@ def run():
if config['debug-stacktraces']:
defer.setDebugging(True)
+ log.start(config['logfile'])
+
classes = runner.findTestClassesFromConfig(config)
casesList, options = runner.loadTestsAndOptions(classes, config)
diff --git a/ooni/utils/log.py b/ooni/utils/log.py
index e93295a..771bad8 100644
--- a/ooni/utils/log.py
+++ b/ooni/utils/log.py
@@ -13,18 +13,22 @@ from twisted.python.logfile import DailyLogFile
from ooni.utils import otime
from ooni import oconfig
-# XXX make this a config option
-log_file = oconfig.basic.logfile
+def start(logfile=None):
+ daily_logfile = None
+
+ if not logfile:
+ logfile = oconfig.basic.logfile
+
+ log_folder = os.path.dirname(logfile)
+ log_filename = os.path.basename(logfile)
-def start(log_file=log_file):
- log_folder = os.path.join('/', *log_file.split('/')[:-1])
- log_filename = log_file.split('/')[-1]
daily_logfile = DailyLogFile(log_filename, log_folder)
txlog.msg("Starting OONI on %s (%s UTC)" % (otime.prettyDateNow(),
otime.utcPrettyDateNow()))
logging.basicConfig()
python_logging = txlog.PythonLoggingObserver()
+
if oconfig.advanced.debug:
python_logging.logger.setLevel(logging.DEBUG)
else:
diff --git a/oonib/oonibackend.py b/oonib/oonibackend.py
index 29f3f58..e2e800f 100644
--- a/oonib/oonibackend.py
+++ b/oonib/oonibackend.py
@@ -9,20 +9,26 @@ import json
import random
import string
-from twisted.application import internet, service
from twisted.internet import protocol, reactor, defer
-from twisted.protocols import basic
+from twisted.application import internet, service
from twisted.web import resource, server, static
from twisted.web.microdom import escape
+from twisted.protocols import basic
from twisted.names import dns
+from ooni.utils import log
+
from oonib.report.api import reportingBackend
-from oonib.lib import config
from oonib.lib.ssl import SSLContext
+from oonib.lib import config
+
from oonib.testhelpers.httph import HTTPBackend, DebugHTTPServer
from oonib.testhelpers.dns import ProxyDNSServer
from oonib.testhelpers.daphn3 import Daphn3Server
+
+log.start('/tmp/oonib.log')
+
# This tells twisted to set the
server.version = config.main.server_version
diff --git a/oonib/report/api.py b/oonib/report/api.py
index ad0f62c..ea6085d 100644
--- a/oonib/report/api.py
+++ b/oonib/report/api.py
@@ -8,46 +8,15 @@ This is the async pcap reporting system. It requires the client to have created
"""
import random
import string
+import json
+
from twisted.internet import reactor, defer
+
from cyclone import web
from oonib.report.db import models
backend_version = '0.0.1'
-def generateReportID():
- size = 100
- report_id = ''.join(random.choice(string.ascii_letters) for x in range(size))
- return report_id
-
-(a)defer.inlineCallbacks
-def newReport(software_name, software_version, test_name, test_version,
- progress, content):
-
- report_id = generateReportID()
-
- new_report = models.Report()
-
- new_report.report_id = unicode(report_id)
-
- new_report.software_name = unicode(software_name)
- new_report.software_version = unicode(software_version)
- new_report.test_name = unicode(test_name)
- new_report.test_version = unicode(test_version)
- new_report.progress = unicode(progress)
- new_report.content = unicode(content)
-
- print "Software Name: %s" % software_name
- print "Software Version: %s" % software_version
- print "Test Name: %s" % test_name
- print "Test Version: %s" % test_version
- print "Progress: %s" % progress
- print "Content: %s" % content
-
- yield new_report.save()
-
- defer.returnValue({'backend_version': backend_version, 'report_id':
- report_id})
-
def updateReport(report_id, content):
print "Report ID: %s" % report_id
print "Content: %s" % content
@@ -61,7 +30,7 @@ class NewReportHandler(web.RequestHandler):
@web.asynchronous
@defer.inlineCallbacks
- def get(self):
+ def post(self):
"""
Creates a new report with the input
@@ -84,27 +53,18 @@ class NewReportHandler(web.RequestHandler):
{'backend_version': 'XXX', 'report_id': 'XXX'}
"""
- # This is the list of supported arguments
- arguments = ['software_name', 'software_version',
- 'test_name','test_version',
- 'progress', 'content']
- report = {}
- for arg in arguments:
- if len(self.get_arguments(arg)) == 0:
- raise web.HTTPError(400, "%s not specified as argument of POST"
- % arg)
- report[arg] = self.get_argument(arg)
+ parsed_request = json.loads(self.request.body)
- try:
- test_helper = self.get_argument('test_helper')
+ # XXX here we should validate and sanitize the request
+ report_data = parsed_request
- except web.HTTPError:
- pass
+ new_report = models.Report()
- new_report = yield newReport(**report)
+ print "Got %s as request" % parsed_request
+ result = yield new_report.new(report_data)
- self.write(new_report)
+ self.write(result)
self.finish()
def put(self):
@@ -128,4 +88,3 @@ spec = [(r"/report/new", NewReportHandler),
(r"/report/pcap", PCAPReportHandler)]
reportingBackend = web.Application(spec)
-
diff --git a/oonib/report/db/models.py b/oonib/report/db/models.py
deleted file mode 100644
index 21e60eb..0000000
--- a/oonib/report/db/models.py
+++ /dev/null
@@ -1,83 +0,0 @@
-__all__ = ['Report', 'TestHelperTMP']
-from storm.twisted.transact import transact
-from storm.locals import *
-
-from oonib.report.db import getStore, transactor
-
-class OModel(object):
-
- transactor = transactor
-
- @transact
- def create(query):
- store = Store(database)
- store.execute(query)
- store.commit()
-
- @transact
- def save(self):
- store = getStore()
- store.add(self)
- store.commit()
-
-class Report(OModel):
- """
- This represents an OONI Report as stored in the database.
-
- report_id: this is generated by the backend and is used by the client to
- reference a previous report and append to it. It should be
- treated as a shared secret between the probe and backend.
-
- software_name: this indicates the name of the software performing the test
- (this will default to ooniprobe)
-
- software_version: this is the version number of the software running the
- test.
-
- test_name: the name of the test on which the report is being created.
-
- test_version: indicates the version of the test
-
- progress: what is the current progress of the report. This allows clients
- to report event partial reports up to a certain percentage of
- progress. Once the report is complete progress will be 100.
-
- content: what is the content of the report. If the current progress is less
- than 100 we should append to the YAML data structure that is
- currently stored in such field.
- """
- __storm_table__ = 'reports'
-
- createQuery = "CREATE TABLE " + __storm_table__ +\
- "(id INTEGER PRIMARY KEY, report_id VARCHAR, software_name VARCHAR,"\
- "software_version VARCHAR, test_name VARCHAR, test_version VARCHAR,"\
- "progress VARCHAR, content VARCHAR)"
-
-
- id = Int(primary=True)
-
- report_id = Unicode()
-
- software_name = Unicode()
- software_version = Unicode()
- test_name = Unicode()
- test_version = Unicode()
- progress = Unicode()
-
- content = Unicode()
-
-class TestHelperTMP(OModel):
- __storm_table__ = 'testhelpertmp'
-
- createQuery = "CREATE TABLE " + __storm_table__ +\
- "(id INTEGER PRIMARY KEY, report_id VARCHAR, test_helper VARCHAR,"\
- " client_ip VARCHAR, creation_time VARCHAR)"
-
- id = Int(primary=True)
-
- report_id = Unicode()
-
- test_helper = Unicode()
- client_ip = Unicode()
-
- creation_time = Date()
diff --git a/test_inputs/README b/test_inputs/README
new file mode 100644
index 0000000..1eff781
--- /dev/null
+++ b/test_inputs/README
@@ -0,0 +1,48 @@
+In here you will find some very simple input lists that are useful for testing
+the correct functionality of the various OONIProbe tests.
+
+# DNS Tamper
+
+./bin/ooniprobe -o dns_tamper_test.yamloo nettests/core/dnstamper.py -t test_inputs/dns_tamper_test_resolvers.txt -f test_inputs/dns_tamper_file.txt
+
+less dns_tamper_test.yamloo
+
+# Captive Portal
+
+./bin/ooniprobe -o captive_portal_test.yamloo nettests/core/captiveportal.py
+
+less captive_portal_test.yamloo
+
+# HTTP Host
+
+./bin/ooniprobe -o http_host.yamloo nettests/core/http_host.py -b http://ooni.nu/test -f test_inputs/http_host_file.txt
+
+less http_host.yamloo
+
+# Keyword filtering
+
+./bin/ooniprobe -o keyword_filtering.yamloo nettests/core/keyword_filtering.py -b http://ooni.nu/test/ -f test_inputs/keyword_filtering_file.txt
+
+less keyword_filtering.yamloo
+
+# URL List
+
+./bin/ooniprobe -o url_lists.yamloo nettests/core/url_list.py -f test_inputs/url_lists_file.txt
+
+less url_lists.yamloo
+
+# Squid transparent proxy
+
+./bin/ooniprobe -o squid.yamloo nettests/core/squid.py
+
+less squid.yamloo
+
+# HTTP Requests
+
+Not Implemented
+
+# Traceroute
+
+Not Implemented
+
+
diff --git a/test_inputs/dns_tamper_file.txt b/test_inputs/dns_tamper_file.txt
new file mode 100644
index 0000000..25f365c
--- /dev/null
+++ b/test_inputs/dns_tamper_file.txt
@@ -0,0 +1,3 @@
+torproject.org
+google.com
+measurementlab.net
diff --git a/test_inputs/dns_tamper_test_resolvers.txt b/test_inputs/dns_tamper_test_resolvers.txt
new file mode 100644
index 0000000..14c77e0
--- /dev/null
+++ b/test_inputs/dns_tamper_test_resolvers.txt
@@ -0,0 +1,2 @@
+8.8.8.8
+8.8.4.4
diff --git a/test_inputs/http_host_file.txt b/test_inputs/http_host_file.txt
new file mode 100644
index 0000000..12afb18
--- /dev/null
+++ b/test_inputs/http_host_file.txt
@@ -0,0 +1,2 @@
+torproject.org
+ooni.nu
diff --git a/test_inputs/keyword_filtering_file.txt b/test_inputs/keyword_filtering_file.txt
new file mode 100644
index 0000000..4583bae
--- /dev/null
+++ b/test_inputs/keyword_filtering_file.txt
@@ -0,0 +1,2 @@
+antani
+sblinda
diff --git a/test_inputs/url_lists_file.txt b/test_inputs/url_lists_file.txt
new file mode 100644
index 0000000..16a4f58
--- /dev/null
+++ b/test_inputs/url_lists_file.txt
@@ -0,0 +1,2 @@
+http://ooni.nu/test
+http://torproject.org/
1
0