commit fb876074f1c040a6bdcf0e7489ca5e07d5ce428f Author: George Kadianakis desnacked@gmail.com Date: Fri Aug 19 05:29:09 2011 +0200
Fix a problem when receiving test files in tester.py.
The workers of tester.py used to socket.recv() till they got zero-length data. That's usually caused by "EOF" or by the other side of the socket closing.
A python string (TEST_FILE) don't cause an "EOF" and obfsproxy doesn't close its sockets since it's supposed to stream data continuously. So, how did the integration tests work? tester.py used to socket.shutdown(socket.SHUT_WR) the upstream part of the connection right after sending the test file, which resulted in obfsproxy conn_free'ing the whole 'circuit'; including the downstream side. That used to return zero-length data to recv() and that's how it was getting out of the ReadWorker:work().
In the case of handshake-less protocols (like 'dummy') that was okay, since the data were ultimately transferred to the server's destination by conn_flush_and_free()s. The thing is that in protocols like obfs2, the handshake couldn't be completed since the whole 'circuit' was torn down. And that's why obfs2 tests did not work.
This patch uses socket.timeout instead of zero-length data to get out of the recv() loop.
Conflicts:
src/test/tester.py.in --- src/test/tester.py.in | 45 ++++++++++++++++++++++++++------------------- 1 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/src/test/tester.py.in b/src/test/tester.py.in index 55d9477..4b93784 100644 --- a/src/test/tester.py.in +++ b/src/test/tester.py.in @@ -102,6 +102,8 @@ def connect_with_retry(addr): retry += 1 time.sleep(0.05)
+SOCKET_TIMEOUT = 1.0 + # Helper: In a separate process (to avoid deadlock), listen on a # specified socket. The first time something connects to that socket, # read all available data, stick it in a string, and post the string @@ -116,13 +118,15 @@ class ReadWorker(object): listener.listen(1) (conn, remote) = listener.accept() listener.close() - conn.settimeout(1.0) + conn.settimeout(SOCKET_TIMEOUT) data = "" try: while True: chunk = conn.recv(4096) if chunk == "": break data += chunk + except socket.timeout: + pass except Exception, e: data += "|RECV ERROR: " + e conn.close() @@ -135,7 +139,7 @@ class ReadWorker(object): self.worker.start()
def get(self): - rv = self.oq.get(timeout=1) + rv = self.oq.get(timeout=SOCKET_TIMEOUT+0.1) self.worker.join() return rv
@@ -162,7 +166,7 @@ class DirectTest(object): self.output_reader = ReadWorker(("127.0.0.1", EXIT_PORT)) self.obfs = Obfsproxy(self.obfs_args) self.input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT)) - self.input_chan.settimeout(1.0) + self.input_chan.settimeout(SOCKET_TIMEOUT)
def tearDown(self): self.obfs.stop() @@ -174,12 +178,13 @@ class DirectTest(object): # transfer a file. Then check whether the output is the same # as the input. self.input_chan.sendall(TEST_FILE) - self.input_chan.shutdown(socket.SHUT_WR) try: output = self.output_reader.get() except Queue.Empty: output = ""
+ self.input_chan.close() + report = diff("errors in transfer:", TEST_FILE, output)
report += self.obfs.check_completion("obfsproxy", report!="") @@ -243,20 +248,22 @@ class SocksTest(object): if e.errno != errno.ECONNRESET: raise self.assertEqual(got, exp) sending = not sending + if good: input_chan.sendall(TEST_FILE) - input_chan.shutdown(socket.SHUT_WR) try: output = self.output_reader.get() except Queue.Empty: output = ""
+ input_chan.close() + if good: return output else: return None
def socksTest(self, sequence): input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT)) - input_chan.settimeout(1.0) + input_chan.settimeout(SOCKET_TIMEOUT)
try: output = self.socksTestInner(sequence, input_chan) @@ -352,13 +359,13 @@ class SocksBad(SocksTest, unittest.TestCase): #
# fails, disabled -#class DirectObfs2(DirectTest, unittest.TestCase): -# obfs_args = ("obfs2", -# "--dest=127.0.0.1:%d" % EXIT_PORT, -# "server", "127.0.0.1:%d" % SERVER_PORT, -# "obfs2", -# "--dest=127.0.0.1:%d" % SERVER_PORT, -# "client", "127.0.0.1:%d" % ENTRY_PORT) +class DirectObfs2(DirectTest, unittest.TestCase): + obfs_args = ("obfs2", + "--dest=127.0.0.1:%d" % EXIT_PORT, + "server", "127.0.0.1:%d" % SERVER_PORT, + "obfs2", + "--dest=127.0.0.1:%d" % SERVER_PORT, + "client", "127.0.0.1:%d" % ENTRY_PORT)
class DirectDummy(DirectTest, unittest.TestCase): obfs_args = ("dummy", "server", @@ -369,12 +376,12 @@ class DirectDummy(DirectTest, unittest.TestCase): "127.0.0.1:%d" % SERVER_PORT)
# fails, disabled -#class SocksObfs2(GoodSocksTest, unittest.TestCase): -# server_args = ("obfs2", -# "--dest=127.0.0.1:%d" % EXIT_PORT, -# "server", "127.0.0.1:%d" % SERVER_PORT) -# client_args = ("obfs2", -# "socks", "127.0.0.1:%d" % ENTRY_PORT) +class SocksObfs2(GoodSocksTest, unittest.TestCase): + server_args = ("obfs2", + "--dest=127.0.0.1:%d" % EXIT_PORT, + "server", "127.0.0.1:%d" % SERVER_PORT) + client_args = ("obfs2", + "socks", "127.0.0.1:%d" % ENTRY_PORT)
class SocksDummy(GoodSocksTest, unittest.TestCase): server_args = ("dummy", "server",