[Python-checkins] cpython (3.2): fix #10340: properly handle EINVAL on OSX and also avoid to call

giampaolo.rodola python-checkins at python.org
Thu Mar 22 16:19:53 CET 2012


http://hg.python.org/cpython/rev/e2cddb3f4526
changeset:   75881:e2cddb3f4526
branch:      3.2
parent:      75877:79422b3684f1
user:        Giampaolo Rodola' <g.rodola at gmail.com>
date:        Thu Mar 22 16:17:43 2012 +0100
summary:
  fix #10340: properly handle EINVAL on OSX and also avoid to call handle_connect() in case of a disconnetected socket which is not meant to connect.

files:
  Lib/asyncore.py           |  17 +++++++++--------
  Lib/test/test_asyncore.py |  16 ++++++++++++++++
  2 files changed, 25 insertions(+), 8 deletions(-)


diff --git a/Lib/asyncore.py b/Lib/asyncore.py
--- a/Lib/asyncore.py
+++ b/Lib/asyncore.py
@@ -225,6 +225,7 @@
     debug = False
     connected = False
     accepting = False
+    connecting = False
     closing = False
     addr = None
     ignore_log_types = frozenset(['warning'])
@@ -248,7 +249,7 @@
             try:
                 self.addr = sock.getpeername()
             except socket.error as 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 @@
 
     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 @@
     def close(self):
         self.connected = False
         self.accepting = False
+        self.connecting = False
         self.del_channel()
         try:
             self.socket.close()
@@ -439,7 +442,8 @@
             # 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 @@
             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 @@
             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):
diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py
--- a/Lib/test/test_asyncore.py
+++ b/Lib/test/test_asyncore.py
@@ -7,6 +7,7 @@
 import time
 import warnings
 import errno
+import struct
 
 from test import support
 from test.support import TESTFN, run_unittest, unlink
@@ -730,6 +731,21 @@
         finally:
             sock.close()
 
+    @unittest.skipUnless(threading, 'Threading required for this 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 range(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

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list