[NET] Cleanup WSAStartup, setoption and ioctlsocket

This commit is contained in:
Adrian
2025-10-31 19:01:37 +00:00
committed by Radosław Gliński
parent ade064d310
commit b800011265
2 changed files with 68 additions and 90 deletions

View File

@@ -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<uint32_t>(data_out + 0x18A);
xe::store_and_swap<uint32_t>(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<XSocket>(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;
}

View File

@@ -26,6 +26,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
@@ -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<uint32_t, uint32_t> 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<uint32_t, uint32_t> supported_tcp_options = {
{0x0001, TCP_NODELAY}};
// Translate socket levels to native
const std::map<uint32_t, uint32_t> supported_levels = {{0xFFFF, SOL_SOCKET},
{0x6, IPPROTO_TCP}};
// Translate ioctl commands to native
const std::map<uint32_t, uint32_t> 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<char*>(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;
}