[NET] Cleanup WSAStartup, setoption and ioctlsocket
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user