From d93fe6c6e66be94b9e68b6980aaf77dbb276bbe7 Mon Sep 17 00:00:00 2001
From: Antoine Martin <antoine@xpra.org>
Date: Wed, 3 Jan 2024 22:10:36 +0000
Subject: [PATCH] always use force_close_connection so errors will be caught

and silenced, the only errors we can hit here are due to the sockets already being closed and we don't care about that, we just want to make sure we don't leak resources
---
 xpra/server/core.py | 32 +++++++++++++++-----------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/xpra/server/core.py b/xpra/server/core.py
index c8fb36ca63..33a0cb90a1 100644
--- a/xpra/server/core.py
+++ b/xpra/server/core.py
@@ -142,6 +142,13 @@ def _filter_display_dict(display_dict, *whitelist):
     return displays_info
 
 
+def force_close_connection(conn) -> None:
+    try:
+        conn.close()
+    except OSError:
+        log("close_connection()", exc_info=True)
+
+
 class ServerCore:
     """
         This is the simplest base class for servers.
@@ -1104,7 +1111,7 @@ def _new_connection(self, socktype: str, listener, handle: int=0):
         if socktype != "socket" and len(self._potential_protocols) >= self._max_connections:
             netlog.error("Error: too many connections (%i)", len(self._potential_protocols))
             netlog.error(" ignoring new one: %s", conn.endpoint)
-            conn.close()
+            force_close_connection(conn)
             return True
         # from here on, we run in a thread, so we can poll (peek does)
         start_thread(self.handle_new_connection, f"new-{socktype}-connection", True,
@@ -1138,16 +1145,10 @@ def new_conn_err(self, conn, sock, socktype: str, socket_info, packet_type: str,
                 # HTTP 400 error:
                 packet_data = HTTP_UNSUPORTED
             conn.write(packet_data)
-            self.timeout_add(500, self.force_close_connection, conn)
+            self.timeout_add(500, force_close_connection, conn)
         except Exception as e:
             netlog("error sending %r: %s", packet_data, e)
 
-    def force_close_connection(self, conn) -> None:
-        try:
-            conn.close()
-        except OSError:
-            log("close_connection()", exc_info=True)
-
     def handle_new_connection(self, conn, socket_info, socket_options) -> None:
         """
             Use peek to decide what sort of connection this is,
@@ -1286,7 +1287,7 @@ def can_upgrade_to(to_socktype: str):
                 data = conn.read(1)
                 if not data:
                     netlog("%s connection already closed", socktype)
-                    noerr(conn.close)
+                    force_close_connection(conn)
                     return
                 pre_read = [data, ]
                 netlog("pre_read data=%r", data)
@@ -1564,7 +1565,7 @@ def addbuf(buf):
             if conn:
                 # the connection object is now removed from the protocol object,
                 # so we have to close it explicitly if we have not wrapped it successfully:
-                conn.close()
+                force_close_connection(conn)
         proto._invalid_header(proto, data, msg)
 
     # #####################################################################
@@ -1635,10 +1636,7 @@ def new_websocket_client(wsh):
         except Exception:
             wslog.error("Error: %s request failure for client %s:",
                         req_info, pretty_socket(frominfo), exc_info=True)
-        try:
-            conn.close()
-        except Exception as ce:
-            wslog("error closing connection following error: %s", ce)
+        force_close_connection(conn)
 
     def get_http_scripts(self) -> dict[str, Any]:
         return self._http_scripts
@@ -2121,14 +2119,14 @@ def _process_ssl_upgrade(self, proto: SocketProtocol, packet: PacketType):
         ioe = proto.wait_for_io_threads_exit(1)
         if not ioe:
             self.disconnect_protocol(proto, "failed to terminate network threads for ssl upgrade")
-            conn.close()
+            force_close_connection(conn)
             return
         options = conn.options
         socktype = conn.socktype
         ssl_sock = self._ssl_wrap_socket(socktype, conn._socket, options)
         if not ssl_sock:
             self.disconnect_protocol(proto, "failed to upgrade socket to ssl")
-            conn.close()
+            force_close_connection(conn)
             return
         ssl_conn = SSLSocketConnection(ssl_sock, conn.local, conn.remote, conn.endpoint, "ssl", socket_options=options)
         ssl_conn.socktype_wrapped = socktype
@@ -2590,4 +2588,4 @@ def process_packet(self, proto: SocketProtocol, packet) -> None:
     def handle_rfb_connection(self, conn, data: bytes = b"") -> None:
         log.error("Error: RFB protocol is not supported by this server")
         log("handle_rfb_connection%s", (conn, data))
-        conn.close()
+        force_close_connection(conn)