[Kernel] Add Linux socket support and ensure binding low ports is remapped.
Remapping ports on both Linux and Windows to ensure games boot under wine as well.
This commit is contained in:
committed by
Radosław Gliński
parent
344e8538e0
commit
4af2fd6513
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/xam/xam_module.h"
|
||||
@@ -25,6 +26,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -91,10 +93,73 @@ X_STATUS XSocket::SetOption(uint32_t level, uint32_t optname, void* optval_ptr,
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int ret =
|
||||
setsockopt(native_handle_, level, optname, (char*)optval_ptr, optlen);
|
||||
// Translate Xbox socket level to native
|
||||
int native_level = level;
|
||||
if (level == 0xFFFF) { // Xbox SOL_SOCKET
|
||||
native_level = SOL_SOCKET;
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
int ret = setsockopt(native_handle_, native_level, native_optname,
|
||||
static_cast<char*>(optval_ptr), optlen);
|
||||
if (ret < 0) {
|
||||
// TODO: WSAGetLastError()
|
||||
XELOGE("XSocket::SetOption: setsockopt failed, errno={}", errno);
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -113,10 +178,29 @@ X_STATUS XSocket::IOControl(uint32_t cmd, uint8_t* arg_ptr) {
|
||||
// TODO: Get last error
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
#elif XE_PLATFORM_LINUX
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -130,8 +214,26 @@ X_STATUS XSocket::Connect(N_XSOCKADDR* name, int name_len) {
|
||||
}
|
||||
|
||||
X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) {
|
||||
// On Linux and Windows (when running under Wine), ports < 1024 require root
|
||||
// privileges. Remap to port + 10000 to avoid privilege issues.
|
||||
// Note: sin_port is xe::be<uint16_t> which automatically handles endianness,
|
||||
// so we use it directly without ntohs/htons.
|
||||
const uint16_t original_port = uint16_t(name->sin_port);
|
||||
if (original_port < 1024) {
|
||||
uint16_t new_port = original_port + 10000;
|
||||
name->sin_port = new_port;
|
||||
XELOGW("XSocket::Bind: port {} requires privileges, remapping to port {}",
|
||||
original_port, new_port);
|
||||
}
|
||||
|
||||
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