From d3178154c3f724557824cb720028902627b56b1b Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 5 Nov 2026 17:28:51 +0300 Subject: [PATCH] fix(console): novncd waits at most 5 s for a VNC server to answer websockify's socket() connects without a timeout, so a console address that does not answer held the console's process for the OS's TCP timeout (some 2 minutes) before the page heard of it. novncd now connects with CONNECT_TIMEOUT, then waits on the open connection as before. --- console/novncd | 12 ++++++++++-- console/tests/test_views.py | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/console/novncd b/console/novncd index d9a9139b..823b688a 100755 --- a/console/novncd +++ b/console/novncd @@ -25,7 +25,7 @@ from websockify import ProxyRequestHandler, WebSocketProxy # noqa: E402 from console.sshtunnels import open_tunnel, tunnel_target # noqa: E402 from console.tokens import ACCESS_CHECK, authorize, may_still_open, session_user_id # noqa: E402 from logs.audit import write # noqa: E402 -from vrtManager.connection import CONN_SOCKET, CONN_SSH # noqa: E402 +from vrtManager.connection import CONN_SOCKET, CONN_SSH, CONNECT_TIMEOUT # noqa: E402 from vrtManager.util import is_loopback # noqa: E402 from webvirtcloud.settings import WS_HOST, WS_PORT # noqa: E402 @@ -79,6 +79,14 @@ def get_connection_infos(instance): WILDCARD = (None, "", "0.0.0.0", "::") +def bounded_connect(host, port, connect=True): + """A connection to a VNC server, in place of websockify's socket(), which + waits for one that does not answer as long as the OS does (some 2 minutes).""" + tsock = socket.create_connection((host, port), timeout=CONNECT_TIMEOUT) + tsock.settimeout(None) # a console may stay quiet for long once connected + return tsock + + def client_address(value): """The client's address nginx sends in X-Real-IP, or None.""" try: @@ -178,7 +186,7 @@ class ConsoleProxyHandler(ProxyRequestHandler, ConsoleClient): self.log_message(*args, **kwargs) def new_websocket_client(self): - self._new_client(self.server.socket) + self._new_client(bounded_connect) if __name__ == "__main__": diff --git a/console/tests/test_views.py b/console/tests/test_views.py index bbb48412..39473d85 100644 --- a/console/tests/test_views.py +++ b/console/tests/test_views.py @@ -570,6 +570,12 @@ class NovncdDaemonLogicTestCase(TestCase): # the VM access was checked for, not whichever VM has its name now self.assertEqual(mock_wvm.call_args.kwargs["uuid"], mock_instance.uuid) + def test_the_vnc_server_is_waited_for_a_bounded_time(self): + with patch.object(novncd_mod.socket, "create_connection") as create_connection: + tsock = novncd_mod.bounded_connect("192.0.2.40", 5900, connect=True) + create_connection.assert_called_once_with(("192.0.2.40", 5900), timeout=novncd_mod.CONNECT_TIMEOUT) + tsock.settimeout.assert_called_once_with(None) + def test_a_token_without_its_users_session_is_refused_and_logged(self): from logs.models import Logs