mirror of https://github.com/python/cpython
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
|
debug = False
|
||||||
connected = False
|
connected = False
|
||||||
accepting = False
|
accepting = False
|
||||||
|
connecting = False
|
||||||
closing = False
|
closing = False
|
||||||
addr = None
|
addr = None
|
||||||
ignore_log_types = frozenset(['warning'])
|
ignore_log_types = frozenset(['warning'])
|
||||||
|
@ -248,7 +249,7 @@ class dispatcher:
|
||||||
try:
|
try:
|
||||||
self.addr = sock.getpeername()
|
self.addr = sock.getpeername()
|
||||||
except socket.error as err:
|
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
|
# To handle the case where we got an unconnected
|
||||||
# socket.
|
# socket.
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
@ -342,6 +343,7 @@ class dispatcher:
|
||||||
|
|
||||||
def connect(self, address):
|
def connect(self, address):
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
self.connecting = True
|
||||||
err = self.socket.connect_ex(address)
|
err = self.socket.connect_ex(address)
|
||||||
if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \
|
if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \
|
||||||
or err == EINVAL and os.name in ('nt', 'ce'):
|
or err == EINVAL and os.name in ('nt', 'ce'):
|
||||||
|
@ -401,6 +403,7 @@ class dispatcher:
|
||||||
def close(self):
|
def close(self):
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.accepting = False
|
self.accepting = False
|
||||||
|
self.connecting = False
|
||||||
self.del_channel()
|
self.del_channel()
|
||||||
try:
|
try:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
|
@ -439,7 +442,8 @@ class dispatcher:
|
||||||
# sockets that are connected
|
# sockets that are connected
|
||||||
self.handle_accept()
|
self.handle_accept()
|
||||||
elif not self.connected:
|
elif not self.connected:
|
||||||
self.handle_connect_event()
|
if self.connecting:
|
||||||
|
self.handle_connect_event()
|
||||||
self.handle_read()
|
self.handle_read()
|
||||||
else:
|
else:
|
||||||
self.handle_read()
|
self.handle_read()
|
||||||
|
@ -450,6 +454,7 @@ class dispatcher:
|
||||||
raise socket.error(err, _strerror(err))
|
raise socket.error(err, _strerror(err))
|
||||||
self.handle_connect()
|
self.handle_connect()
|
||||||
self.connected = True
|
self.connected = True
|
||||||
|
self.connecting = False
|
||||||
|
|
||||||
def handle_write_event(self):
|
def handle_write_event(self):
|
||||||
if self.accepting:
|
if self.accepting:
|
||||||
|
@ -458,12 +463,8 @@ class dispatcher:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
#check for errors
|
if self.connecting:
|
||||||
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
|
self.handle_connect_event()
|
||||||
if err != 0:
|
|
||||||
raise socket.error(err, _strerror(err))
|
|
||||||
|
|
||||||
self.handle_connect_event()
|
|
||||||
self.handle_write()
|
self.handle_write()
|
||||||
|
|
||||||
def handle_expt_event(self):
|
def handle_expt_event(self):
|
||||||
|
|
|
@ -7,6 +7,7 @@ import sys
|
||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
import errno
|
import errno
|
||||||
|
import struct
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import TESTFN, run_unittest, unlink
|
from test.support import TESTFN, run_unittest, unlink
|
||||||
|
@ -730,6 +731,21 @@ class BaseTestAPI(unittest.TestCase):
|
||||||
finally:
|
finally:
|
||||||
sock.close()
|
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):
|
class TestAPI_UseSelect(BaseTestAPI):
|
||||||
use_poll = False
|
use_poll = False
|
||||||
|
|
Loading…
Reference in New Issue