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.
This commit is contained in:
parent
9faf5ee750
commit
350c94b900
|
@ -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 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 @@ 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):
|
||||
|
|
|
@ -7,6 +7,7 @@ import sys
|
|||
import time
|
||||
import warnings
|
||||
import errno
|
||||
import struct
|
||||
|
||||
from test import support
|
||||
from test.support import TESTFN, run_unittest, unlink
|
||||
|
@ -730,6 +731,21 @@ class BaseTestAPI(unittest.TestCase):
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue