From 15d44adde98fec2e466e1a7fd1ff3979709ffc8d Mon Sep 17 00:00:00 2001 From: Stan Hatko Date: Thu, 12 Sep 2024 21:46:39 -0400 Subject: [PATCH 1/3] Fix bug that when accepting a socket connection and ERROR_NETNAME_DELETED occurs, leads this into a closing of the serving socket This is done with the patches described by fercod in the GitHub thread https://github.com/python/cpython/issues/93821. These patches were successfully tested by me and worked properly. The error propagates properly without closing the original socket and without causing the server to hang. --- Lib/asyncio/proactor_events.py | 2 ++ Lib/asyncio/windows_events.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 7eb55bd63ddb73..d4320772e10064 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -858,6 +858,8 @@ def loop(f=None): if self.is_closed(): return f = self._proactor.accept(sock) + except ConnectionResetError: + self.call_soon(loop) 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..4b590b904ec715 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -553,7 +553,16 @@ def accept(self, listener): ov.AcceptEx(listener.fileno(), conn.fileno()) def finish_accept(trans, key, ov): - ov.getresult() + try: + ov.getresult() + except OSError as exc: + # Fix bug when accepting a socket connection and ERROR_NETNAME_DELETED + # occurs, leads this into a closing of the serving socket. + if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, + _overlapped.ERROR_OPERATION_ABORTED): + conn.close() + raise ConnectionResetError(*exc.args) + raise # Use SO_UPDATE_ACCEPT_CONTEXT so getsockname() etc work. buf = struct.pack('@P', listener.fileno()) conn.setsockopt(socket.SOL_SOCKET, From b61114cd7a4a52db25e04da9a96ebcb931090d08 Mon Sep 17 00:00:00 2001 From: Stan Hatko Date: Thu, 12 Sep 2024 21:53:06 -0400 Subject: [PATCH 2/3] On UNIX-like systems don't fail because winerror is not available --- Lib/asyncio/windows_events.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index 4b590b904ec715..58e53a3ef00af9 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -558,7 +558,8 @@ def finish_accept(trans, key, ov): except OSError as exc: # Fix bug when accepting a socket connection and ERROR_NETNAME_DELETED # occurs, leads this into a closing of the serving socket. - if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, + if hasattr(exc, 'winerror') and exc.winerror in ( + _overlapped.ERROR_NETNAME_DELETED, _overlapped.ERROR_OPERATION_ABORTED): conn.close() raise ConnectionResetError(*exc.args) From a5fcc88b56922761a0dfd8f5978f2926ca54a328 Mon Sep 17 00:00:00 2001 From: StanHatko <38304828+StanHatko@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:09:53 -0400 Subject: [PATCH 3/3] Omit unnecessary winerror check and improve comment No need for checking winerror present as windows_events.py only imported on Windows (with check near top). Make comment more clear as to purpose of this patch. --- Lib/asyncio/windows_events.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py index 58e53a3ef00af9..84f4bbdc45fb9c 100644 --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -556,10 +556,9 @@ def finish_accept(trans, key, ov): try: ov.getresult() except OSError as exc: - # Fix bug when accepting a socket connection and ERROR_NETNAME_DELETED - # occurs, leads this into a closing of the serving socket. - if hasattr(exc, 'winerror') and exc.winerror in ( - _overlapped.ERROR_NETNAME_DELETED, + # If ERROR_NETNAME_DELETED or ERROR_OPERATION_ABORTED occur, + # do not close the serving socket. + if exc.winerror in (_overlapped.ERROR_NETNAME_DELETED, _overlapped.ERROR_OPERATION_ABORTED): conn.close() raise ConnectionResetError(*exc.args)