From 818a22c445603b14e5cacdded11732ab374c2904 Mon Sep 17 00:00:00 2001 From: Wiktor Mazur Date: Mon, 21 Jul 2025 16:56:08 +0200 Subject: [PATCH] Fix WinHTTP initialization timing to prevent error 12007 Resolve an issue in Microsoft GDK titles where WinHttpSendRequest intermittently failed with error code 12007 in Release Package builds. This fix delays the initialization of the HTTP session until the network stack is fully ready and the first HTTP request is made https://learn.microsoft.com/pl-pl/gaming/gdk/docs/features/console/networking/initialization-connectivity-networking --- CHANGELOG.md | 1 + CMakeLists.txt | 2 +- src/CMakeLists.txt | 5 ++ src/transports/sentry_transport_winhttp.c | 65 ++++++++++++++----- .../sentry_transport_xnetworking.cpp | 64 ++++++++++++++++++ 5 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 src/transports/sentry_transport_xnetworking.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 63c642e22..1eda15f72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Update Xbox toolchain to include `UseDebugLibraries` fix for Debug builds. ([#1302](https://github.com/getsentry/sentry-native/pull/1302)) - Fix GDK version selection for Xbox by propagating `XdkEditionTarget` to MSBuild. ([#1312](https://github.com/getsentry/sentry-native/pull/1312)) +- Fix WinHTTP initialization timing to prevent error 12007 on Xbox platform. ([#1321](https://github.com/getsentry/sentry-native/pull/1321)) **Meta**: diff --git a/CMakeLists.txt b/CMakeLists.txt index 98f30edff..fd6d56afd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -489,7 +489,7 @@ elseif(LINUX) set(_SENTRY_PLATFORM_LIBS "dl" "rt") elseif(WIN32) if (XBOX) - set(_SENTRY_PLATFORM_LIBS "version") + set(_SENTRY_PLATFORM_LIBS "version" "xgameruntime") else() set(_SENTRY_PLATFORM_LIBS "dbghelp" "shlwapi" "version") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a34a54004..46742197c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -112,6 +112,11 @@ elseif(SENTRY_TRANSPORT_WINHTTP) sentry_target_sources_cwd(sentry transports/sentry_transport_winhttp.c ) + if (XBOX) + sentry_target_sources_cwd(sentry + transports/sentry_transport_xnetworking.cpp + ) + endif() elseif(SENTRY_TRANSPORT_NONE) sentry_target_sources_cwd(sentry transports/sentry_transport_none.c diff --git a/src/transports/sentry_transport_winhttp.c b/src/transports/sentry_transport_winhttp.c index d9c7b60b1..659c182b8 100644 --- a/src/transports/sentry_transport_winhttp.c +++ b/src/transports/sentry_transport_winhttp.c @@ -13,6 +13,10 @@ #include #include +#ifdef SENTRY_PLATFORM_XBOX +HRESULT sentry__transport_ensure_network_initialized(); +#endif // SENTRY_PLATFORM_XBOX + typedef struct { sentry_dsn_t *dsn; wchar_t *user_agent; @@ -40,6 +44,31 @@ sentry__winhttp_bgworker_state_new(void) return state; } +static void +sentry__winhttp_session_start(void *_state) +{ + winhttp_bgworker_state_t *state = _state; + if (state->proxy) { + state->session + = WinHttpOpen(state->user_agent, WINHTTP_ACCESS_TYPE_NAMED_PROXY, + state->proxy, WINHTTP_NO_PROXY_BYPASS, 0); + } else { +#if _WIN32_WINNT >= 0x0603 + state->session = WinHttpOpen(state->user_agent, + WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0); +#endif + // On windows 8.0 or lower, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY does + // not work on error we fallback to + // WINHTTP_ACCESS_TYPE_DEFAULT_PROXY + if (!state->session) { + state->session = WinHttpOpen(state->user_agent, + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0); + } + } +} + static void sentry__winhttp_bgworker_state_free(void *_state) { @@ -118,28 +147,14 @@ sentry__winhttp_transport_start( } } - if (state->proxy) { - state->session - = WinHttpOpen(state->user_agent, WINHTTP_ACCESS_TYPE_NAMED_PROXY, - state->proxy, WINHTTP_NO_PROXY_BYPASS, 0); - } else { -#if _WIN32_WINNT >= 0x0603 - state->session = WinHttpOpen(state->user_agent, - WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, 0); -#endif - // On windows 8.0 or lower, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY does - // not work on error we fallback to WINHTTP_ACCESS_TYPE_DEFAULT_PROXY - if (!state->session) { - state->session = WinHttpOpen(state->user_agent, - WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, 0); - } - } +#ifndef SENTRY_PLATFORM_XBOX + sentry__winhttp_session_start(state); + if (!state->session) { SENTRY_WARN("`WinHttpOpen` failed"); return 1; } +#endif // !SENTRY_PLATFORM_XBOX return sentry__bgworker_start(bgworker); } @@ -187,6 +202,20 @@ sentry__winhttp_send_task(void *_envelope, void *_state) sentry_envelope_t *envelope = (sentry_envelope_t *)_envelope; winhttp_bgworker_state_t *state = (winhttp_bgworker_state_t *)_state; +#ifdef SENTRY_PLATFORM_XBOX + if (!state->session) { + SENTRY_DEBUG( + "ensuring xbox network is initialized for WinHttp transport"); + sentry__transport_ensure_network_initialized(); + sentry__winhttp_session_start(state); + + if (!state->session) { + SENTRY_WARN("`WinHttpOpen` failed"); + return; + } + } +#endif // SENTRY_PLATFORM_XBOX + uint64_t started = sentry__monotonic_time(); char *user_agent = sentry__string_from_wstr(state->user_agent); diff --git a/src/transports/sentry_transport_xnetworking.cpp b/src/transports/sentry_transport_xnetworking.cpp new file mode 100644 index 000000000..4af10ecd8 --- /dev/null +++ b/src/transports/sentry_transport_xnetworking.cpp @@ -0,0 +1,64 @@ +#include "sentry_boot.h" + +#include + +static void +sentry__transport_network_connectivity_hint_changed_callback(_In_ void *context, + _In_ const XNetworkingConnectivityHint *connectivity_hint) +{ + HANDLE network_initialized_event = static_cast(context); + if (connectivity_hint->networkInitialized) { + (void)SetEvent(network_initialized_event); + } +} + +extern "C" { + +HRESULT +sentry__transport_ensure_network_initialized() +{ + HRESULT hr = S_OK; + XNetworkingConnectivityHint connectivity_hint; + XTaskQueueHandle queue; + + hr = XTaskQueueCreate(XTaskQueueDispatchMode::Immediate, + XTaskQueueDispatchMode::Immediate, &queue); + if (SUCCEEDED(hr)) { + // Use the new XNetworking APIs to check if the network is initialized. + hr = XNetworkingGetConnectivityHint(&connectivity_hint); + if (SUCCEEDED(hr)) { + if (!connectivity_hint.networkInitialized) { + // The network isn't initialized. Wait until the network becomes + // initialized. + HANDLE network_initialized_event + = CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (network_initialized_event != nullptr) { + XTaskQueueRegistrationToken token; + hr = XNetworkingRegisterConnectivityHintChanged(queue, + network_initialized_event, + sentry__transport_network_connectivity_hint_changed_callback, + &token); + if (SUCCEEDED(hr)) { + DWORD result = WaitForSingleObjectEx( + network_initialized_event, INFINITE, FALSE); + if (result != WAIT_OBJECT_0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + XNetworkingUnregisterConnectivityHintChanged( + token, true); + } + + CloseHandle(network_initialized_event); + } else { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + } + + XTaskQueueCloseHandle(queue); + } + + return hr; +} +}