From b800011265bf47ea6b3f4f2b234d25249823a9be Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Fri, 31 Oct 2025 19:01:37 +0000 Subject: [PATCH] [NET] Cleanup WSAStartup, setoption and ioctlsocket --- src/xenia/kernel/xam/xam_net.cc | 34 ++++----- src/xenia/kernel/xsocket.cc | 124 +++++++++++++------------------- 2 files changed, 68 insertions(+), 90 deletions(-) diff --git a/src/xenia/kernel/xam/xam_net.cc b/src/xenia/kernel/xam/xam_net.cc index 315596046..ff94c0bfb 100644 --- a/src/xenia/kernel/xam/xam_net.cc +++ b/src/xenia/kernel/xam/xam_net.cc @@ -258,7 +258,7 @@ dword_result_t NetDll_WSAStartup_entry(dword_t caller, word_t version, #endif if (data_ptr) { - auto data_out = kernel_state()->memory()->TranslateVirtual(data_ptr); + data_ptr.Zero(); #ifdef XE_PLATFORM_WIN32 data_ptr->version = wsaData.wVersion; @@ -267,22 +267,25 @@ dword_result_t NetDll_WSAStartup_entry(dword_t caller, word_t version, data_ptr->max_udpdg = wsaData.iMaxUdpDg; std::memcpy(&data_ptr->description, wsaData.szDescription, 0x100); std::memcpy(&data_ptr->system_status, wsaData.szSystemStatus, 0x80); + data_ptr->vendor_info_ptr = 0; #else // Match Windows behavior with reasonable values - data_ptr->version = version.value(); - data_ptr->version_high = version.value(); - data_ptr->max_sockets = 100; - data_ptr->max_udpdg = 1024; - // WinSock 2.2 typically returns empty strings for these fields - std::memset(&data_ptr->description, 0, 0x100); - std::memset(&data_ptr->system_status, 0, 0x80); -#endif + data_ptr->version = 2; + data_ptr->version_high = 0x0202; + data_ptr->max_sockets = 0; + data_ptr->max_udpdg = 0; - // Some games (5841099F) want this value round-tripped - they'll compare if - // it changes and bugcheck if it does. - // vendor_info_ptr is at offset 0x18A (after max_udpdg at 0x188) - uint32_t vendor_ptr = xe::load_and_swap(data_out + 0x18A); - xe::store_and_swap(data_out + 0x18A, vendor_ptr); + const std::string description = "WinSock 2.0"; + const std::string status = "Running"; + + std::memset(&data_ptr->description, 0, 0x100); + std::memcpy(&data_ptr->description, description.data(), description.size()); + + std::memset(&data_ptr->system_status, 0, 0x80); + std::memcpy(&data_ptr->system_status, status.data(), status.size()); + + data_ptr->vendor_info_ptr = 0; +#endif } // DEBUG @@ -765,7 +768,6 @@ dword_result_t NetDll_bind_entry(dword_t caller, dword_t socket_handle, kernel_state()->object_table()->LookupObject(socket_handle); if (!socket) { XThread::SetLastError(uint32_t(X_WSAError::X_WSAENOTSOCK)); - XELOGE("NetDll_bind: failed - invalid socket"); return -1; } @@ -773,7 +775,7 @@ dword_result_t NetDll_bind_entry(dword_t caller, dword_t socket_handle, X_STATUS status = socket->Bind(&native_name, namelen); if (XFAILED(status)) { XThread::SetLastError(socket->GetLastWSAError()); - XELOGE("NetDll_bind: failed with status {:08X}", status); + XELOGE("NetDll_bind: failed with error {:08X}", socket->GetLastWSAError()); return -1; } diff --git a/src/xenia/kernel/xsocket.cc b/src/xenia/kernel/xsocket.cc index 3f9bbaada..c6980ec19 100644 --- a/src/xenia/kernel/xsocket.cc +++ b/src/xenia/kernel/xsocket.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,28 @@ namespace xe { namespace kernel { +// Translate socket options to native +// Note: +// SO_DONTLINGER = ~SO_LINGER +// SO_EXCLUSIVEADDRUSE = ~SO_REUSEADDR +// TODO: Check SO_DONTLINGER and SO_EXCLUSIVEADDRUSE usage on linux +const std::map supported_socket_options = { + {0x0004, SO_REUSEADDR}, {0x0020, SO_BROADCAST}, {0x0080, SO_LINGER}, + {0x1001, SO_SNDBUF}, {0x1002, SO_RCVBUF}, {0x1005, SO_SNDTIMEO}, + {0x1006, SO_RCVTIMEO}, {~0x0080, ~SO_LINGER}, {~0x0004, ~SO_REUSEADDR}}; + +// Translate socket TCP options to native +const std::map supported_tcp_options = { + {0x0001, TCP_NODELAY}}; + +// Translate socket levels to native +const std::map supported_levels = {{0xFFFF, SOL_SOCKET}, + {0x6, IPPROTO_TCP}}; + +// Translate ioctl commands to native +const std::map supported_controls = { + {0x8004667E, FIONBIO}, {0x4004667F, FIONREAD}}; + XSocket::XSocket(KernelState* kernel_state) : XObject(kernel_state, kObjectType) {} @@ -93,73 +116,37 @@ X_STATUS XSocket::SetOption(uint32_t level, uint32_t optname, void* optval_ptr, return X_STATUS_SUCCESS; } - // Translate Xbox socket level to native int native_level = level; - if (level == 0xFFFF) { // Xbox SOL_SOCKET - native_level = SOL_SOCKET; + + assert_false(!supported_levels.contains(level)); + + if (supported_levels.contains(level)) { + level = supported_levels.at(level); } - // Translate Xbox socket options to native - // Xbox uses Winsock constants which mostly match standard values int native_optname = optname; + if (level == 0xFFFF) { - switch (optname) { - case 0x0001: // SO_DEBUG - native_optname = SO_DEBUG; - break; - case 0x0002: // SO_ACCEPTCONN - native_optname = SO_ACCEPTCONN; - break; - case 0x0004: // SO_REUSEADDR - native_optname = SO_REUSEADDR; - break; - case 0x0008: // SO_KEEPALIVE - native_optname = SO_KEEPALIVE; - break; - case 0x0010: // SO_DONTROUTE - native_optname = SO_DONTROUTE; - break; - case 0x0020: // SO_BROADCAST - native_optname = SO_BROADCAST; - break; - case 0x0080: // SO_LINGER - native_optname = SO_LINGER; - break; - case 0x0100: // SO_OOBINLINE - native_optname = SO_OOBINLINE; - break; - case 0x1001: // SO_SNDBUF - native_optname = SO_SNDBUF; - break; - case 0x1002: // SO_RCVBUF - native_optname = SO_RCVBUF; - break; - case 0x1003: // SO_SNDLOWAT - native_optname = SO_SNDLOWAT; - break; - case 0x1004: // SO_RCVLOWAT - native_optname = SO_RCVLOWAT; - break; - case 0x1005: // SO_SNDTIMEO - native_optname = SO_SNDTIMEO; - break; - case 0x1006: // SO_RCVTIMEO - native_optname = SO_RCVTIMEO; - break; - case 0x1007: // SO_ERROR - native_optname = SO_ERROR; - break; - case 0x1008: // SO_TYPE - native_optname = SO_TYPE; - break; - // Add more translations as needed + assert_false(!supported_socket_options.contains(optname)); + + if (supported_socket_options.contains(optname)) { + native_optname = supported_socket_options.at(optname); + } + } + + if (level == IPPROTO_TCP) { + assert_false(!supported_tcp_options.contains(optname)); + + if (supported_tcp_options.contains(optname)) { + native_optname = supported_tcp_options.at(optname); } } int ret = setsockopt(native_handle_, native_level, native_optname, static_cast(optval_ptr), optlen); if (ret < 0) { - XELOGE("XSocket::SetOption: setsockopt failed, errno={}", errno); + // TODO: WSAGetLastError() + XELOGE("XSocket::SetOption: failed with error {:08X}", GetLastWSAError()); return X_STATUS_UNSUCCESSFUL; } @@ -180,26 +167,20 @@ X_STATUS XSocket::IOControl(uint32_t cmd, uint8_t* arg_ptr) { } return X_STATUS_SUCCESS; #elif XE_PLATFORM_LINUX - // Translate Xbox/Windows ioctl commands to Linux equivalents int native_cmd = cmd; - switch (cmd) { - case 0x8004667E: // Windows FIONBIO - set non-blocking mode - native_cmd = FIONBIO; - break; - case 0x4004667F: // Windows FIONREAD - get bytes available - native_cmd = FIONREAD; - break; - default: - XELOGW("XSocket::IOControl: unknown cmd={:08X}, passing through", cmd); - break; + + assert_false(!supported_controls.contains(cmd)); + + if (supported_controls.contains(cmd)) { + native_cmd = supported_controls.at(cmd); } int ret = ioctl(native_handle_, native_cmd, arg_ptr); + if (ret < 0) { - XELOGE("XSocket::IOControl: ioctl failed, cmd={:08X} -> {:08X}, errno={}", - cmd, native_cmd, errno); return X_STATUS_UNSUCCESSFUL; } + return X_STATUS_SUCCESS; #endif } @@ -229,11 +210,6 @@ X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) { int ret = bind(native_handle_, (sockaddr*)name, name_len); if (ret < 0) { -#ifdef XE_PLATFORM_WIN32 - XELOGE("XSocket::Bind: bind() failed with WSA error {}", WSAGetLastError()); -#else - XELOGE("XSocket::Bind: bind() failed with errno={}", errno); -#endif return X_STATUS_UNSUCCESSFUL; }