Add NXDK (Xbox) support

This commit is contained in:
ReenigneArcher
2026-04-04 22:38:08 -04:00
committed by Cameron Gutman
parent 2600beaf13
commit 40d87314d0
7 changed files with 65 additions and 42 deletions
+1 -1
Submodule enet updated: c7353c0593...0eb84dcca8
+1 -1
View File
@@ -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++) { for (unsigned idx = 0, p = 0; idx < k; idx += 8 * sizeof(u32), p++) {
u32 tmp = b[p]; u32 tmp = b[p];
while (tmp > 0) { while (tmp > 0) {
#ifdef _MSC_VER #if defined(_MSC_VER) && !defined(__clang__)
unsigned long index = 0; unsigned long index = 0;
_BitScanForward(&index, tmp); _BitScanForward(&index, tmp);
unsigned tz = (unsigned int)index; unsigned tz = (unsigned int)index;
+7 -5
View File
@@ -20,7 +20,7 @@ static int activeMutexes = 0;
static int activeEvents = 0; static int activeEvents = 0;
static int activeCondVars = 0; static int activeCondVars = 0;
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(NXDK)
#pragma pack(push, 8) #pragma pack(push, 8)
typedef struct tagTHREADNAME_INFO typedef struct tagTHREADNAME_INFO
@@ -65,7 +65,9 @@ void setThreadNameWin32(const char* name) {
} }
#endif #endif
} }
#endif
#if defined(LC_WINDOWS)
DWORD WINAPI ThreadProc(LPVOID lpParameter) { DWORD WINAPI ThreadProc(LPVOID lpParameter) {
struct thread_context* ctx = (struct thread_context*)lpParameter; struct thread_context* ctx = (struct thread_context*)lpParameter;
#elif defined(__WIIU__) #elif defined(__WIIU__)
@@ -76,7 +78,7 @@ void* ThreadProc(void* context) {
struct thread_context* ctx = (struct thread_context*)context; struct thread_context* ctx = (struct thread_context*)context;
#endif #endif
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(NXDK)
setThreadNameWin32(ctx->name); setThreadNameWin32(ctx->name);
#elif defined(__linux__) || defined(__FreeBSD__) #elif defined(__linux__) || defined(__FreeBSD__)
pthread_setname_np(pthread_self(), ctx->name); pthread_setname_np(pthread_self(), ctx->name);
@@ -298,7 +300,7 @@ int PltCreateThread(const char* name, ThreadEntry entry, void* context, PLT_THRE
free(ctx); free(ctx);
return err; return err;
} }
} }
#endif #endif
@@ -309,7 +311,7 @@ int PltCreateThread(const char* name, ThreadEntry entry, void* context, PLT_THRE
int PltCreateEvent(PLT_EVENT* event) { int PltCreateEvent(PLT_EVENT* event) {
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS)
*event = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); *event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!*event) { if (!*event) {
return -1; return -1;
} }
@@ -578,7 +580,7 @@ bool PltSafeStrcpy(char* dest, size_t dest_size, const char* src) {
memset(dest, 0xFE, dest_size); memset(dest, 0xFE, dest_size);
#endif #endif
#ifdef _MSC_VER #if defined(_MSC_VER) && !defined(NXDK)
// strncpy_s() with _TRUNCATE does what we need for MSVC. // strncpy_s() with _TRUNCATE does what we need for MSVC.
// We use this rather than strcpy_s() because we don't want // We use this rather than strcpy_s() because we don't want
// the invalid parameter handler invoked upon failure. // the invalid parameter handler invoked upon failure.
+34 -17
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
#ifdef _WIN32 #if defined(_WIN32) && !defined(NXDK)
// Prevent bogus definitions of error codes // Prevent bogus definitions of error codes
// that are incompatible with Winsock errors. // that are incompatible with Winsock errors.
#define _CRT_NO_POSIX_ERROR_CODES #define _CRT_NO_POSIX_ERROR_CODES
@@ -13,11 +13,23 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#ifdef _WIN32 #if defined(_WIN32) && !defined(NXDK)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#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 <windows.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#elif defined(__APPLE__) #elif defined(__APPLE__)
#include <mach/mach_time.h> #include <mach/mach_time.h>
#include <unistd.h> #include <unistd.h>
@@ -64,15 +76,19 @@
#endif #endif
#ifdef LC_WINDOWS #ifdef LC_WINDOWS
# if !defined(NXDK)
// Windows doesn't have strtok_r() but it has the same // Windows doesn't have strtok_r() but it has the same
// function named strtok_s(). // function named strtok_s().
#define strtok_r strtok_s #define strtok_r strtok_s
# endif
# if defined(WINAPI_FAMILY) && WINAPI_FAMILY==WINAPI_FAMILY_APP # if !defined(NXDK)
# define LC_UWP # if defined(WINAPI_FAMILY) && WINAPI_FAMILY==WINAPI_FAMILY_APP
# else # define LC_UWP
# define LC_WINDOWS_DESKTOP # else
#endif # define LC_WINDOWS_DESKTOP
# endif
# endif
#endif #endif
@@ -83,7 +99,7 @@
if (ListenerCallbacks.logMessage) \ if (ListenerCallbacks.logMessage) \
ListenerCallbacks.logMessage(s, ##__VA_ARGS__) ListenerCallbacks.logMessage(s, ##__VA_ARGS__)
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(__clang__)
#include <crtdbg.h> #include <crtdbg.h>
#ifdef LC_DEBUG #ifdef LC_DEBUG
#define LC_ASSERT(x) __analysis_assume(x); \ #define LC_ASSERT(x) __analysis_assume(x); \
@@ -116,21 +132,22 @@
#define LC_ASSERT_VT(x) LC_ASSERT(x) #define LC_ASSERT_VT(x) LC_ASSERT(x)
#endif #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) #pragma intrinsic(_byteswap_ushort)
#define BSWAP16(x) _byteswap_ushort(x) #define BSWAP16(x) _byteswap_ushort(x)
#pragma intrinsic(_byteswap_ulong) #pragma intrinsic(_byteswap_ulong)
#define BSWAP32(x) _byteswap_ulong(x) #define BSWAP32(x) _byteswap_ulong(x)
#pragma intrinsic(_byteswap_uint64) #pragma intrinsic(_byteswap_uint64)
#define BSWAP64(x) _byteswap_uint64(x) #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 #else
#error Please define your platform byteswap macros! #error Please define your platform byteswap macros!
#endif #endif
+17 -15
View File
@@ -12,7 +12,7 @@
#endif #endif
#define TCPv6_MSS 1220 #define TCPv6_MSS 1220
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(NXDK)
#ifndef SIO_UDP_CONNRESET #ifndef SIO_UDP_CONNRESET
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12) #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
@@ -70,7 +70,7 @@ void shutdownTcpSocket(SOCKET s) {
} }
int setNonFatalRecvTimeoutMs(SOCKET s, int timeoutMs) { 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 // 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 // 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 // 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) { 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 // We could have used WSAPoll() but it has some nasty bugs
// https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/ // 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() == EWOULDBLOCK ||
LastSocketError() == EINTR || LastSocketError() == EINTR ||
LastSocketError() == EAGAIN || LastSocketError() == EAGAIN ||
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(NXDK)
// This error is specific to overlapped I/O which isn't even // This error is specific to overlapped I/O which isn't even
// possible to perform with recvfrom(). It seems to randomly // possible to perform with recvfrom(). It seems to randomly
// be returned instead of WSAETIMEDOUT on certain systems. // 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 // 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 // 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. // 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); } while (err < 0 && LastSocketError() == WSAECONNRESET);
#else #else
} while (err < 0 && LastSocketError() == ECONNREFUSED); } while (err < 0 && LastSocketError() == ECONNREFUSED);
@@ -231,7 +231,7 @@ int recvUdpSocket(SOCKET s, char* buffer, int size, bool useSelect) {
} }
void closeSocket(SOCKET s) { void closeSocket(SOCKET s) {
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(NXDK)
closesocket(s); closesocket(s);
#else #else
close(s); close(s);
@@ -335,7 +335,7 @@ SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCK
int val = 1; int val = 1;
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (char*)&val, sizeof(val)); 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 // Disable WSAECONNRESET for UDP sockets on Windows
BOOL val = FALSE; BOOL val = FALSE;
@@ -409,10 +409,10 @@ int setSocketNonBlocking(SOCKET s, bool enabled) {
#if defined(__vita__) || defined(__HAIKU__) #if defined(__vita__) || defined(__HAIKU__)
int val = enabled ? 1 : 0; int val = enabled ? 1 : 0;
return setsockopt(s, SOL_SOCKET, SO_NONBLOCK, (char*)&val, sizeof(val)); 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)); return fcntl(s, F_SETFL, (enabled ? O_NONBLOCK : 0) | (fcntl(s, F_GETFL) & ~O_NONBLOCK));
#elif defined(FIONBIO) #elif defined(FIONBIO)
#ifdef LC_WINDOWS #if defined(LC_WINDOWS) && !defined(NXDK)
u_long val = enabled ? 1 : 0; u_long val = enabled ? 1 : 0;
#else #else
int val = enabled ? 1 : 0; int val = enabled ? 1 : 0;
@@ -452,7 +452,6 @@ SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen,
LC_SOCKADDR addr; LC_SOCKADDR addr;
struct pollfd pfd; struct pollfd pfd;
int err; int err;
int val;
// Create a non-blocking TCP socket // Create a non-blocking TCP socket
s = createSocket(dstaddr->ss_family, SOCK_STREAM, IPPROTO_TCP, true); 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. // 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 // 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. // 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 // 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). // minimum which is what we want here. Linux doesn't do this (disabling PMTUD just avoids setting DF).
if (dstaddr->ss_family == AF_INET) { 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 // 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 // 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. // 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) { if (setsockopt(s, IPPROTO_TCP, TCP_NOOPT, (char*)&val, sizeof(val)) < 0) {
Limelog("setsockopt(TCP_NOOPT, %d) failed: %d\n", val, (int)LastSocketError()); Limelog("setsockopt(TCP_NOOPT, %d) failed: %d\n", val, (int)LastSocketError());
} }
#elif defined(TCP_MAXSEG) #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) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, (char*)&val, sizeof(val)) < 0) {
Limelog("setsockopt(TCP_MAXSEG, %d) failed: %d\n", val, (int)LastSocketError()); Limelog("setsockopt(TCP_MAXSEG, %d) failed: %d\n", val, (int)LastSocketError());
} }
@@ -1004,7 +1006,7 @@ void exitLowLatencyMode(void) {
} }
int initializePlatformSockets(void) { int initializePlatformSockets(void) {
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(NXDK)
WSADATA data; WSADATA data;
return WSAStartup(MAKEWORD(2, 0), &data); return WSAStartup(MAKEWORD(2, 0), &data);
#elif defined(__vita__) || defined(__WIIU__) || defined(__3DS__) #elif defined(__vita__) || defined(__WIIU__) || defined(__3DS__)
@@ -1027,7 +1029,7 @@ int initializePlatformSockets(void) {
} }
void cleanupPlatformSockets(void) { void cleanupPlatformSockets(void) {
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS) && !defined(NXDK)
WSACleanup(); WSACleanup();
#else #else
#endif #endif
+3 -1
View File
@@ -18,7 +18,7 @@ extern in_port_t n3ds_udp_port;
#endif #endif
#endif #endif
#ifdef _WIN32 #if defined(_WIN32) && !defined(NXDK)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <wlanapi.h> #include <wlanapi.h>
@@ -83,7 +83,9 @@ typedef int SOCKADDR_LEN;
#include <signal.h> #include <signal.h>
#include <poll.h> #include <poll.h>
#ifndef ioctlsocket
#define ioctlsocket ioctl #define ioctlsocket ioctl
#endif
#define LastSocketError() errno #define LastSocketError() errno
#define SetLastSocketError(x) errno = x #define SetLastSocketError(x) errno = x
#define INVALID_SOCKET -1 #define INVALID_SOCKET -1
+2 -2
View File
@@ -117,7 +117,7 @@ reed_solomon_release_t reed_solomon_release_fn;
reed_solomon_encode_t reed_solomon_encode_fn; reed_solomon_encode_t reed_solomon_encode_fn;
reed_solomon_decode_t reed_solomon_decode_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) #if defined(_M_AMD64)
// For some reason this is needed to avoid a "C1189 No target architecture" error from winnt.h // 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. * @details The streaming code will directly invoke these function pointers during encoding.
*/ */
void reed_solomon_init(void) { 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 // Visual Studio
if (_msc_supports_avx512f()) { if (_msc_supports_avx512f()) {
reed_solomon_new_fn = reed_solomon_new_avx512; reed_solomon_new_fn = reed_solomon_new_avx512;