Skip to content

Commit bf940f1

Browse files
committed
Fix sock_* methods to support already closed sockets on cancellation
1 parent 97c174a commit bf940f1

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

tests/test_sockets.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ def test_socket_close_remove_writer(self):
505505
s.close()
506506
self.assertEqual(s.fileno(), -1)
507507

508-
def test_socket_cancel_sock_recv(self):
508+
def test_socket_cancel_sock_recv_1(self):
509509
def srv_gen(sock):
510510
time.sleep(1.2)
511511
sock.send(b'helo')
@@ -534,6 +534,46 @@ async def client(sock, addr):
534534
w = asyncio.wait_for(c, timeout=5.0, loop=self.loop)
535535
self.loop.run_until_complete(w)
536536

537+
def test_socket_cancel_sock_recv_2(self):
538+
def srv_gen(sock):
539+
time.sleep(1.2)
540+
sock.send(b'helo')
541+
542+
async def kill(fut):
543+
await asyncio.sleep(0.5, loop=self.loop)
544+
fut.cancel()
545+
546+
async def recv(sock):
547+
fut = self.loop.sock_recv(sock, 10)
548+
await asyncio.sleep(0.1, loop=self.loop)
549+
self.loop.remove_reader(sock)
550+
sock.close()
551+
try:
552+
await fut
553+
except asyncio.CancelledError:
554+
raise
555+
finally:
556+
sock.close()
557+
558+
async def client(sock, addr):
559+
await self.loop.sock_connect(sock, addr)
560+
561+
f = asyncio.ensure_future(recv(sock), loop=self.loop)
562+
self.loop.create_task(kill(f))
563+
with self.assertRaises(asyncio.CancelledError):
564+
await f
565+
sock.close()
566+
self.assertEqual(sock.fileno(), -1)
567+
568+
with self.tcp_server(srv_gen) as srv:
569+
570+
sock = socket.socket()
571+
with sock:
572+
sock.setblocking(False)
573+
c = client(sock, srv.addr)
574+
w = asyncio.wait_for(c, timeout=5.0, loop=self.loop)
575+
self.loop.run_until_complete(w)
576+
537577
def test_socket_cancel_sock_sendall(self):
538578
def srv_gen(sock):
539579
time.sleep(1.2)

uvloop/loop.pyx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,15 @@ cdef class Loop:
804804

805805
cdef _new_reader_future(self, sock):
806806
def _on_cancel(fut):
807-
if fut.cancelled():
807+
# Check if the future was cancelled and if the socket
808+
# is still open, i.e.
809+
#
810+
# loop.remove_reader(sock)
811+
# sock.close()
812+
# fut.cancel()
813+
#
814+
# wasn't called by the user.
815+
if fut.cancelled() and sock.fileno() != -1:
808816
self._remove_reader(sock)
809817

810818
fut = self._new_future()
@@ -813,7 +821,7 @@ cdef class Loop:
813821

814822
cdef _new_writer_future(self, sock):
815823
def _on_cancel(fut):
816-
if fut.cancelled():
824+
if fut.cancelled() and sock.fileno() != -1:
817825
self._remove_writer(sock)
818826

819827
fut = self._new_future()

0 commit comments

Comments
 (0)