]> granicus.if.org Git - python/commitdiff
fix #10340: properly handle EINVAL on OSX and also avoid to call handle_connect(...
authorGiampaolo Rodola' <g.rodola@gmail.com>
Thu, 22 Mar 2012 15:06:43 +0000 (16:06 +0100)
committerGiampaolo Rodola' <g.rodola@gmail.com>
Thu, 22 Mar 2012 15:06:43 +0000 (16:06 +0100)
Lib/asyncore.py
Lib/test/test_asyncore.py
Misc/NEWS

index d8d28a467be6ef0d4ddd39600b27459f6061a139..a281e786fb85aff1190169254d3a94c1580bcad1 100644 (file)
@@ -225,6 +225,7 @@ class dispatcher:
     debug = False
     connected = False
     accepting = False
+    connecting = False
     closing = False
     addr = None
     ignore_log_types = frozenset(['warning'])
@@ -248,7 +249,7 @@ class dispatcher:
             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
@@ -342,6 +343,7 @@ class dispatcher:
 
     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'):
@@ -401,6 +403,7 @@ class dispatcher:
     def close(self):
         self.connected = False
         self.accepting = False
+        self.connecting = False
         self.del_channel()
         try:
             self.socket.close()
@@ -439,7 +442,8 @@ class dispatcher:
             # sockets that are connected
             self.handle_accept()
         elif not self.connected:
-            self.handle_connect_event()
+            if self.connecting:
+                self.handle_connect_event()
             self.handle_read()
         else:
             self.handle_read()
@@ -450,6 +454,7 @@ class dispatcher:
             raise socket.error(err, _strerror(err))
         self.handle_connect()
         self.connected = True
+        self.connecting = False
 
     def handle_write_event(self):
         if self.accepting:
@@ -458,12 +463,8 @@ class dispatcher:
             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()
+            if self.connecting:
+                self.handle_connect_event()
         self.handle_write()
 
     def handle_expt_event(self):
index 7d1a3cb33ff9a7b4aa1f861038fedb70ac2fbca8..f2fbc589c38d762ec9a9087898d93968a73ae712 100644 (file)
@@ -7,6 +7,7 @@ import sys
 import time
 import warnings
 import errno
+import struct
 
 from test import test_support
 from test.test_support import TESTFN, run_unittest, unlink
@@ -703,6 +704,21 @@ class BaseTestAPI(unittest.TestCase):
         finally:
             sock.close()
 
+    @unittest.skipUnless(threading, 'Threading required for this test.')
+    @test_support.reap_threads
+    def test_quick_connect(self):
+        # see: http://bugs.python.org/issue10340
+        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
index 1994d38932086b1539f5157463e17065a5ceae6d..b39c1d694a8ff1a3c73e32b10e4e6aad0edd6422 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -30,6 +30,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on
+  OSX; avoid to call handle_connect in case of a disconnected socket which
+  was not meant to connect.
+
 - Issue #12757: Fix the skipping of doctests when python is run with -OO so
   that it works in unittest's verbose mode as well as non-verbose mode.