From: Ben Darnell Date: Tue, 22 Feb 2011 21:35:41 +0000 (-0800) Subject: Check for EOF in the kqueue-based IOLoop to avoid incorrectly calling X-Git-Tag: v2.0.0~127 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb8736cdf139af178bd3b69e9d0e78fc799c3271;p=thirdparty%2Ftornado.git Check for EOF in the kqueue-based IOLoop to avoid incorrectly calling the connect callback when the connection was refused. Closes #223. --- diff --git a/tornado/ioloop.py b/tornado/ioloop.py index a7445d7cd..62b2b0900 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -490,7 +490,17 @@ class _KQueue(object): if kevent.filter == select.KQ_FILTER_READ: events[fd] = events.get(fd, 0) | IOLoop.READ if kevent.filter == select.KQ_FILTER_WRITE: - events[fd] = events.get(fd, 0) | IOLoop.WRITE + if kevent.flags & select.KQ_EV_EOF: + # If an asynchronous connection is refused, kqueue + # returns a write event with the EOF flag set. + # Turn this into an error for consistency with the + # other IOLoop implementations. + # Note that for read events, EOF may be returned before + # all data has been consumed from the socket buffer, + # so we only check for EOF on write events. + events[fd] = IOLoop.ERROR + else: + events[fd] = events.get(fd, 0) | IOLoop.WRITE if kevent.flags & select.KQ_EV_ERROR: events[fd] = events.get(fd, 0) | IOLoop.ERROR return events.items() diff --git a/tornado/test/iostream_test.py b/tornado/test/iostream_test.py index 8e0d64f5c..48ccd4a6c 100644 --- a/tornado/test/iostream_test.py +++ b/tornado/test/iostream_test.py @@ -1,5 +1,5 @@ from tornado.iostream import IOStream -from tornado.testing import AsyncHTTPTestCase, LogTrapTestCase +from tornado.testing import AsyncHTTPTestCase, LogTrapTestCase, get_unused_port from tornado.web import RequestHandler, Application import socket @@ -31,3 +31,18 @@ class TestIOStream(AsyncHTTPTestCase, LogTrapTestCase): self.stream.read_bytes(3, self.stop) data = self.wait() self.assertEqual(data, "200") + + def test_connection_refused(self): + # When a connection is refused, the connect callback should not + # be run. (The kqueue IOLoop used to behave differently from the + # epoll IOLoop in this respect) + port = get_unused_port() + stream = IOStream(socket.socket(), self.io_loop) + self.connect_called = False + def connect_callback(): + self.connect_called = True + stream.set_close_callback(self.stop) + stream.connect(("localhost", port), connect_callback) + self.wait() + self.assertFalse(self.connect_called) +