From b28adf8cbe1b92cfd4ea8795cf01d48e7ddd086a Mon Sep 17 00:00:00 2001 From: Keith Smith Date: Tue, 8 Sep 2026 09:37:02 -0600 Subject: [PATCH] Fix RDP host resolution failure on Windows: initialize Winsock Every RDP connect attempt on Windows failed instantly with ERRCONNECT_DNS_NAME_NOT_FOUND, even for a literal IP address. Root cause: Winsock requires WSAStartup() to be called once by the process before any socket/getaddrinfo call will succeed, and nothing in OrbitHub was calling it (Qt Network isn't used, so Qt never does it either). FreeRDP's own reference Windows client (wf_client.c) pairs WSAStartup with freerdp_handle_signals() in its startup init for exactly this reason. WinPR provides a portable no-op WSAStartup shim on POSIX, so this can be called unconditionally cross-platform alongside the existing signal-handler fix. Co-Authored-By: Claude Sonnet 5 --- src/rdp_session_backend.cpp | 39 ++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/rdp_session_backend.cpp b/src/rdp_session_backend.cpp index 59cc854..e5d9048 100644 --- a/src/rdp_session_backend.cpp +++ b/src/rdp_session_backend.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -41,19 +42,35 @@ namespace { #ifdef ORBITHUB_HAS_FREERDP -// Every reference FreeRDP client (X11, Windows, macOS, SDL, Wayland, -// Android) calls this once at startup before connecting. On Windows it's -// the only place that initializes a global CRITICAL_SECTION used by -// freerdp_add_signal_cleanup_handler(); skipping it leaves that lock -// zero-initialized (invalid on Windows, tolerated on POSIX), so the first -// freerdp_connect() crashes with a null-pointer dereference inside -// EnterCriticalSection. Guarded so it only ever runs once. -void ensureFreeRdpSignalHandlersInitialized() +// Mirrors wfreerdp_client_global_init() in FreeRDP's own reference Windows +// client (client/Windows/wf_client.c): every reference client calls +// WSAStartup + freerdp_handle_signals once at startup before connecting. +// +// WSAStartup: on Windows, sockets (getaddrinfo et al.) fail immediately +// with WSANOTINITIALISED until this has been called by *someone* in the +// process; OrbitHub never used Qt Network, so nothing else on Windows was +// calling it, and every connect failed instantly with +// ERRCONNECT_DNS_NAME_NOT_FOUND even for a literal IP address. WinPR +// provides a portable no-op WSAStartup shim on POSIX, so this is safe to +// call unconditionally cross-platform. +// +// freerdp_handle_signals: on Windows it's the only place that initializes +// a global CRITICAL_SECTION used by freerdp_add_signal_cleanup_handler(); +// skipping it leaves that lock zero-initialized (invalid on Windows, +// tolerated on POSIX), so the first freerdp_connect() crashed with a +// null-pointer dereference inside EnterCriticalSection. +// +// Guarded so it only ever runs once. +void ensureFreeRdpRuntimeInitialized() { static std::once_flag onceFlag; std::call_once(onceFlag, []() { - const int rc = freerdp_handle_signals(); - Q_UNUSED(rc); + WSADATA wsaData; + const int wsaRc = WSAStartup(0x101, &wsaData); + Q_UNUSED(wsaRc); + + const int signalRc = freerdp_handle_signals(); + Q_UNUSED(signalRc); }); } #endif @@ -1493,7 +1510,7 @@ void RdpSessionBackend::workerMain() m_workerRunning.store(false); return; #else - ensureFreeRdpSignalHandlersInitialized(); + ensureFreeRdpRuntimeInitialized(); freerdp* instance = freerdp_new(); if (instance == nullptr) {