Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit eeeebcd

Browse files
committed
asyncio: Synchronize with Tulip
* Issue #159: Fix windows_utils.socketpair() - Use "127.0.0.1" (IPv4) or "::1" (IPv6) host instead of "localhost", because "localhost" may be a different IP address - Reject also invalid arguments: only AF_INET/AF_INET6 with SOCK_STREAM (and proto=0) are supported * Reject add/remove reader/writer when event loop is closed. * Fix ResourceWarning warnings
1 parent c5cc501 commit eeeebcd

4 files changed

Lines changed: 73 additions & 6 deletions

File tree

Lib/asyncio/selector_events.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ def _accept_connection(self, protocol_factory, sock,
136136

137137
def add_reader(self, fd, callback, *args):
138138
"""Add a reader callback."""
139+
if self._selector is None:
140+
raise RuntimeError('Event loop is closed')
139141
handle = events.Handle(callback, args, self)
140142
try:
141143
key = self._selector.get_key(fd)
@@ -151,6 +153,8 @@ def add_reader(self, fd, callback, *args):
151153

152154
def remove_reader(self, fd):
153155
"""Remove a reader callback."""
156+
if self._selector is None:
157+
return False
154158
try:
155159
key = self._selector.get_key(fd)
156160
except KeyError:
@@ -171,6 +175,8 @@ def remove_reader(self, fd):
171175

172176
def add_writer(self, fd, callback, *args):
173177
"""Add a writer callback.."""
178+
if self._selector is None:
179+
raise RuntimeError('Event loop is closed')
174180
handle = events.Handle(callback, args, self)
175181
try:
176182
key = self._selector.get_key(fd)
@@ -186,6 +192,8 @@ def add_writer(self, fd, callback, *args):
186192

187193
def remove_writer(self, fd):
188194
"""Remove a writer callback."""
195+
if self._selector is None:
196+
return False
189197
try:
190198
key = self._selector.get_key(fd)
191199
except KeyError:

Lib/asyncio/windows_utils.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,25 @@ def socketpair(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
3636
3737
Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
3838
"""
39+
if family == socket.AF_INET:
40+
host = '127.0.0.1'
41+
elif family == socket.AF_INET6:
42+
host = '::1'
43+
else:
44+
raise ValueError("Ony AF_INET and AF_INET6 socket address families "
45+
"are supported")
46+
if type != socket.SOCK_STREAM:
47+
raise ValueError("Only SOCK_STREAM socket type is supported")
48+
if proto != 0:
49+
raise ValueError("Only protocol zero is supported")
50+
3951
# We create a connected TCP socket. Note the trick with setblocking(0)
4052
# that prevents us from having to create a thread.
4153
lsock = socket.socket(family, type, proto)
42-
lsock.bind(('localhost', 0))
54+
lsock.bind((host, 0))
4355
lsock.listen(1)
44-
addr, port = lsock.getsockname()
56+
# On IPv6, ignore flow_info and scope_id
57+
addr, port = lsock.getsockname()[:2]
4558
csock = socket.socket(family, type, proto)
4659
csock.setblocking(False)
4760
try:

Lib/test/test_asyncio/test_events.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,30 @@ def test_sock_connect_address(self):
13261326
self.assertIn('address must be resolved',
13271327
str(cm.exception))
13281328

1329+
def test_remove_fds_after_closing(self):
1330+
loop = self.create_event_loop()
1331+
callback = lambda: None
1332+
r, w = test_utils.socketpair()
1333+
self.addCleanup(r.close)
1334+
self.addCleanup(w.close)
1335+
loop.add_reader(r, callback)
1336+
loop.add_writer(w, callback)
1337+
loop.close()
1338+
self.assertFalse(loop.remove_reader(r))
1339+
self.assertFalse(loop.remove_writer(w))
1340+
1341+
def test_add_fds_after_closing(self):
1342+
loop = self.create_event_loop()
1343+
callback = lambda: None
1344+
r, w = test_utils.socketpair()
1345+
self.addCleanup(r.close)
1346+
self.addCleanup(w.close)
1347+
loop.close()
1348+
with self.assertRaises(RuntimeError):
1349+
loop.add_reader(r, callback)
1350+
with self.assertRaises(RuntimeError):
1351+
loop.add_writer(w, callback)
1352+
13291353

13301354
class SubprocessTestsMixin:
13311355

@@ -1632,6 +1656,9 @@ def test_writer_callback_cancel(self):
16321656
def test_create_datagram_endpoint(self):
16331657
raise unittest.SkipTest(
16341658
"IocpEventLoop does not have create_datagram_endpoint()")
1659+
1660+
def test_remove_fds_after_closing(self):
1661+
raise unittest.SkipTest("IocpEventLoop does not have add_reader()")
16351662
else:
16361663
from asyncio import selectors
16371664

Lib/test/test_asyncio/test_windows_utils.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Tests for window_utils"""
22

3+
import socket
34
import sys
45
import test.support
56
import unittest
7+
from test.support import IPV6_ENABLED
68
from unittest import mock
79

810
if sys.platform != 'win32':
@@ -16,23 +18,40 @@
1618

1719
class WinsocketpairTests(unittest.TestCase):
1820

19-
def test_winsocketpair(self):
20-
ssock, csock = windows_utils.socketpair()
21-
21+
def check_winsocketpair(self, ssock, csock):
2222
csock.send(b'xxx')
2323
self.assertEqual(b'xxx', ssock.recv(1024))
24-
2524
csock.close()
2625
ssock.close()
2726

27+
def test_winsocketpair(self):
28+
ssock, csock = windows_utils.socketpair()
29+
self.check_winsocketpair(ssock, csock)
30+
31+
@unittest.skipUnless(IPV6_ENABLED, 'IPv6 not supported or enabled')
32+
def test_winsocketpair_ipv6(self):
33+
ssock, csock = windows_utils.socketpair(family=socket.AF_INET6)
34+
self.check_winsocketpair(ssock, csock)
35+
2836
@mock.patch('asyncio.windows_utils.socket')
2937
def test_winsocketpair_exc(self, m_socket):
38+
m_socket.AF_INET = socket.AF_INET
39+
m_socket.SOCK_STREAM = socket.SOCK_STREAM
3040
m_socket.socket.return_value.getsockname.return_value = ('', 12345)
3141
m_socket.socket.return_value.accept.return_value = object(), object()
3242
m_socket.socket.return_value.connect.side_effect = OSError()
3343

3444
self.assertRaises(OSError, windows_utils.socketpair)
3545

46+
def test_winsocketpair_invalid_args(self):
47+
self.assertRaises(ValueError,
48+
windows_utils.socketpair, family=socket.AF_UNSPEC)
49+
self.assertRaises(ValueError,
50+
windows_utils.socketpair, type=socket.SOCK_DGRAM)
51+
self.assertRaises(ValueError,
52+
windows_utils.socketpair, proto=1)
53+
54+
3655

3756
class PipeTests(unittest.TestCase):
3857

0 commit comments

Comments
 (0)