Index: Lib/asyncore.py =================================================================== --- Lib/asyncore.py (revisione 86084) +++ Lib/asyncore.py (copia locale) @@ -56,6 +56,8 @@ from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EINTR, EISCONN, EBADF, ECONNABORTED, errorcode +_DISCONNECTED = frozenset([ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED]) + try: socket_map except NameError: @@ -218,6 +220,7 @@ debug = False connected = False + connecting = False accepting = False closing = False addr = None @@ -242,7 +245,7 @@ try: self.addr = sock.getpeername() except socket.error, err: - if err.args[0] == ENOTCONN: + if err.args[0] in (ENOTCONN, EINVAL): # To handle the case where we got an unconnected # socket. self.connected = False @@ -336,6 +339,7 @@ def connect(self, address): self.connected = False + self.connecting = True err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): @@ -367,7 +371,7 @@ except socket.error, why: if why.args[0] == EWOULDBLOCK: return 0 - elif why.args[0] in (ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED): + elif why.args[0] in _DISCONNECTED: self.handle_close() return 0 else: @@ -385,7 +389,7 @@ return data except socket.error, why: # winsock sometimes throws ENOTCONN - if why.args[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED]: + if why.args[0] in _DISCONNECTED: self.handle_close() return '' else: @@ -393,6 +397,7 @@ def close(self): self.connected = False + self.connecting = False self.accepting = False self.del_channel() try: @@ -432,17 +437,24 @@ # sockets that are connected self.handle_accept() elif not self.connected: - self.handle_connect_event() - self.handle_read() + if self.connecting: + self.handle_connect_event() + if self.connected: + self.handle_read() else: self.handle_read() def handle_connect_event(self): err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) if err != 0: + if err in _DISCONNECTED: + # remote peer quickly disconnected; let's pretend + # it never happened + return raise socket.error(err, _strerror(err)) self.handle_connect() self.connected = True + self.connecting = False def handle_write_event(self): if self.accepting: @@ -451,11 +463,6 @@ return if not self.connected: - #check for errors - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err != 0: - raise socket.error(err, _strerror(err)) - self.handle_connect_event() self.handle_write() Index: Lib/test/test_asyncore.py =================================================================== --- Lib/test/test_asyncore.py (revisione 86083) +++ Lib/test/test_asyncore.py (copia locale) @@ -7,6 +7,7 @@ import time import warnings import errno +import struct from test import test_support from test.test_support import TESTFN, run_unittest, unlink @@ -482,8 +483,10 @@ return self.socket.getsockname()[:2] def handle_accept(self): - sock, addr = self.accept() - self.handler(sock) + pair = self.accept() + if pair is not None: + sock, addr = pair + self.handler(sock) def handle_error(self): raise @@ -499,6 +502,9 @@ def handle_connect(self): pass + def handle_error(self): + raise + class BaseTestAPI(unittest.TestCase): @@ -702,6 +708,21 @@ finally: sock.close() + @unittest.skipUnless(threading, 'Threading required for this test.') + @test_support.reap_threads + def test_quick_connect(self): + server = TCPServer() + t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500)) + t.start() + + for x in xrange(20): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + s.connect(server.address) + s.close() + + class TestAPI_UseSelect(BaseTestAPI): use_poll = False