Skip to content

Commit d112929

Browse files
miss-islingtondevanshc777asvetlov
authored
[3.15] gh-160429: Ignore ConnectionResetError from shutdown() when closing proactor sockets (GH-160909) (#161391)
gh-160429: Ignore ConnectionResetError from shutdown() when closing proactor sockets (GH-160909) * gh-160429: Ignore ConnectionResetError from shutdown() when closing proactor sockets * Update Lib/asyncio/proactor_events.py --------- (cherry picked from commit 7b06d6f) Co-authored-by: Zap777 <124182405+devanshc777@users.noreply.github.com> Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
1 parent 57e3d34 commit d112929

3 files changed

Lines changed: 23 additions & 1 deletion

File tree

‎Lib/asyncio/proactor_events.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,12 @@ def _call_connection_lost(self, exc):
164164
# just close our end. First calling shutdown() seems to
165165
# cure it, but maybe using DisconnectEx() would be better.
166166
if hasattr(self._sock, 'shutdown') and self._sock.fileno() != -1:
167-
self._sock.shutdown(socket.SHUT_RDWR)
167+
try:
168+
self._sock.shutdown(socket.SHUT_RDWR)
169+
except ConnectionError:
170+
# The connection is already gone.
171+
# The peer has already reset the connection.
172+
pass
168173
self._sock.close()
169174
self._sock = None
170175
server = self._server

‎Lib/test/test_asyncio/test_proactor_events.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,20 @@ def test_call_connection_lost(self):
336336
self.assertTrue(self.protocol.connection_lost.called)
337337
self.assertTrue(self.sock.close.called)
338338

339+
def test_call_connection_lost_shutdown_reset(self):
340+
# gh-160429: a ConnectionResetError from shutdown() must not skip
341+
# closing the socket and detaching the transport from its server.
342+
server = mock.Mock()
343+
tr = _ProactorSocketTransport(self.loop, self.sock, self.protocol,
344+
server=server)
345+
self.sock.shutdown.side_effect = ConnectionResetError
346+
tr._call_connection_lost(None)
347+
self.protocol.connection_lost.assert_called_once_with(None)
348+
self.sock.close.assert_called_once_with()
349+
server._detach.assert_called_once_with(tr)
350+
self.assertIsNone(tr._sock)
351+
self.assertTrue(tr._called_connection_lost)
352+
339353
def test_write_eof(self):
340354
tr = self.socket_transport()
341355
self.assertTrue(tr.can_write_eof())
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :class:`asyncio.ProactorEventLoop` socket transports leaving the socket
2+
open, and :meth:`asyncio.Server.wait_closed` hanging, when the peer resets
3+
the connection while the transport is being closed.

0 commit comments

Comments
 (0)