From cf9aa61ab687373d3ffa256045943484971734f6 Mon Sep 17 00:00:00 2001 From: Corey Bird Date: Sun, 29 Sep 2024 20:53:06 -0600 Subject: [PATCH 1/5] Handle connection resets on Windows Refactor OSError re-throwing and wrap all instances of 'ov.getresult()' with the decorator so that client-side disconnects can be gracefully handled. Update the Proactor server to handle the connection and continue looping and serving (client disconnects are not a fatal error). --- Lib/asyncio/proactor_events.py | 4 ++++ Lib/asyncio/windows_events.py | 31 +++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 7eb55bd63ddb73..3dc9d765b0a37a 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -858,6 +858,10 @@ def loop(f=None): if self.is_closed(): return f = self._proactor.accept(sock) + except exceptions.CancelledError: + # Effectively ignore connections that throw a cancelled error + # during setup, loop back around and continue serving. + sock.close() except OSError as exc: if sock.fileno() != -1: self.call_exception_handler({ diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index bf99bc271c7acd..1c70fc7559ddb8 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -414,6 +414,24 @@ async def _make_subprocess_transport(self, protocol, args, shell, return transp +def overlapped_connection_reset_error_handler(func): + """ + Rethrow common connection errors that come from clients + disconnecting unexpectedly. This is a common error that + can be safely ignored in most cases. + """ + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except OSError as exc: + if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, + _overlapped.ERROR_OPERATION_ABORTED): + raise ConnectionResetError(*exc.args) + else: + raise + return wrapper + + class IocpProactor: """Proactor implementation using IOCP.""" @@ -458,15 +476,9 @@ def _result(self, value): return fut @staticmethod + @overlapped_connection_reset_error_handler def finish_socket_func(trans, key, ov): - try: - return ov.getresult() - except OSError as exc: - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, - _overlapped.ERROR_OPERATION_ABORTED): - raise ConnectionResetError(*exc.args) - else: - raise + return ov.getresult() @classmethod def _finish_recvfrom(cls, trans, key, ov, *, empty_result): @@ -552,6 +564,7 @@ def accept(self, listener): ov = _overlapped.Overlapped(NULL) ov.AcceptEx(listener.fileno(), conn.fileno()) + @overlapped_connection_reset_error_handler def finish_accept(trans, key, ov): ov.getresult() # Use SO_UPDATE_ACCEPT_CONTEXT so getsockname() etc work. @@ -596,6 +609,7 @@ def connect(self, conn, address): ov = _overlapped.Overlapped(NULL) ov.ConnectEx(conn.fileno(), address) + @overlapped_connection_reset_error_handler def finish_connect(trans, key, ov): ov.getresult() # Use SO_UPDATE_CONNECT_CONTEXT so getsockname() etc work. @@ -628,6 +642,7 @@ def accept_pipe(self, pipe): # completion of the connection. return self._result(pipe) + @overlapped_connection_reset_error_handler def finish_accept_pipe(trans, key, ov): ov.getresult() return pipe From c41f32a10e8b1807e4d65f9d2aaa0536af7a7c5c Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 03:17:50 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst new file mode 100644 index 00000000000000..e411268d926a45 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst @@ -0,0 +1 @@ +Fix error handling in `windows_events.py` where clients terminating connections could result in an asyncio server using Proactor event loops to hang indefinitely. From ae9e5458f34220123b99f53eeeed9f807b7ec06c Mon Sep 17 00:00:00 2001 From: Corey Bird Date: Sun, 29 Sep 2024 21:39:41 -0600 Subject: [PATCH 3/5] Fix blurb text not passing linter --- .../2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst index e411268d926a45..5366f4fbddf0ba 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst @@ -1 +1 @@ -Fix error handling in `windows_events.py` where clients terminating connections could result in an asyncio server using Proactor event loops to hang indefinitely. +Fix error handling in windows_events.py where clients terminating connections could result in an asyncio server using Proactor event loops to hang indefinitely. From 1de9339ebd151e2ee6ac364c1c8f1c58cddbff6b Mon Sep 17 00:00:00 2001 From: Corey Bird Date: Sun, 29 Sep 2024 21:52:29 -0600 Subject: [PATCH 4/5] Tweak blurb text to avoid py:obj checker --- .../2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst index 5366f4fbddf0ba..33cf16bdd68771 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst @@ -1 +1 @@ -Fix error handling in windows_events.py where clients terminating connections could result in an asyncio server using Proactor event loops to hang indefinitely. +Fix error handling in windows events where clients terminating connections could result in an asyncio server using Proactor event loops to hang indefinitely. From af5f035cda9314a009085c93472a198e9f20dac0 Mon Sep 17 00:00:00 2001 From: Corey Bird Date: Wed, 2 Oct 2024 21:55:38 -0600 Subject: [PATCH 5/5] Add link to :mod:`asyncio` Keep docs better organized by linking the module the change was destined for. --- .../2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst index 33cf16bdd68771..fdbcce5dd92e7a 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-09-30-03-17-49.gh-issue-93821.5L0mkX.rst @@ -1 +1 @@ -Fix error handling in windows events where clients terminating connections could result in an asyncio server using Proactor event loops to hang indefinitely. +Fix error handling in windows events where clients terminating connections could result in an :mod:`asyncio` server using Proactor event loops to hang indefinitely.