From 40d87314d05b87b623cf62b50c8cd471209beaeb Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:38:08 -0400 Subject: [PATCH] Add NXDK (Xbox) support --- enet | 2 +- nanors/deps/obl/oblas_lite.c | 2 +- src/Platform.c | 12 +++++---- src/Platform.h | 51 ++++++++++++++++++++++++------------ src/PlatformSockets.c | 32 +++++++++++----------- src/PlatformSockets.h | 4 ++- src/rswrapper.c | 4 +-- 7 files changed, 65 insertions(+), 42 deletions(-) diff --git a/enet b/enet index c7353c0..0eb84dc 160000 --- a/enet +++ b/enet @@ -1 +1 @@ -Subproject commit c7353c059373f8d3fc83d451f8f1a477be3dc94e +Subproject commit 0eb84dcca830dcee950a12a48f63062d950d03d0 diff --git a/nanors/deps/obl/oblas_lite.c b/nanors/deps/obl/oblas_lite.c index 64cc8d8..1e01697 100644 --- a/nanors/deps/obl/oblas_lite.c +++ b/nanors/deps/obl/oblas_lite.c @@ -58,7 +58,7 @@ void obl_axpyb32_ref(u8 *a, u32 *b, u8 u, unsigned k) for (unsigned idx = 0, p = 0; idx < k; idx += 8 * sizeof(u32), p++) { u32 tmp = b[p]; while (tmp > 0) { -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) unsigned long index = 0; _BitScanForward(&index, tmp); unsigned tz = (unsigned int)index; diff --git a/src/Platform.c b/src/Platform.c index d68e692..d34171e 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -20,7 +20,7 @@ static int activeMutexes = 0; static int activeEvents = 0; static int activeCondVars = 0; -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) #pragma pack(push, 8) typedef struct tagTHREADNAME_INFO @@ -65,7 +65,9 @@ void setThreadNameWin32(const char* name) { } #endif } +#endif +#if defined(LC_WINDOWS) DWORD WINAPI ThreadProc(LPVOID lpParameter) { struct thread_context* ctx = (struct thread_context*)lpParameter; #elif defined(__WIIU__) @@ -76,7 +78,7 @@ void* ThreadProc(void* context) { struct thread_context* ctx = (struct thread_context*)context; #endif -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) setThreadNameWin32(ctx->name); #elif defined(__linux__) || defined(__FreeBSD__) pthread_setname_np(pthread_self(), ctx->name); @@ -298,7 +300,7 @@ int PltCreateThread(const char* name, ThreadEntry entry, void* context, PLT_THRE free(ctx); return err; } - + } #endif @@ -309,7 +311,7 @@ int PltCreateThread(const char* name, ThreadEntry entry, void* context, PLT_THRE int PltCreateEvent(PLT_EVENT* event) { #if defined(LC_WINDOWS) - *event = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); + *event = CreateEvent(NULL, TRUE, FALSE, NULL); if (!*event) { return -1; } @@ -578,7 +580,7 @@ bool PltSafeStrcpy(char* dest, size_t dest_size, const char* src) { memset(dest, 0xFE, dest_size); #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(NXDK) // strncpy_s() with _TRUNCATE does what we need for MSVC. // We use this rather than strcpy_s() because we don't want // the invalid parameter handler invoked upon failure. diff --git a/src/Platform.h b/src/Platform.h index 302d52a..2292b38 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -1,6 +1,6 @@ #pragma once -#ifdef _WIN32 +#if defined(_WIN32) && !defined(NXDK) // Prevent bogus definitions of error codes // that are incompatible with Winsock errors. #define _CRT_NO_POSIX_ERROR_CODES @@ -13,11 +13,23 @@ #include #include -#ifdef _WIN32 +#if defined(_WIN32) && !defined(NXDK) #define WIN32_LEAN_AND_MEAN #include #include #include +#elif defined(NXDK) +// nxdk exposes Win32-style threading primitives, but its network stack is +// lwIP with POSIX/BSD socket compatibility headers. Pull in the socket-facing +// headers from the POSIX side so moonlight-common-c uses the Unix backend. +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include #elif defined(__APPLE__) #include #include @@ -64,15 +76,19 @@ #endif #ifdef LC_WINDOWS +# if !defined(NXDK) // Windows doesn't have strtok_r() but it has the same // function named strtok_s(). #define strtok_r strtok_s +# endif -# if defined(WINAPI_FAMILY) && WINAPI_FAMILY==WINAPI_FAMILY_APP -# define LC_UWP -# else -# define LC_WINDOWS_DESKTOP -#endif +# if !defined(NXDK) +# if defined(WINAPI_FAMILY) && WINAPI_FAMILY==WINAPI_FAMILY_APP +# define LC_UWP +# else +# define LC_WINDOWS_DESKTOP +# endif +# endif #endif @@ -83,7 +99,7 @@ if (ListenerCallbacks.logMessage) \ ListenerCallbacks.logMessage(s, ##__VA_ARGS__) -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(__clang__) #include #ifdef LC_DEBUG #define LC_ASSERT(x) __analysis_assume(x); \ @@ -116,21 +132,22 @@ #define LC_ASSERT_VT(x) LC_ASSERT(x) #endif -#ifdef _MSC_VER +#if defined(__has_builtin) && __has_builtin(__builtin_bswap16) +#define LC_HAS_BUILTIN_BSWAP +#endif + +#if defined(LC_HAS_BUILTIN_BSWAP) || \ + (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) +#define BSWAP16(x) __builtin_bswap16(x) +#define BSWAP32(x) __builtin_bswap32(x) +#define BSWAP64(x) __builtin_bswap64(x) +#elif defined(_MSC_VER) #pragma intrinsic(_byteswap_ushort) #define BSWAP16(x) _byteswap_ushort(x) #pragma intrinsic(_byteswap_ulong) #define BSWAP32(x) _byteswap_ulong(x) #pragma intrinsic(_byteswap_uint64) #define BSWAP64(x) _byteswap_uint64(x) -#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) -#define BSWAP16(x) __builtin_bswap16(x) -#define BSWAP32(x) __builtin_bswap32(x) -#define BSWAP64(x) __builtin_bswap64(x) -#elif defined(__has_builtin) && __has_builtin(__builtin_bswap16) -#define BSWAP16(x) __builtin_bswap16(x) -#define BSWAP32(x) __builtin_bswap32(x) -#define BSWAP64(x) __builtin_bswap64(x) #else #error Please define your platform byteswap macros! #endif diff --git a/src/PlatformSockets.c b/src/PlatformSockets.c index 41e7dd8..bd4789c 100644 --- a/src/PlatformSockets.c +++ b/src/PlatformSockets.c @@ -12,7 +12,7 @@ #endif #define TCPv6_MSS 1220 -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) #ifndef SIO_UDP_CONNRESET #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12) @@ -70,7 +70,7 @@ void shutdownTcpSocket(SOCKET s) { } int setNonFatalRecvTimeoutMs(SOCKET s, int timeoutMs) { -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) // Windows says that SO_RCVTIMEO puts the socket into an indeterminate state // when a timeout occurs. MSDN doesn't go into it any more than that, but it // seems likely that they are referring to the inability to know whether a @@ -93,7 +93,7 @@ int setNonFatalRecvTimeoutMs(SOCKET s, int timeoutMs) { } int pollSockets(struct pollfd* pollFds, int pollFdsCount, int timeoutMs) { -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) // We could have used WSAPoll() but it has some nasty bugs // https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/ // @@ -206,7 +206,7 @@ int recvUdpSocket(SOCKET s, char* buffer, int size, bool useSelect) { (LastSocketError() == EWOULDBLOCK || LastSocketError() == EINTR || LastSocketError() == EAGAIN || - #if defined(LC_WINDOWS) + #if defined(LC_WINDOWS) && !defined(NXDK) // This error is specific to overlapped I/O which isn't even // possible to perform with recvfrom(). It seems to randomly // be returned instead of WSAETIMEDOUT on certain systems. @@ -221,7 +221,7 @@ int recvUdpSocket(SOCKET s, char* buffer, int size, bool useSelect) { // We may receive an error due to a previous ICMP Port Unreachable error received // by this socket. We want to ignore those and continue reading. If the remote party // is really dead, ENet or TCP connection failures will trigger connection teardown. -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) } while (err < 0 && LastSocketError() == WSAECONNRESET); #else } while (err < 0 && LastSocketError() == ECONNREFUSED); @@ -231,7 +231,7 @@ int recvUdpSocket(SOCKET s, char* buffer, int size, bool useSelect) { } void closeSocket(SOCKET s) { -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) closesocket(s); #else close(s); @@ -335,7 +335,7 @@ SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCK int val = 1; setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (char*)&val, sizeof(val)); } -#elif defined(LC_WINDOWS) +#elif defined(LC_WINDOWS) && !defined(NXDK) { // Disable WSAECONNRESET for UDP sockets on Windows BOOL val = FALSE; @@ -409,10 +409,10 @@ int setSocketNonBlocking(SOCKET s, bool enabled) { #if defined(__vita__) || defined(__HAIKU__) int val = enabled ? 1 : 0; return setsockopt(s, SOL_SOCKET, SO_NONBLOCK, (char*)&val, sizeof(val)); -#elif defined(O_NONBLOCK) +#elif defined(O_NONBLOCK) && !defined(NXDK) return fcntl(s, F_SETFL, (enabled ? O_NONBLOCK : 0) | (fcntl(s, F_GETFL) & ~O_NONBLOCK)); #elif defined(FIONBIO) -#ifdef LC_WINDOWS +#if defined(LC_WINDOWS) && !defined(NXDK) u_long val = enabled ? 1 : 0; #else int val = enabled ? 1 : 0; @@ -452,7 +452,6 @@ SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen, LC_SOCKADDR addr; struct pollfd pfd; int err; - int val; // Create a non-blocking TCP socket s = createSocket(dstaddr->ss_family, SOCK_STREAM, IPPROTO_TCP, true); @@ -471,7 +470,9 @@ SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen, // Note: This only changes the max packet size we can *receive* from the host PC. // We still must split our own sends into smaller chunks with TCP_NODELAY enabled to // avoid MTU issues on the way out to to the target. -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) + int val; + // Windows doesn't support setting TCP_MAXSEG but IP_PMTUDISC_DONT forces the MSS to the protocol // minimum which is what we want here. Linux doesn't do this (disabling PMTUD just avoids setting DF). if (dstaddr->ss_family == AF_INET) { @@ -491,12 +492,13 @@ SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen, // restrict MSS to the minimum. It strips all options out of the SYN packet which // forces the remote party to fall back to the minimum MSS. TCP_MAXSEG doesn't seem // to work correctly for outbound connections on macOS/iOS. - val = 1; + int val = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, (char*)&val, sizeof(val)) < 0) { Limelog("setsockopt(TCP_NOOPT, %d) failed: %d\n", val, (int)LastSocketError()); } #elif defined(TCP_MAXSEG) - val = dstaddr->ss_family == AF_INET ? TCPv4_MSS : TCPv6_MSS; + int val = dstaddr->ss_family == AF_INET ? TCPv4_MSS : TCPv6_MSS; + if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, (char*)&val, sizeof(val)) < 0) { Limelog("setsockopt(TCP_MAXSEG, %d) failed: %d\n", val, (int)LastSocketError()); } @@ -1004,7 +1006,7 @@ void exitLowLatencyMode(void) { } int initializePlatformSockets(void) { -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) WSADATA data; return WSAStartup(MAKEWORD(2, 0), &data); #elif defined(__vita__) || defined(__WIIU__) || defined(__3DS__) @@ -1027,7 +1029,7 @@ int initializePlatformSockets(void) { } void cleanupPlatformSockets(void) { -#if defined(LC_WINDOWS) +#if defined(LC_WINDOWS) && !defined(NXDK) WSACleanup(); #else #endif diff --git a/src/PlatformSockets.h b/src/PlatformSockets.h index 02a5445..4bac8bd 100644 --- a/src/PlatformSockets.h +++ b/src/PlatformSockets.h @@ -18,7 +18,7 @@ extern in_port_t n3ds_udp_port; #endif #endif -#ifdef _WIN32 +#if defined(_WIN32) && !defined(NXDK) #define WIN32_LEAN_AND_MEAN #include #include @@ -83,7 +83,9 @@ typedef int SOCKADDR_LEN; #include #include +#ifndef ioctlsocket #define ioctlsocket ioctl +#endif #define LastSocketError() errno #define SetLastSocketError(x) errno = x #define INVALID_SOCKET -1 diff --git a/src/rswrapper.c b/src/rswrapper.c index 620f0e0..1a61d1c 100644 --- a/src/rswrapper.c +++ b/src/rswrapper.c @@ -117,7 +117,7 @@ reed_solomon_release_t reed_solomon_release_fn; reed_solomon_encode_t reed_solomon_encode_fn; reed_solomon_decode_t reed_solomon_decode_fn; -#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64)) +#if defined(_MSC_VER) && !defined(NXDK) && (defined(_M_IX86) || defined(_M_AMD64)) #if defined(_M_AMD64) // For some reason this is needed to avoid a "C1189 No target architecture" error from winnt.h @@ -135,7 +135,7 @@ reed_solomon_decode_t reed_solomon_decode_fn; * @details The streaming code will directly invoke these function pointers during encoding. */ void reed_solomon_init(void) { -#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64)) +#if defined(_MSC_VER) && !defined(NXDK) && (defined(_M_IX86) || defined(_M_AMD64)) // Visual Studio if (_msc_supports_avx512f()) { reed_solomon_new_fn = reed_solomon_new_avx512;