XSocket Implementation
This commit is contained in:
parent
6c73aa51a0
commit
f6ac79ea07
|
@ -13,10 +13,12 @@
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
|
#include "xenia/kernel/xam/xam_module.h"
|
||||||
#include "xenia/kernel/xam/xam_private.h"
|
#include "xenia/kernel/xam/xam_private.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_error.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_error.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
||||||
#include "xenia/kernel/xevent.h"
|
#include "xenia/kernel/xevent.h"
|
||||||
|
#include "xenia/kernel/xsocket.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
|
@ -48,11 +50,27 @@ typedef struct {
|
||||||
uint8_t abOnline[20]; // Online identification
|
uint8_t abOnline[20]; // Online identification
|
||||||
} XNADDR;
|
} XNADDR;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
xe::be<int32_t> status;
|
||||||
|
xe::be<uint32_t> cina;
|
||||||
|
IN_ADDR aina[8];
|
||||||
|
} XNDNS;
|
||||||
|
|
||||||
struct Xsockaddr_t {
|
struct Xsockaddr_t {
|
||||||
xe::be<uint16_t> sa_family;
|
xe::be<uint16_t> sa_family;
|
||||||
char sa_data[14];
|
char sa_data[14];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct X_WSADATA {
|
||||||
|
xe::be<uint16_t> version;
|
||||||
|
xe::be<uint16_t> version_high;
|
||||||
|
char description[256 + 1];
|
||||||
|
char system_status[128 + 1];
|
||||||
|
xe::be<uint16_t> max_sockets;
|
||||||
|
xe::be<uint16_t> max_udpdg;
|
||||||
|
xe::be<uint32_t> vendor_info_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct XWSABUF {
|
struct XWSABUF {
|
||||||
xe::be<uint32_t> len;
|
xe::be<uint32_t> len;
|
||||||
xe::be<uint32_t> buf_ptr;
|
xe::be<uint32_t> buf_ptr;
|
||||||
|
@ -78,7 +96,7 @@ void LoadSockaddr(const uint8_t* ptr, sockaddr* out_addr) {
|
||||||
auto in_addr = reinterpret_cast<sockaddr_in*>(out_addr);
|
auto in_addr = reinterpret_cast<sockaddr_in*>(out_addr);
|
||||||
in_addr->sin_port = xe::load_and_swap<uint16_t>(ptr + 2);
|
in_addr->sin_port = xe::load_and_swap<uint16_t>(ptr + 2);
|
||||||
// Maybe? Depends on type.
|
// Maybe? Depends on type.
|
||||||
in_addr->sin_addr.S_un.S_addr = xe::load_and_swap<uint32_t>(ptr + 4);
|
in_addr->sin_addr.S_un.S_addr = *(uint32_t*)(ptr + 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -125,32 +143,41 @@ struct XNetStartupParams {
|
||||||
|
|
||||||
XNetStartupParams xnet_startup_params = {0};
|
XNetStartupParams xnet_startup_params = {0};
|
||||||
|
|
||||||
SHIM_CALL NetDll_XNetStartup_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_XNetStartup(dword_t caller,
|
||||||
KernelState* kernel_state) {
|
pointer_t<XNetStartupParams> params) {
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
if (params) {
|
||||||
uint32_t params_ptr = SHIM_GET_ARG_32(1);
|
|
||||||
|
|
||||||
XELOGD("NetDll_XNetStartup(%d, %.8X)", caller, params_ptr);
|
|
||||||
|
|
||||||
if (params_ptr) {
|
|
||||||
auto params =
|
|
||||||
kernel_memory()->TranslateVirtual<XNetStartupParams*>(params_ptr);
|
|
||||||
assert_true(params->cfgSizeOfStruct == sizeof(XNetStartupParams));
|
assert_true(params->cfgSizeOfStruct == sizeof(XNetStartupParams));
|
||||||
std::memcpy(&xnet_startup_params, params, sizeof(XNetStartupParams));
|
std::memcpy(&xnet_startup_params, params, sizeof(XNetStartupParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(0);
|
auto xam = kernel_state()->GetKernelModule<XamModule>("xam.xex");
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (!xam->xnet()) {
|
||||||
|
auto xnet = new XNet(kernel_state());
|
||||||
|
xnet->Initialize();
|
||||||
|
|
||||||
|
xam->set_xnet(xnet);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetStartup,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
SHIM_CALL NetDll_XNetCleanup_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_XNetCleanup(dword_t caller, lpvoid_t params) {
|
||||||
KernelState* kernel_state) {
|
auto xam = kernel_state()->GetKernelModule<XamModule>("xam.xex");
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
// auto xnet = xam->xnet();
|
||||||
uint32_t params_ptr = SHIM_GET_ARG_32(1);
|
// xam->set_xnet(nullptr);
|
||||||
|
|
||||||
XELOGD("NetDll_XNetCleanup(%d, %.8X)", caller, params_ptr);
|
// TODO: Shut down and delete.
|
||||||
|
// delete xnet;
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetCleanup,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
dword_result_t NetDll_XNetGetOpt(dword_t one, dword_t option_id,
|
dword_result_t NetDll_XNetGetOpt(dword_t one, dword_t option_id,
|
||||||
lpvoid_t buffer_ptr, lpdword_t buffer_size) {
|
lpvoid_t buffer_ptr, lpdword_t buffer_size) {
|
||||||
|
@ -170,101 +197,140 @@ dword_result_t NetDll_XNetGetOpt(dword_t one, dword_t option_id,
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT(NetDll_XNetGetOpt, ExportTag::kNetworking);
|
DECLARE_XAM_EXPORT(NetDll_XNetGetOpt, ExportTag::kNetworking);
|
||||||
|
|
||||||
SHIM_CALL NetDll_XNetRandom_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_XNetRandom(dword_t caller, lpvoid_t buffer_ptr,
|
||||||
KernelState* kernel_state) {
|
dword_t length) {
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t buffer_ptr = SHIM_GET_ARG_32(1);
|
|
||||||
uint32_t length = SHIM_GET_ARG_32(2);
|
|
||||||
|
|
||||||
XELOGD("NetDll_XNetRandom(%d, %.8X, %d)", caller, buffer_ptr, length);
|
|
||||||
|
|
||||||
// For now, constant values.
|
// For now, constant values.
|
||||||
// This makes replicating things easier.
|
// This makes replicating things easier.
|
||||||
std::memset(SHIM_MEM_ADDR(buffer_ptr), 0xBB, length);
|
std::memset(buffer_ptr, 0xBB, length);
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetRandom,
|
||||||
|
ExportTag::kNetworking | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL NetDll_WSAStartup_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_WSAStartup(dword_t caller, word_t version,
|
||||||
KernelState* kernel_state) {
|
pointer_t<X_WSADATA> data_ptr) {
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint16_t version = SHIM_GET_ARG_16(1);
|
|
||||||
uint32_t data_ptr = SHIM_GET_ARG_32(2);
|
|
||||||
|
|
||||||
XELOGD("NetDll_WSAStartup(%d, %.4X, %.8X)", caller, version, data_ptr);
|
|
||||||
|
|
||||||
// TODO(benvanik): abstraction layer needed.
|
// TODO(benvanik): abstraction layer needed.
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
ZeroMemory(&wsaData, sizeof(WSADATA));
|
ZeroMemory(&wsaData, sizeof(WSADATA));
|
||||||
int ret = WSAStartup(version, &wsaData);
|
int ret = WSAStartup(version, &wsaData);
|
||||||
|
|
||||||
auto data_out = kernel_state->memory()->TranslateVirtual(data_ptr);
|
auto data_out = kernel_state()->memory()->TranslateVirtual(data_ptr);
|
||||||
|
|
||||||
if (data_ptr) {
|
if (data_ptr) {
|
||||||
xe::store_and_swap<uint16_t>(data_out + 0x000, wsaData.wVersion);
|
data_ptr->version = wsaData.wVersion;
|
||||||
xe::store_and_swap<uint16_t>(data_out + 0x002, wsaData.wHighVersion);
|
data_ptr->version_high = wsaData.wHighVersion;
|
||||||
std::memcpy(data_out + 0x004, wsaData.szDescription, 0x100);
|
std::memcpy(&data_ptr->description, wsaData.szDescription, 0x100);
|
||||||
std::memcpy(data_out + 0x105, wsaData.szSystemStatus, 0x80);
|
std::memcpy(&data_ptr->system_status, wsaData.szSystemStatus, 0x80);
|
||||||
xe::store_and_swap<uint16_t>(data_out + 0x186, wsaData.iMaxSockets);
|
data_ptr->max_sockets = wsaData.iMaxSockets;
|
||||||
xe::store_and_swap<uint16_t>(data_out + 0x188, wsaData.iMaxUdpDg);
|
data_ptr->max_udpdg = wsaData.iMaxUdpDg;
|
||||||
|
|
||||||
// Some games (PoG) want this value round-tripped - they'll compare if it
|
// Some games (PoG) want this value round-tripped - they'll compare if it
|
||||||
// changes and bugcheck if it does.
|
// changes and bugcheck if it does.
|
||||||
uint32_t vendor_ptr = SHIM_MEM_32(data_ptr + 0x190);
|
uint32_t vendor_ptr = xe::load_and_swap<uint32_t>(data_out + 0x190);
|
||||||
SHIM_SET_MEM_32(data_ptr + 0x190, vendor_ptr);
|
xe::store_and_swap<uint32_t>(data_out + 0x190, vendor_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
// DEBUG
|
||||||
|
/*
|
||||||
|
auto xam = kernel_state()->GetKernelModule<XamModule>("xam.xex");
|
||||||
|
if (!xam->xnet()) {
|
||||||
|
auto xnet = new XNet(kernel_state());
|
||||||
|
xnet->Initialize();
|
||||||
|
|
||||||
|
xam->set_xnet(xnet);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_WSAStartup,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
SHIM_CALL NetDll_WSACleanup_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_WSACleanup(dword_t caller) {
|
||||||
KernelState* kernel_state) {
|
// This does nothing. Xenia needs WSA running.
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
return 0;
|
||||||
|
|
||||||
XELOGD("NetDll_WSACleanup(%d)", caller);
|
|
||||||
|
|
||||||
// Don't actually call WSACleanup - we use it for the debugger and such.
|
|
||||||
// int ret = WSACleanup();
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_WSACleanup,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
SHIM_CALL NetDll_WSAGetLastError_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_WSAGetLastError() { return XThread::GetLastError(); }
|
||||||
KernelState* kernel_state) {
|
DECLARE_XAM_EXPORT(NetDll_WSAGetLastError,
|
||||||
XELOGD("NetDll_WSAGetLastError()");
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
int err = WSAGetLastError();
|
|
||||||
SHIM_SET_RETURN_32(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
dword_result_t NetDll_WSARecvFrom(dword_t caller, dword_t socket,
|
dword_result_t NetDll_WSARecvFrom(dword_t caller, dword_t socket,
|
||||||
pointer_t<XWSABUF> buffers_ptr,
|
pointer_t<XWSABUF> buffers_ptr,
|
||||||
dword_t buffer_count,
|
dword_t buffer_count,
|
||||||
lpdword_t num_bytes_recv, lpdword_t flags_ptr,
|
lpdword_t num_bytes_recv, lpdword_t flags_ptr,
|
||||||
pointer_t<Xsockaddr_t> from_addr,
|
pointer_t<XSOCKADDR_IN> from_addr,
|
||||||
pointer_t<XWSAOVERLAPPED> overlapped_ptr,
|
pointer_t<XWSAOVERLAPPED> overlapped_ptr,
|
||||||
lpvoid_t completion_routine_ptr) {
|
lpvoid_t completion_routine_ptr) {
|
||||||
if (overlapped_ptr) {
|
if (overlapped_ptr) {
|
||||||
auto evt = kernel_state()->object_table()->LookupObject<XEvent>(
|
// auto evt = kernel_state()->object_table()->LookupObject<XEvent>(
|
||||||
overlapped_ptr->event_handle);
|
// overlapped_ptr->event_handle);
|
||||||
|
|
||||||
if (evt) {
|
// if (evt) {
|
||||||
evt->Set(0, false);
|
// //evt->Set(0, false);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT(NetDll_WSARecvFrom, ExportTag::kNetworking);
|
DECLARE_XAM_EXPORT(NetDll_WSARecvFrom, ExportTag::kNetworking);
|
||||||
|
|
||||||
|
// If the socket is a VDP socket, buffer 0 is the game data length, and buffer 1
|
||||||
|
// is the unencrypted game data.
|
||||||
|
dword_result_t NetDll_WSASendTo(dword_t caller, dword_t socket_handle,
|
||||||
|
pointer_t<XWSABUF> buffers, dword_t num_buffers,
|
||||||
|
lpdword_t num_bytes_sent, dword_t flags,
|
||||||
|
pointer_t<XSOCKADDR_IN> to_ptr, dword_t to_len,
|
||||||
|
pointer_t<XWSAOVERLAPPED> overlapped,
|
||||||
|
lpvoid_t completion_routine) {
|
||||||
|
assert(!overlapped);
|
||||||
|
assert(!completion_routine);
|
||||||
|
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our sockets implementation doesn't support multiple buffers, so we need
|
||||||
|
// to combine the buffers the game has given us!
|
||||||
|
std::vector<uint8_t> combined_buffer_mem;
|
||||||
|
uint32_t combined_buffer_size = 0;
|
||||||
|
uint32_t combined_buffer_offset = 0;
|
||||||
|
for (uint32_t i = 0; i < num_buffers; i++) {
|
||||||
|
combined_buffer_size += buffers[i].len;
|
||||||
|
combined_buffer_mem.resize(combined_buffer_size);
|
||||||
|
uint8_t* combined_buffer = combined_buffer_mem.data();
|
||||||
|
|
||||||
|
std::memcpy(combined_buffer + combined_buffer_offset,
|
||||||
|
kernel_memory()->TranslateVirtual(buffers[i].buf_ptr),
|
||||||
|
buffers[i].len);
|
||||||
|
combined_buffer_offset += buffers[i].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
N_XSOCKADDR_IN native_to(to_ptr);
|
||||||
|
socket->SendTo(combined_buffer_mem.data(), combined_buffer_size, flags,
|
||||||
|
&native_to, to_len);
|
||||||
|
|
||||||
|
// TODO: Instantly complete overlapped
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_WSASendTo,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
dword_result_t NetDll_WSAWaitForMultipleEvents(dword_t num_events,
|
dword_result_t NetDll_WSAWaitForMultipleEvents(dword_t num_events,
|
||||||
lpdword_t events,
|
lpdword_t events,
|
||||||
dword_t wait_all,
|
dword_t wait_all,
|
||||||
dword_t timeout,
|
dword_t timeout,
|
||||||
dword_t alertable) {
|
dword_t alertable) {
|
||||||
if (num_events > 64) {
|
if (num_events > 64) {
|
||||||
XThread::GetCurrentThread()->set_last_error(87); // ERROR_INVALID_PARAMETER
|
XThread::SetLastError(87); // ERROR_INVALID_PARAMETER
|
||||||
return ~0u;
|
return ~0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,13 +345,14 @@ dword_result_t NetDll_WSAWaitForMultipleEvents(dword_t num_events,
|
||||||
|
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
||||||
XThread::GetCurrentThread()->set_last_error(error);
|
XThread::SetLastError(error);
|
||||||
return ~0u;
|
return ~0u;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT(NetDll_WSAWaitForMultipleEvents,
|
DECLARE_XAM_EXPORT(NetDll_WSAWaitForMultipleEvents, ExportTag::kNetworking |
|
||||||
ExportTag::kNetworking | ExportTag::kThreading);
|
ExportTag::kThreading |
|
||||||
|
ExportTag::kBlocking);
|
||||||
|
|
||||||
dword_result_t NetDll_WSACreateEvent() {
|
dword_result_t NetDll_WSACreateEvent() {
|
||||||
XEvent* ev = new XEvent(kernel_state());
|
XEvent* ev = new XEvent(kernel_state());
|
||||||
|
@ -299,7 +366,7 @@ dword_result_t NetDll_WSACloseEvent(dword_t event_handle) {
|
||||||
X_STATUS result = kernel_state()->object_table()->ReleaseHandle(event_handle);
|
X_STATUS result = kernel_state()->object_table()->ReleaseHandle(event_handle);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
||||||
XThread::GetCurrentThread()->set_last_error(error);
|
XThread::SetLastError(error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -311,7 +378,7 @@ dword_result_t NetDll_WSAResetEvent(dword_t event_handle) {
|
||||||
X_STATUS result = xboxkrnl::NtClearEvent(event_handle);
|
X_STATUS result = xboxkrnl::NtClearEvent(event_handle);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
||||||
XThread::GetCurrentThread()->set_last_error(error);
|
XThread::SetLastError(error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -323,7 +390,7 @@ dword_result_t NetDll_WSASetEvent(dword_t event_handle) {
|
||||||
X_STATUS result = xboxkrnl::NtSetEvent(event_handle, nullptr);
|
X_STATUS result = xboxkrnl::NtSetEvent(event_handle, nullptr);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
||||||
XThread::GetCurrentThread()->set_last_error(error);
|
XThread::SetLastError(error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -357,6 +424,7 @@ struct XnAddrStatus {
|
||||||
dword_result_t NetDll_XNetGetTitleXnAddr(dword_t caller,
|
dword_result_t NetDll_XNetGetTitleXnAddr(dword_t caller,
|
||||||
pointer_t<XNADDR> addr_ptr) {
|
pointer_t<XNADDR> addr_ptr) {
|
||||||
// Just return a loopback address atm.
|
// Just return a loopback address atm.
|
||||||
|
// FIXME: This needs to return the ethernet MAC address!
|
||||||
addr_ptr->ina.S_un.S_addr = htonl(INADDR_LOOPBACK);
|
addr_ptr->ina.S_un.S_addr = htonl(INADDR_LOOPBACK);
|
||||||
addr_ptr->inaOnline.S_un.S_addr = 0;
|
addr_ptr->inaOnline.S_un.S_addr = 0;
|
||||||
addr_ptr->wPortOnline = 0;
|
addr_ptr->wPortOnline = 0;
|
||||||
|
@ -378,6 +446,42 @@ dword_result_t NetDll_XNetGetDebugXnAddr(dword_t caller,
|
||||||
DECLARE_XAM_EXPORT(NetDll_XNetGetDebugXnAddr,
|
DECLARE_XAM_EXPORT(NetDll_XNetGetDebugXnAddr,
|
||||||
ExportTag::kNetworking | ExportTag::kStub);
|
ExportTag::kNetworking | ExportTag::kStub);
|
||||||
|
|
||||||
|
dword_result_t NetDll_XNetXnAddrToMachineId(dword_t caller,
|
||||||
|
pointer_t<XNADDR> addr_ptr,
|
||||||
|
lpdword_t id_ptr) {
|
||||||
|
// Tell the caller we're not signed in to live (non-zero ret)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetXnAddrToMachineId,
|
||||||
|
ExportTag::kNetworking | ExportTag::kStub);
|
||||||
|
|
||||||
|
void NetDll_XNetInAddrToString(dword_t caller, dword_t in_addr,
|
||||||
|
lpstring_t string_out, dword_t string_size) {
|
||||||
|
strncpy(string_out, "666.666.666.666", string_size);
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetInAddrToString,
|
||||||
|
ExportTag::kNetworking | ExportTag::kStub);
|
||||||
|
|
||||||
|
// This converts a XNet address to an IN_ADDR. The IN_ADDR is used for
|
||||||
|
// subsequent socket calls (like a handle to a XNet address)
|
||||||
|
dword_result_t NetDll_XNetXnAddrToInAddr(dword_t caller,
|
||||||
|
pointer_t<XNADDR> xn_addr,
|
||||||
|
lpvoid_t xid, lpvoid_t in_addr) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetXnAddrToInAddr,
|
||||||
|
ExportTag::kNetworking | ExportTag::kStub);
|
||||||
|
|
||||||
|
// Does the reverse of the above.
|
||||||
|
// FIXME: Arguments may not be correct.
|
||||||
|
dword_result_t NetDll_XNetInAddrToXnAddr(dword_t caller, lpvoid_t in_addr,
|
||||||
|
pointer_t<XNADDR> xn_addr,
|
||||||
|
lpvoid_t xid) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetInAddrToXnAddr,
|
||||||
|
ExportTag::kNetworking | ExportTag::kStub);
|
||||||
|
|
||||||
// http://www.google.com/patents/WO2008112448A1?cl=en
|
// http://www.google.com/patents/WO2008112448A1?cl=en
|
||||||
// Reserves a port for use by system link
|
// Reserves a port for use by system link
|
||||||
dword_result_t NetDll_XNetSetSystemLinkPort(dword_t caller, dword_t port) {
|
dword_result_t NetDll_XNetSetSystemLinkPort(dword_t caller, dword_t port) {
|
||||||
|
@ -386,16 +490,25 @@ dword_result_t NetDll_XNetSetSystemLinkPort(dword_t caller, dword_t port) {
|
||||||
DECLARE_XAM_EXPORT(NetDll_XNetSetSystemLinkPort,
|
DECLARE_XAM_EXPORT(NetDll_XNetSetSystemLinkPort,
|
||||||
ExportTag::kNetworking | ExportTag::kStub);
|
ExportTag::kNetworking | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL NetDll_XNetGetEthernetLinkStatus_shim(PPCContext* ppc_context,
|
// https://github.com/ILOVEPIE/Cxbx-Reloaded/blob/master/src/CxbxKrnl/EmuXOnline.h#L39
|
||||||
KernelState* kernel_state) {
|
struct XEthernetStatus {
|
||||||
// Games seem to call this before *Startup. If we return 0, they don't even
|
static const uint32_t XNET_ETHERNET_LINK_ACTIVE = 0x01;
|
||||||
// try.
|
static const uint32_t XNET_ETHERNET_LINK_100MBPS = 0x02;
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
static const uint32_t XNET_ETHERNET_LINK_10MBPS = 0x04;
|
||||||
|
static const uint32_t XNET_ETHERNET_LINK_FULL_DUPLEX = 0x08;
|
||||||
|
static const uint32_t XNET_ETHERNET_LINK_HALF_DUPLEX = 0x10;
|
||||||
|
};
|
||||||
|
|
||||||
XELOGD("NetDll_XNetGetEthernetLinkStatus(%d)", caller);
|
dword_result_t NetDll_XNetGetEthernetLinkStatus(dword_t caller) { return 0; }
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetGetEthernetLinkStatus,
|
||||||
|
ExportTag::kStub | ExportTag::kNetworking);
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(0);
|
dword_result_t NetDll_XNetDnsLookup(lpstring_t address, dword_t evt_handle,
|
||||||
|
pointer_t<XNDNS> host_out) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetDnsLookup,
|
||||||
|
ExportTag::kStub | ExportTag::kNetworking);
|
||||||
|
|
||||||
SHIM_CALL NetDll_XNetQosServiceLookup_shim(PPCContext* ppc_context,
|
SHIM_CALL NetDll_XNetQosServiceLookup_shim(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state) {
|
||||||
|
@ -411,6 +524,14 @@ SHIM_CALL NetDll_XNetQosServiceLookup_shim(PPCContext* ppc_context,
|
||||||
SHIM_SET_RETURN_32(1);
|
SHIM_SET_RETURN_32(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t NetDll_XNetQosListen(dword_t caller, lpvoid_t id, lpvoid_t data,
|
||||||
|
dword_t data_size, dword_t r7,
|
||||||
|
dword_t flags) {
|
||||||
|
return X_ERROR_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_XNetQosListen,
|
||||||
|
ExportTag::kStub | ExportTag::kNetworking);
|
||||||
|
|
||||||
dword_result_t NetDll_inet_addr(lpstring_t addr_ptr) {
|
dword_result_t NetDll_inet_addr(lpstring_t addr_ptr) {
|
||||||
uint32_t addr = inet_addr(addr_ptr);
|
uint32_t addr = inet_addr(addr_ptr);
|
||||||
return xe::byte_swap(addr);
|
return xe::byte_swap(addr);
|
||||||
|
@ -418,162 +539,190 @@ dword_result_t NetDll_inet_addr(lpstring_t addr_ptr) {
|
||||||
DECLARE_XAM_EXPORT(NetDll_inet_addr,
|
DECLARE_XAM_EXPORT(NetDll_inet_addr,
|
||||||
ExportTag::kImplemented | ExportTag::kNetworking);
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
SHIM_CALL NetDll_socket_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_socket(dword_t caller, dword_t af, dword_t type,
|
||||||
KernelState* kernel_state) {
|
dword_t protocol) {
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
XSocket* socket = new XSocket(kernel_state());
|
||||||
uint32_t af = SHIM_GET_ARG_32(1);
|
X_STATUS result = socket->Initialize(XSocket::AddressFamily((uint32_t)af),
|
||||||
uint32_t type = SHIM_GET_ARG_32(2);
|
XSocket::Type((uint32_t)type),
|
||||||
uint32_t protocol = SHIM_GET_ARG_32(3);
|
XSocket::Protocol((uint32_t)protocol));
|
||||||
|
|
||||||
XELOGD("NetDll_socket(%d, %d, %d, %d)", caller, af, type, protocol);
|
if (XFAILED(result)) {
|
||||||
if (protocol == 0xFE) {
|
socket->Release();
|
||||||
protocol = IPPROTO_UDP;
|
|
||||||
|
uint32_t error = xboxkrnl::RtlNtStatusToDosError(result);
|
||||||
|
XThread::SetLastError(error);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SOCKET socket_handle = socket(af, type, protocol);
|
return socket->handle();
|
||||||
assert_true(socket_handle >> 32 == 0);
|
|
||||||
|
|
||||||
XELOGD("NetDll_socket = %.8X", socket_handle);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(static_cast<uint32_t>(socket_handle));
|
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_socket,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
SHIM_CALL NetDll_closesocket_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_closesocket(dword_t caller, dword_t socket_handle) {
|
||||||
KernelState* kernel_state) {
|
auto socket =
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
XELOGD("NetDll_closesocket(%d, %.8X)", caller, socket_handle);
|
XThread::SetLastError(0x2736);
|
||||||
int ret = closesocket(socket_handle);
|
return -1;
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_CALL NetDll_setsockopt_shim(PPCContext* ppc_context,
|
|
||||||
KernelState* kernel_state) {
|
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
|
||||||
uint32_t level = SHIM_GET_ARG_32(2);
|
|
||||||
uint32_t optname = SHIM_GET_ARG_32(3);
|
|
||||||
uint32_t optval_ptr = SHIM_GET_ARG_32(4);
|
|
||||||
uint32_t optlen = SHIM_GET_ARG_32(5);
|
|
||||||
|
|
||||||
XELOGD("NetDll_setsockopt(%d, %.8X, %d, %d, %.8X, %d)", caller, socket_handle,
|
|
||||||
level, optname, optval_ptr, optlen);
|
|
||||||
|
|
||||||
char* optval = reinterpret_cast<char*>(SHIM_MEM_ADDR(optval_ptr));
|
|
||||||
int ret = setsockopt(socket_handle, level, optname, optval, optlen);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_CALL NetDll_ioctlsocket_shim(PPCContext* ppc_context,
|
|
||||||
KernelState* kernel_state) {
|
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
|
||||||
uint32_t cmd = SHIM_GET_ARG_32(2);
|
|
||||||
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
|
|
||||||
|
|
||||||
XELOGD("NetDll_ioctlsocket(%d, %.8X, %.8X, %.8X)", caller, socket_handle, cmd,
|
|
||||||
arg_ptr);
|
|
||||||
|
|
||||||
u_long arg = SHIM_MEM_32(arg_ptr);
|
|
||||||
int ret = ioctlsocket(socket_handle, cmd, &arg);
|
|
||||||
|
|
||||||
SHIM_SET_MEM_32(arg_ptr, arg);
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_CALL NetDll_bind_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
|
||||||
uint32_t name_ptr = SHIM_GET_ARG_32(2);
|
|
||||||
uint32_t namelen = SHIM_GET_ARG_32(3);
|
|
||||||
|
|
||||||
XELOGD("NetDll_bind(%d, %.8X, %.8X, %d)", caller, socket_handle, name_ptr,
|
|
||||||
namelen);
|
|
||||||
|
|
||||||
sockaddr name;
|
|
||||||
LoadSockaddr(SHIM_MEM_ADDR(name_ptr), &name);
|
|
||||||
int ret = bind(socket_handle, &name, namelen);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_CALL NetDll_connect_shim(PPCContext* ppc_context,
|
|
||||||
KernelState* kernel_state) {
|
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
|
||||||
uint32_t name_ptr = SHIM_GET_ARG_32(2);
|
|
||||||
uint32_t namelen = SHIM_GET_ARG_32(3);
|
|
||||||
|
|
||||||
XELOGD("NetDll_connect(%d, %.8X, %.8X, %d)", caller, socket_handle, name_ptr,
|
|
||||||
namelen);
|
|
||||||
|
|
||||||
sockaddr name;
|
|
||||||
LoadSockaddr(SHIM_MEM_ADDR(name_ptr), &name);
|
|
||||||
int ret = connect(socket_handle, &name, namelen);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_CALL NetDll_listen_shim(PPCContext* ppc_context,
|
|
||||||
KernelState* kernel_state) {
|
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
|
||||||
int32_t backlog = SHIM_GET_ARG_32(2);
|
|
||||||
|
|
||||||
XELOGD("NetDll_listen(%d, %.8X, %d)", caller, socket_handle, backlog);
|
|
||||||
|
|
||||||
int ret = listen(socket_handle, backlog);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_CALL NetDll_accept_shim(PPCContext* ppc_context,
|
|
||||||
KernelState* kernel_state) {
|
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
|
||||||
uint32_t addr_ptr = SHIM_GET_ARG_32(2);
|
|
||||||
uint32_t addrlen_ptr = SHIM_GET_ARG_32(3);
|
|
||||||
|
|
||||||
XELOGD("NetDll_accept(%d, %.8X, %d)", caller, socket_handle, addr_ptr,
|
|
||||||
addrlen_ptr);
|
|
||||||
|
|
||||||
sockaddr addr;
|
|
||||||
int addrlen;
|
|
||||||
SOCKET ret_socket = accept(socket_handle, &addr, &addrlen);
|
|
||||||
|
|
||||||
if (ret_socket == INVALID_SOCKET) {
|
|
||||||
if (addr_ptr) {
|
|
||||||
std::memset(SHIM_MEM_ADDR(addr_ptr), 0, sizeof(addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addrlen_ptr) {
|
// TODO: Absolutely delete this object. It is no longer valid after calling
|
||||||
SHIM_SET_MEM_32(addrlen_ptr, sizeof(addr));
|
// closesocket.
|
||||||
|
socket->Close();
|
||||||
|
socket->ReleaseHandle();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_closesocket,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
|
dword_result_t NetDll_setsockopt(dword_t caller, dword_t socket_handle,
|
||||||
|
dword_t level, dword_t optname,
|
||||||
|
lpvoid_t optval_ptr, dword_t optlen) {
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(-1);
|
X_STATUS status = socket->SetOption(level, optname, optval_ptr, optlen);
|
||||||
|
return XSUCCEEDED(status) ? 0 : -1;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_setsockopt,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
|
dword_result_t NetDll_ioctlsocket(dword_t caller, dword_t socket_handle,
|
||||||
|
dword_t cmd, lpvoid_t arg_ptr) {
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS status = socket->IOControl(cmd, arg_ptr);
|
||||||
|
if (XFAILED(status)) {
|
||||||
|
XThread::SetLastError(xboxkrnl::RtlNtStatusToDosError(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_ioctlsocket,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
|
dword_result_t NetDll_bind(dword_t caller, dword_t socket_handle,
|
||||||
|
pointer_t<XSOCKADDR_IN> name, dword_t namelen) {
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
N_XSOCKADDR_IN native_name(name);
|
||||||
|
X_STATUS status = socket->Bind(&native_name, namelen);
|
||||||
|
if (XFAILED(status)) {
|
||||||
|
XThread::SetLastError(xboxkrnl::RtlNtStatusToDosError(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_bind,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
|
dword_result_t NetDll_connect(dword_t caller, dword_t socket_handle,
|
||||||
|
pointer_t<XSOCKADDR> name, dword_t namelen) {
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
N_XSOCKADDR native_name(name);
|
||||||
|
X_STATUS status = socket->Connect(&native_name, namelen);
|
||||||
|
if (XFAILED(status)) {
|
||||||
|
XThread::SetLastError(xboxkrnl::RtlNtStatusToDosError(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_connect,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
|
dword_result_t NetDll_listen(dword_t caller, dword_t socket_handle,
|
||||||
|
int_t backlog) {
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS status = socket->Listen(backlog);
|
||||||
|
if (XFAILED(status)) {
|
||||||
|
XThread::SetLastError(xboxkrnl::RtlNtStatusToDosError(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_listen,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
|
dword_result_t NetDll_accept(dword_t caller, dword_t socket_handle,
|
||||||
|
pointer_t<XSOCKADDR> addr_ptr,
|
||||||
|
lpdword_t addrlen_ptr) {
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
N_XSOCKADDR native_addr(addr_ptr);
|
||||||
|
int native_len = *addrlen_ptr;
|
||||||
|
auto new_socket = socket->Accept(&native_addr, &native_len);
|
||||||
|
if (new_socket) {
|
||||||
|
addr_ptr->address_family = native_addr.address_family;
|
||||||
|
std::memcpy(addr_ptr->sa_data, native_addr.sa_data, *addrlen_ptr - 2);
|
||||||
|
*addrlen_ptr = native_len;
|
||||||
|
|
||||||
|
return new_socket->handle();
|
||||||
} else {
|
} else {
|
||||||
assert_true(ret_socket >> 32 == 0);
|
return -1;
|
||||||
if (addr_ptr) {
|
|
||||||
StoreSockaddr(addr, SHIM_MEM_ADDR(addr_ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addrlen_ptr) {
|
|
||||||
SHIM_SET_MEM_32(addrlen_ptr, addrlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(static_cast<uint32_t>(ret_socket));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_accept,
|
||||||
|
ExportTag::kImplemented | ExportTag::kNetworking);
|
||||||
|
|
||||||
void LoadFdset(const uint8_t* src, fd_set* dest) {
|
void LoadFdset(const uint8_t* src, fd_set* dest) {
|
||||||
dest->fd_count = xe::load_and_swap<uint32_t>(src);
|
dest->fd_count = xe::load_and_swap<uint32_t>(src);
|
||||||
for (int i = 0; i < 64; ++i) {
|
for (int i = 0; i < 64; ++i) {
|
||||||
auto socket_handle =
|
auto socket_handle =
|
||||||
static_cast<SOCKET>(xe::load_and_swap<uint32_t>(src + 4 + i * 4));
|
static_cast<X_HANDLE>(xe::load_and_swap<uint32_t>(src + 4 + i * 4));
|
||||||
dest->fd_array[i] = socket_handle;
|
if (!socket_handle) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert from Xenia -> native
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
auto native_handle = socket->native_handle();
|
||||||
|
|
||||||
|
dest->fd_array[i] = native_handle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,6 +730,9 @@ void StoreFdset(const fd_set& src, uint8_t* dest) {
|
||||||
xe::store_and_swap<uint32_t>(dest, src.fd_count);
|
xe::store_and_swap<uint32_t>(dest, src.fd_count);
|
||||||
for (int i = 0; i < 64; ++i) {
|
for (int i = 0; i < 64; ++i) {
|
||||||
SOCKET socket_handle = src.fd_array[i];
|
SOCKET socket_handle = src.fd_array[i];
|
||||||
|
|
||||||
|
// TODO: Native -> Xenia
|
||||||
|
|
||||||
assert_true(socket_handle >> 32 == 0);
|
assert_true(socket_handle >> 32 == 0);
|
||||||
xe::store_and_swap<uint32_t>(dest + 4 + i * 4,
|
xe::store_and_swap<uint32_t>(dest + 4 + i * 4,
|
||||||
static_cast<uint32_t>(socket_handle));
|
static_cast<uint32_t>(socket_handle));
|
||||||
|
@ -637,112 +789,98 @@ SHIM_CALL NetDll_select_shim(PPCContext* ppc_context,
|
||||||
SHIM_SET_RETURN_32(ret);
|
SHIM_SET_RETURN_32(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHIM_CALL NetDll_recv_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
dword_result_t NetDll_recv(dword_t caller, dword_t socket_handle,
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
lpvoid_t buf_ptr, dword_t buf_len, dword_t flags) {
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
auto socket =
|
||||||
uint32_t buf_ptr = SHIM_GET_ARG_32(2);
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
uint32_t len = SHIM_GET_ARG_32(3);
|
if (!socket) {
|
||||||
uint32_t flags = SHIM_GET_ARG_32(4);
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
XELOGD("NetDll_recv(%d, %.8X, %.8X, %d, %d)", caller, socket_handle, buf_ptr,
|
return -1;
|
||||||
len, flags);
|
|
||||||
|
|
||||||
int ret = recv(socket_handle, reinterpret_cast<char*>(SHIM_MEM_ADDR(buf_ptr)),
|
|
||||||
len, flags);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHIM_CALL NetDll_recvfrom_shim(PPCContext* ppc_context,
|
|
||||||
KernelState* kernel_state) {
|
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
|
||||||
uint32_t buf_ptr = SHIM_GET_ARG_32(2);
|
|
||||||
uint32_t len = SHIM_GET_ARG_32(3);
|
|
||||||
uint32_t flags = SHIM_GET_ARG_32(4);
|
|
||||||
uint32_t from_ptr = SHIM_GET_ARG_32(5);
|
|
||||||
uint32_t fromlen_ptr = SHIM_GET_ARG_32(6);
|
|
||||||
|
|
||||||
XELOGD("NetDll_recvfrom(%d, %.8X, %.8X, %d, %d, %.8X, %.8X)", caller,
|
|
||||||
socket_handle, buf_ptr, len, flags, from_ptr, fromlen_ptr);
|
|
||||||
|
|
||||||
sockaddr from;
|
|
||||||
int fromlen = sizeof(from);
|
|
||||||
int ret =
|
|
||||||
recvfrom(socket_handle, reinterpret_cast<char*>(SHIM_MEM_ADDR(buf_ptr)),
|
|
||||||
len, flags, &from, &fromlen);
|
|
||||||
if (ret == -1) {
|
|
||||||
std::memset(SHIM_MEM_ADDR(from_ptr), 0, sizeof(from));
|
|
||||||
SHIM_SET_MEM_32(fromlen_ptr, sizeof(from));
|
|
||||||
} else {
|
|
||||||
StoreSockaddr(from, SHIM_MEM_ADDR(from_ptr));
|
|
||||||
SHIM_SET_MEM_32(fromlen_ptr, fromlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
return socket->Recv(buf_ptr, buf_len, flags);
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_recv,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
SHIM_CALL NetDll_send_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
dword_result_t NetDll_recvfrom(dword_t caller, dword_t socket_handle,
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
lpvoid_t buf_ptr, dword_t buf_len, dword_t flags,
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
pointer_t<XSOCKADDR_IN> from_ptr,
|
||||||
uint32_t buf_ptr = SHIM_GET_ARG_32(2);
|
lpdword_t fromlen_ptr) {
|
||||||
uint32_t len = SHIM_GET_ARG_32(3);
|
auto socket =
|
||||||
uint32_t flags = SHIM_GET_ARG_32(4);
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
XELOGD("NetDll_send(%d, %.8X, %.8X, %d, %d)", caller, socket_handle, buf_ptr,
|
N_XSOCKADDR_IN native_from;
|
||||||
len, flags);
|
if (from_ptr) {
|
||||||
|
native_from = *from_ptr;
|
||||||
|
}
|
||||||
|
uint32_t native_fromlen = fromlen_ptr ? *fromlen_ptr : 0;
|
||||||
|
int ret = socket->RecvFrom(buf_ptr, buf_len, flags, &native_from,
|
||||||
|
fromlen_ptr ? &native_fromlen : 0);
|
||||||
|
|
||||||
int ret = send(socket_handle, reinterpret_cast<char*>(SHIM_MEM_ADDR(buf_ptr)),
|
if (from_ptr) {
|
||||||
len, flags);
|
from_ptr->sin_family = native_from.sin_family;
|
||||||
|
from_ptr->sin_port = native_from.sin_port;
|
||||||
|
from_ptr->sin_addr = native_from.sin_addr;
|
||||||
|
memset(from_ptr->sin_zero, 0, 8);
|
||||||
|
}
|
||||||
|
if (fromlen_ptr) {
|
||||||
|
*fromlen_ptr = native_fromlen;
|
||||||
|
}
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
if (ret == -1) {
|
||||||
|
// TODO: Better way of getting the error code
|
||||||
|
uint32_t error_code = WSAGetLastError();
|
||||||
|
XThread::SetLastError(error_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_recvfrom,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
SHIM_CALL NetDll_sendto_shim(PPCContext* ppc_context,
|
dword_result_t NetDll_send(dword_t caller, dword_t socket_handle,
|
||||||
KernelState* kernel_state) {
|
lpvoid_t buf_ptr, dword_t buf_len, dword_t flags) {
|
||||||
uint32_t caller = SHIM_GET_ARG_32(0);
|
auto socket =
|
||||||
uint32_t socket_handle = SHIM_GET_ARG_32(1);
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
uint32_t buf_ptr = SHIM_GET_ARG_32(2);
|
if (!socket) {
|
||||||
uint32_t len = SHIM_GET_ARG_32(3);
|
// WSAENOTSOCK
|
||||||
uint32_t flags = SHIM_GET_ARG_32(4);
|
XThread::SetLastError(0x2736);
|
||||||
uint32_t to_ptr = SHIM_GET_ARG_32(5);
|
return -1;
|
||||||
uint32_t tolen = SHIM_GET_ARG_32(6);
|
}
|
||||||
|
|
||||||
XELOGD("NetDll_sendto(%d, %.8X, %.8X, %d, %d, %.8X, %d)", caller,
|
return socket->Send(buf_ptr, buf_len, flags);
|
||||||
socket_handle, buf_ptr, len, flags, to_ptr, tolen);
|
|
||||||
|
|
||||||
sockaddr to;
|
|
||||||
LoadSockaddr(SHIM_MEM_ADDR(to_ptr), &to);
|
|
||||||
int ret =
|
|
||||||
sendto(socket_handle, reinterpret_cast<char*>(SHIM_MEM_ADDR(buf_ptr)),
|
|
||||||
len, flags, &to, tolen);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(ret);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_send,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
|
dword_result_t NetDll_sendto(dword_t caller, dword_t socket_handle,
|
||||||
|
lpvoid_t buf_ptr, dword_t buf_len, dword_t flags,
|
||||||
|
pointer_t<XSOCKADDR_IN> to_ptr, dword_t to_len) {
|
||||||
|
auto socket =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSocket>(socket_handle);
|
||||||
|
if (!socket) {
|
||||||
|
// WSAENOTSOCK
|
||||||
|
XThread::SetLastError(0x2736);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
N_XSOCKADDR_IN native_to(to_ptr);
|
||||||
|
return socket->SendTo(buf_ptr, buf_len, flags, &native_to, to_len);
|
||||||
|
}
|
||||||
|
DECLARE_XAM_EXPORT(NetDll_sendto,
|
||||||
|
ExportTag::kNetworking | ExportTag::kImplemented);
|
||||||
|
|
||||||
void RegisterNetExports(xe::cpu::ExportResolver* export_resolver,
|
void RegisterNetExports(xe::cpu::ExportResolver* export_resolver,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state) {
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_XNetStartup, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_XNetCleanup, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_XNetRandom, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_WSAStartup, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_WSACleanup, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_WSAGetLastError, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_XNetGetEthernetLinkStatus, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_XNetQosServiceLookup, state);
|
SHIM_SET_MAPPING("xam.xex", NetDll_XNetQosServiceLookup, state);
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_socket, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_closesocket, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_setsockopt, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_ioctlsocket, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_bind, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_connect, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_listen, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_accept, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_select, state);
|
SHIM_SET_MAPPING("xam.xex", NetDll_select, state);
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_recv, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_recvfrom, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_send, state);
|
|
||||||
SHIM_SET_MAPPING("xam.xex", NetDll_sendto, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xam
|
} // namespace xam
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "src/xenia/kernel/xsocket.h"
|
||||||
|
|
||||||
|
#include "xenia/base/platform.h"
|
||||||
|
#include "xenia/kernel/kernel_state.h"
|
||||||
|
#include "xenia/kernel/xam/xam_module.h"
|
||||||
|
// #include "xenia/kernel/xnet.h"
|
||||||
|
|
||||||
|
#if XE_PLATFORM_WIN32
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#elif XE_PLATFORM_LINUX
|
||||||
|
#error TODO: Proper network includes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
XSocket::XSocket(KernelState* kernel_state)
|
||||||
|
: XObject(kernel_state, XObject::kTypeSocket) {}
|
||||||
|
|
||||||
|
XSocket::XSocket(KernelState* kernel_state, uint64_t native_handle)
|
||||||
|
: XObject(kernel_state, XObject::kTypeSocket),
|
||||||
|
native_handle_(native_handle) {}
|
||||||
|
|
||||||
|
XSocket::~XSocket() { Close(); }
|
||||||
|
|
||||||
|
X_STATUS XSocket::Initialize(AddressFamily af, Type type, Protocol proto) {
|
||||||
|
af_ = af;
|
||||||
|
type_ = type;
|
||||||
|
proto_ = proto;
|
||||||
|
|
||||||
|
if (proto == Protocol::IPPROTO_VDP) {
|
||||||
|
// VDP is a layer on top of UDP.
|
||||||
|
proto = Protocol::IPPROTO_UDP;
|
||||||
|
}
|
||||||
|
|
||||||
|
native_handle_ = socket(af, type, proto);
|
||||||
|
if (native_handle_ == -1) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XSocket::Close() {
|
||||||
|
#if XE_PLATFORM_WIN32
|
||||||
|
int ret = closesocket(native_handle_);
|
||||||
|
#elif XE_PLATFORM_LINUX
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XSocket::SetOption(uint32_t level, uint32_t optname, void* optval_ptr,
|
||||||
|
uint32_t optlen) {
|
||||||
|
if (level == 0xFFFF && (optname == 0x5801 || optname == 0x5802)) {
|
||||||
|
// Disable socket encryption
|
||||||
|
secure_ = false;
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret =
|
||||||
|
setsockopt(native_handle_, level, optname, (char*)optval_ptr, optlen);
|
||||||
|
if (ret < 0) {
|
||||||
|
// TODO: WSAGetLastError()
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SO_BROADCAST
|
||||||
|
if (level == 0xFFFF && optname == 0x0020) {
|
||||||
|
broadcast_socket_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XSocket::IOControl(uint32_t cmd, uint8_t* arg_ptr) {
|
||||||
|
int ret = ioctlsocket(native_handle_, cmd, (u_long*)arg_ptr);
|
||||||
|
if (ret < 0) {
|
||||||
|
// TODO: Get last error
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XSocket::Connect(N_XSOCKADDR* name, int name_len) {
|
||||||
|
int ret = connect(native_handle_, (sockaddr*)name, name_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) {
|
||||||
|
int ret = bind(native_handle_, (sockaddr*)name, name_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bound_ = true;
|
||||||
|
bound_port_ = name->sin_port;
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XSocket::Listen(int backlog) {
|
||||||
|
int ret = listen(native_handle_, backlog);
|
||||||
|
if (ret < 0) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref<XSocket> XSocket::Accept(N_XSOCKADDR* name, int* name_len) {
|
||||||
|
sockaddr n_sockaddr;
|
||||||
|
int n_name_len = sizeof(sockaddr);
|
||||||
|
SOCKET ret = accept(native_handle_, &n_sockaddr, &n_name_len);
|
||||||
|
if (ret == INVALID_SOCKET) {
|
||||||
|
std::memset(name, 0, *name_len);
|
||||||
|
*name_len = 0;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(name, &n_sockaddr, n_name_len);
|
||||||
|
*name_len = n_name_len;
|
||||||
|
|
||||||
|
// Create a kernel object to represent the new socket, and copy parameters
|
||||||
|
// over.
|
||||||
|
auto socket = object_ref<XSocket>(new XSocket(kernel_state_, ret));
|
||||||
|
socket->af_ = af_;
|
||||||
|
socket->type_ = type_;
|
||||||
|
socket->proto_ = proto_;
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XSocket::Recv(uint8_t* buf, uint32_t buf_len, uint32_t flags) {
|
||||||
|
return recv(native_handle_, reinterpret_cast<char*>(buf), buf_len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int XSocket::RecvFrom(uint8_t* buf, uint32_t buf_len, uint32_t flags,
|
||||||
|
N_XSOCKADDR_IN* from, uint32_t* from_len) {
|
||||||
|
// Pop from secure packets first
|
||||||
|
// TODO(DrChat): Enable when I commit XNet
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(incoming_packet_mutex_);
|
||||||
|
if (incoming_packets_.size()) {
|
||||||
|
packet* pkt = (packet*)incoming_packets_.front();
|
||||||
|
int data_len = pkt->data_len;
|
||||||
|
std::memcpy(buf, pkt->data, std::min((uint32_t)pkt->data_len, buf_len));
|
||||||
|
|
||||||
|
from->sin_family = 2;
|
||||||
|
from->sin_addr = pkt->src_ip;
|
||||||
|
from->sin_port = pkt->src_port;
|
||||||
|
|
||||||
|
incoming_packets_.pop();
|
||||||
|
uint8_t* pkt_ui8 = (uint8_t*)pkt;
|
||||||
|
delete[] pkt_ui8;
|
||||||
|
|
||||||
|
return data_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
sockaddr_in nfrom;
|
||||||
|
int nfromlen = sizeof(sockaddr_in);
|
||||||
|
int ret = recvfrom(native_handle_, reinterpret_cast<char*>(buf), buf_len,
|
||||||
|
flags, (sockaddr*)&nfrom, &nfromlen);
|
||||||
|
if (from) {
|
||||||
|
from->sin_family = nfrom.sin_family;
|
||||||
|
from->sin_addr = ntohl(nfrom.sin_addr.s_addr); // BE <- BE
|
||||||
|
from->sin_port = nfrom.sin_port;
|
||||||
|
memset(&from->sin_zero, 0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from_len) {
|
||||||
|
*from_len = nfromlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XSocket::Send(const uint8_t* buf, uint32_t buf_len, uint32_t flags) {
|
||||||
|
return send(native_handle_, reinterpret_cast<const char*>(buf), buf_len,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int XSocket::SendTo(uint8_t* buf, uint32_t buf_len, uint32_t flags,
|
||||||
|
N_XSOCKADDR_IN* to, uint32_t to_len) {
|
||||||
|
// Send 2 copies of the packet: One to XNet (for network security) and an
|
||||||
|
// unencrypted copy for other Xenia hosts.
|
||||||
|
// TODO(DrChat): Enable when I commit XNet.
|
||||||
|
/*
|
||||||
|
auto xam = kernel_state()->GetKernelModule<xam::XamModule>("xam.xex");
|
||||||
|
auto xnet = xam->xnet();
|
||||||
|
if (xnet) {
|
||||||
|
xnet->SendPacket(this, to, buf, buf_len);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
sockaddr_in nto;
|
||||||
|
if (to) {
|
||||||
|
nto.sin_addr.S_un.S_addr = to->sin_addr;
|
||||||
|
nto.sin_family = to->sin_family;
|
||||||
|
nto.sin_port = to->sin_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendto(native_handle_, reinterpret_cast<char*>(buf), buf_len, flags,
|
||||||
|
to ? (sockaddr*)&nto : nullptr, to_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XSocket::QueuePacket(uint32_t src_ip, uint16_t src_port,
|
||||||
|
const uint8_t* buf, size_t len) {
|
||||||
|
packet* pkt = reinterpret_cast<packet*>(new uint8_t[sizeof(packet) + len]);
|
||||||
|
pkt->src_ip = src_ip;
|
||||||
|
pkt->src_port = src_port;
|
||||||
|
|
||||||
|
pkt->data_len = (uint16_t)len;
|
||||||
|
std::memcpy(pkt->data, buf, len);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(incoming_packet_mutex_);
|
||||||
|
incoming_packets_.push((uint8_t*)pkt);
|
||||||
|
|
||||||
|
// TODO: Limit on number of incoming packets?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,151 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_KERNEL_XSOCKET_H_
|
||||||
|
#define XENIA_KERNEL_XSOCKET_H_
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include "xenia/base/byte_order.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
#include "xenia/kernel/xobject.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
struct XSOCKADDR {
|
||||||
|
xe::be<uint16_t> address_family;
|
||||||
|
char sa_data[14];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct N_XSOCKADDR {
|
||||||
|
N_XSOCKADDR() {}
|
||||||
|
N_XSOCKADDR(const XSOCKADDR* other) { *this = *other; }
|
||||||
|
N_XSOCKADDR& operator=(const XSOCKADDR& other) {
|
||||||
|
address_family = other.address_family;
|
||||||
|
std::memcpy(sa_data, other.sa_data, xe::countof(sa_data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t address_family;
|
||||||
|
char sa_data[14];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XSOCKADDR_IN {
|
||||||
|
xe::be<uint16_t> sin_family;
|
||||||
|
|
||||||
|
// Always big-endian!
|
||||||
|
xe::be<uint16_t> sin_port;
|
||||||
|
xe::be<uint32_t> sin_addr;
|
||||||
|
char sin_zero[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Xenia native sockaddr_in
|
||||||
|
struct N_XSOCKADDR_IN {
|
||||||
|
N_XSOCKADDR_IN() {}
|
||||||
|
N_XSOCKADDR_IN(const XSOCKADDR_IN* other) { *this = *other; }
|
||||||
|
N_XSOCKADDR_IN& operator=(const XSOCKADDR_IN& other) {
|
||||||
|
sin_family = other.sin_family;
|
||||||
|
sin_port = other.sin_port;
|
||||||
|
sin_addr = other.sin_addr;
|
||||||
|
std::memset(sin_zero, 0, 8);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sin_family;
|
||||||
|
xe::be<uint16_t> sin_port;
|
||||||
|
xe::be<uint32_t> sin_addr;
|
||||||
|
char sin_zero[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
class XSocket : public XObject {
|
||||||
|
public:
|
||||||
|
static const Type kType = kTypeSocket;
|
||||||
|
|
||||||
|
enum AddressFamily {
|
||||||
|
AF_INET = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
SOCK_STREAM = 1,
|
||||||
|
SOCK_DGRAM = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Protocol {
|
||||||
|
IPPROTO_TCP = 6,
|
||||||
|
IPPROTO_UDP = 17,
|
||||||
|
|
||||||
|
// LIVE Voice and Data Protocol
|
||||||
|
// http://blog.csdn.net/baozi3026/article/details/4277227
|
||||||
|
// Format: [cbGameData][GameData(encrypted)][VoiceData(unencrypted)]
|
||||||
|
IPPROTO_VDP = 254,
|
||||||
|
};
|
||||||
|
|
||||||
|
XSocket(KernelState* kernel_state);
|
||||||
|
~XSocket();
|
||||||
|
|
||||||
|
uint64_t native_handle() const { return native_handle_; }
|
||||||
|
uint16_t bound_port() const { return bound_port_; }
|
||||||
|
|
||||||
|
X_STATUS Initialize(AddressFamily af, Type type, Protocol proto);
|
||||||
|
X_STATUS Close();
|
||||||
|
|
||||||
|
X_STATUS SetOption(uint32_t level, uint32_t optname, void* optval_ptr,
|
||||||
|
uint32_t optlen);
|
||||||
|
X_STATUS IOControl(uint32_t cmd, uint8_t* arg_ptr);
|
||||||
|
|
||||||
|
X_STATUS Connect(N_XSOCKADDR* name, int name_len);
|
||||||
|
X_STATUS Bind(N_XSOCKADDR_IN* name, int name_len);
|
||||||
|
X_STATUS Listen(int backlog);
|
||||||
|
object_ref<XSocket> Accept(N_XSOCKADDR* name, int* name_len);
|
||||||
|
|
||||||
|
int Recv(uint8_t* buf, uint32_t buf_len, uint32_t flags);
|
||||||
|
int Send(const uint8_t* buf, uint32_t buf_len, uint32_t flags);
|
||||||
|
|
||||||
|
int RecvFrom(uint8_t* buf, uint32_t buf_len, uint32_t flags,
|
||||||
|
N_XSOCKADDR_IN* from, uint32_t* from_len);
|
||||||
|
int SendTo(uint8_t* buf, uint32_t buf_len, uint32_t flags, N_XSOCKADDR_IN* to,
|
||||||
|
uint32_t to_len);
|
||||||
|
|
||||||
|
struct packet {
|
||||||
|
// These values are in network byte order.
|
||||||
|
xe::be<uint16_t> src_port;
|
||||||
|
xe::be<uint32_t> src_ip;
|
||||||
|
|
||||||
|
uint16_t data_len;
|
||||||
|
uint8_t data[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Queue a packet into our internal buffer.
|
||||||
|
bool QueuePacket(uint32_t src_ip, uint16_t src_port, const uint8_t* buf,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
XSocket(KernelState* kernel_state, uint64_t native_handle);
|
||||||
|
uint64_t native_handle_ = -1;
|
||||||
|
|
||||||
|
AddressFamily af_; // Address family
|
||||||
|
Type type_; // Type (DGRAM/Stream/etc)
|
||||||
|
Protocol proto_; // Protocol (TCP/UDP/etc)
|
||||||
|
bool secure_ = true; // Secure socket (encryption enabled)
|
||||||
|
|
||||||
|
bool bound_ = false; // Explicitly bound to an IP address?
|
||||||
|
uint16_t bound_port_ = 0;
|
||||||
|
|
||||||
|
bool broadcast_socket_ = false;
|
||||||
|
|
||||||
|
std::unique_ptr<xe::threading::Event> event_;
|
||||||
|
std::mutex incoming_packet_mutex_;
|
||||||
|
std::queue<uint8_t*> incoming_packets_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_KERNEL_XSOCKET_H_
|
Loading…
Reference in New Issue