Add platform support for the 3DS

Prevent wildcard port binding on the 3DS
Add 3DS threading logic
Add 3DS socket logic
Bump the connection timeout to 60s for the 3DS
This commit is contained in:
zoey jodon 2024-01-16 10:41:00 -05:00 committed by Cameron Gutman
parent 2597b5e779
commit c104a97fa0
6 changed files with 125 additions and 26 deletions

View File

@ -1646,7 +1646,12 @@ int startControlStream(void) {
LC_ASSERT(ControlPortNumber != 0); LC_ASSERT(ControlPortNumber != 0);
enet_address_set_address(&localAddress, (struct sockaddr *)&LocalAddr, AddrLen); enet_address_set_address(&localAddress, (struct sockaddr *)&LocalAddr, AddrLen);
#ifdef __3DS__
// binding to wildcard port is broken on the 3DS, so we need to define a port manually
enet_address_set_port(&localAddress, htons(n3ds_udp_port++));
#else
enet_address_set_port(&localAddress, 0); // Wildcard port enet_address_set_port(&localAddress, 0); // Wildcard port
#endif
enet_address_set_address(&remoteAddress, (struct sockaddr *)&RemoteAddr, AddrLen); enet_address_set_address(&remoteAddress, (struct sockaddr *)&RemoteAddr, AddrLen);
enet_address_set_port(&remoteAddress, ControlPortNumber); enet_address_set_port(&remoteAddress, ControlPortNumber);
@ -1712,8 +1717,14 @@ int startControlStream(void) {
// Ensure the connect verify ACK is sent immediately // Ensure the connect verify ACK is sent immediately
enet_host_flush(client); enet_host_flush(client);
#ifdef __3DS__
// Set the peer timeout to 1 minute and limit backoff to 2x RTT
// The 3DS can take a bit longer to set up when starting fresh
enet_peer_timeout(peer, 2, 60000, 60000);
#else
// Set the peer timeout to 10 seconds and limit backoff to 2x RTT // Set the peer timeout to 10 seconds and limit backoff to 2x RTT
enet_peer_timeout(peer, 2, 10000, 10000); enet_peer_timeout(peer, 2, 10000, 10000);
#endif
} }
else { else {
// NB: Do NOT use ControlPortNumber here. 47995 is correct for these old versions. // NB: Do NOT use ControlPortNumber here. 47995 is correct for these old versions.

View File

@ -93,7 +93,7 @@ void* ThreadProc(void* context) {
free(ctx); free(ctx);
#endif #endif
#if defined(LC_WINDOWS) || defined(__vita__) || defined(__WIIU__) #if defined(LC_WINDOWS) || defined(__vita__) || defined(__WIIU__) || defined(__3DS__)
return 0; return 0;
#else #else
return NULL; return NULL;
@ -105,6 +105,9 @@ void PltSleepMs(int ms) {
SleepEx(ms, FALSE); SleepEx(ms, FALSE);
#elif defined(__vita__) #elif defined(__vita__)
sceKernelDelayThread(ms * 1000); sceKernelDelayThread(ms * 1000);
#elif defined(__3DS__)
s64 nsecs = ms * 1000000;
svcSleepThread(nsecs);
#else #else
useconds_t usecs = ms * 1000; useconds_t usecs = ms * 1000;
usleep(usecs); usleep(usecs);
@ -129,6 +132,8 @@ int PltCreateMutex(PLT_MUTEX* mutex) {
} }
#elif defined(__WIIU__) #elif defined(__WIIU__)
OSFastMutex_Init(mutex, ""); OSFastMutex_Init(mutex, "");
#elif defined(__3DS__)
LightLock_Init(mutex);
#else #else
int err = pthread_mutex_init(mutex, NULL); int err = pthread_mutex_init(mutex, NULL);
if (err != 0) { if (err != 0) {
@ -145,7 +150,7 @@ void PltDeleteMutex(PLT_MUTEX* mutex) {
// No-op to destroy a SRWLOCK // No-op to destroy a SRWLOCK
#elif defined(__vita__) #elif defined(__vita__)
sceKernelDeleteMutex(*mutex); sceKernelDeleteMutex(*mutex);
#elif defined(__WIIU__) #elif defined(__WIIU__) || defined(__3DS__)
#else #else
pthread_mutex_destroy(mutex); pthread_mutex_destroy(mutex);
@ -159,6 +164,8 @@ void PltLockMutex(PLT_MUTEX* mutex) {
sceKernelLockMutex(*mutex, 1, NULL); sceKernelLockMutex(*mutex, 1, NULL);
#elif defined(__WIIU__) #elif defined(__WIIU__)
OSFastMutex_Lock(mutex); OSFastMutex_Lock(mutex);
#elif defined(__3DS__)
LightLock_Lock(mutex);
#else #else
pthread_mutex_lock(mutex); pthread_mutex_lock(mutex);
#endif #endif
@ -171,6 +178,8 @@ void PltUnlockMutex(PLT_MUTEX* mutex) {
sceKernelUnlockMutex(*mutex, 1); sceKernelUnlockMutex(*mutex, 1);
#elif defined(__WIIU__) #elif defined(__WIIU__)
OSFastMutex_Unlock(mutex); OSFastMutex_Unlock(mutex);
#elif defined(__3DS__)
LightLock_Unlock(mutex);
#else #else
pthread_mutex_unlock(mutex); pthread_mutex_unlock(mutex);
#endif #endif
@ -187,6 +196,9 @@ void PltJoinThread(PLT_THREAD* thread) {
free(thread->context); free(thread->context);
#elif defined(__WIIU__) #elif defined(__WIIU__)
OSJoinThread(&thread->thread, NULL); OSJoinThread(&thread->thread, NULL);
#elif defined(__3DS__)
threadJoin(thread->thread, U64_MAX);
threadFree(thread->thread);
#else #else
pthread_join(thread->thread, NULL); pthread_join(thread->thread, NULL);
#endif #endif
@ -265,6 +277,22 @@ int PltCreateThread(const char* name, ThreadEntry entry, void* context, PLT_THRE
OSSetThreadDeallocator(&thread->thread, thread_deallocator); OSSetThreadDeallocator(&thread->thread, thread_deallocator);
OSResumeThread(&thread->thread); OSResumeThread(&thread->thread);
#elif defined(__3DS__)
{
s32 priority = 0x30;
size_t stack_size = 1024 * 1024;
svcGetThreadPriority(&priority, CUR_THREAD_HANDLE);
thread->thread = threadCreate(ThreadProc,
ctx,
stack_size,
priority,
-1,
false);
if (thread->thread == NULL) {
free(ctx);
return -1;
}
}
#else #else
{ {
int err = pthread_create(&thread->thread, NULL, ThreadProc, ctx); int err = pthread_create(&thread->thread, NULL, ThreadProc, ctx);
@ -351,6 +379,8 @@ int PltCreateConditionVariable(PLT_COND* cond, PLT_MUTEX* mutex) {
} }
#elif defined(__WIIU__) #elif defined(__WIIU__)
OSFastCond_Init(cond, ""); OSFastCond_Init(cond, "");
#elif defined(__3DS__)
CondVar_Init(cond);
#else #else
pthread_cond_init(cond, NULL); pthread_cond_init(cond, NULL);
#endif #endif
@ -364,6 +394,8 @@ void PltDeleteConditionVariable(PLT_COND* cond) {
sceKernelDeleteCond(*cond); sceKernelDeleteCond(*cond);
#elif defined(__WIIU__) #elif defined(__WIIU__)
// No-op to delete an OSFastCondition // No-op to delete an OSFastCondition
#elif defined(__3DS__)
// No-op to delete CondVar
#else #else
pthread_cond_destroy(cond); pthread_cond_destroy(cond);
#endif #endif
@ -376,6 +408,8 @@ void PltSignalConditionVariable(PLT_COND* cond) {
sceKernelSignalCond(*cond); sceKernelSignalCond(*cond);
#elif defined(__WIIU__) #elif defined(__WIIU__)
OSFastCond_Signal(cond); OSFastCond_Signal(cond);
#elif defined(__3DS__)
CondVar_Signal(cond);
#else #else
pthread_cond_signal(cond); pthread_cond_signal(cond);
#endif #endif
@ -388,6 +422,8 @@ void PltWaitForConditionVariable(PLT_COND* cond, PLT_MUTEX* mutex) {
sceKernelWaitCond(*cond, NULL); sceKernelWaitCond(*cond, NULL);
#elif defined(__WIIU__) #elif defined(__WIIU__)
OSFastCond_Wait(cond, mutex); OSFastCond_Wait(cond, mutex);
#elif defined(__3DS__)
CondVar_Wait(cond, mutex);
#else #else
pthread_cond_wait(cond, mutex); pthread_cond_wait(cond, mutex);
#endif #endif

View File

@ -32,6 +32,9 @@
#include <coreinit/fastmutex.h> #include <coreinit/fastmutex.h>
#include <coreinit/fastcondition.h> #include <coreinit/fastcondition.h>
#include <fcntl.h> #include <fcntl.h>
#elif defined(__3DS__)
#include <3ds.h>
#include <fcntl.h>
#else #else
#include <unistd.h> #include <unistd.h>
#include <pthread.h> #include <pthread.h>

View File

@ -35,6 +35,10 @@ DWORD (WINAPI *pfnWlanSetInterface)(HANDLE hClientHandle, CONST GUID *pInterface
#endif #endif
#ifdef __3DS__
in_port_t n3ds_udp_port = 47998;
#endif
void addrToUrlSafeString(struct sockaddr_storage* addr, char* string, size_t stringLength) void addrToUrlSafeString(struct sockaddr_storage* addr, char* string, size_t stringLength)
{ {
char addrstr[URLSAFESTRING_LEN]; char addrstr[URLSAFESTRING_LEN];
@ -74,8 +78,8 @@ int setNonFatalRecvTimeoutMs(SOCKET s, int timeoutMs) {
// losing some data in a very rare case is fine, especially because we get to // losing some data in a very rare case is fine, especially because we get to
// halve the number of syscalls per packet by avoiding select(). // halve the number of syscalls per packet by avoiding select().
return setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeoutMs, sizeof(timeoutMs)); return setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeoutMs, sizeof(timeoutMs));
#elif defined(__WIIU__) #elif defined(__WIIU__) || defined(__3DS__)
// timeouts aren't supported on Wii U // timeouts aren't supported on Wii U or 3DS
return -1; return -1;
#else #else
struct timeval val; struct timeval val;
@ -142,6 +146,15 @@ int pollSockets(struct pollfd* pollFds, int pollFdsCount, int timeoutMs) {
} }
} }
return err;
#elif defined(__3DS__)
int err;
for (int i = 0; i < timeoutMs; i++) {
err = poll(pollFds, pollFdsCount, 1); // need to do this on 3ds since poll will block even if socket is ready before
if (err) {
break;
}
}
return err; return err;
#else #else
return poll(pollFds, pollFdsCount, timeoutMs); return poll(pollFds, pollFdsCount, timeoutMs);
@ -251,6 +264,11 @@ SOCKET bindUdpSocket(int addressFamily, struct sockaddr_storage* localAddr, SOCK
#endif #endif
} }
#ifdef __3DS__
// binding to wildcard port is broken on the 3DS, so we need to define a port manually
struct sockaddr_in *n3ds_addr = &bindAddr;
n3ds_addr->sin_port = htons(n3ds_udp_port++);
#endif
if (bind(s, (struct sockaddr*) &bindAddr, addrLen) == SOCKET_ERROR) { if (bind(s, (struct sockaddr*) &bindAddr, addrLen) == SOCKET_ERROR) {
err = LastSocketError(); err = LastSocketError();
Limelog("bind() failed: %d\n", err); Limelog("bind() failed: %d\n", err);
@ -353,6 +371,9 @@ SOCKET createSocket(int addressFamily, int socketType, int protocol, bool nonBlo
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (char*)&val, sizeof(val)); setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (char*)&val, sizeof(val));
} }
#endif #endif
#ifdef __3DS__
SOCU_AddGlobalSocket(s);
#endif
if (nonBlocking) { if (nonBlocking) {
setSocketNonBlocking(s, true); setSocketNonBlocking(s, true);
@ -446,6 +467,17 @@ SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen,
SetLastSocketError(ETIMEDOUT); SetLastSocketError(ETIMEDOUT);
return INVALID_SOCKET; return INVALID_SOCKET;
} }
#ifdef __3DS__ //SO_ERROR is unreliable on 3DS
else {
char test_buffer[1];
err = (int)recv(s, test_buffer, 1, MSG_PEEK);
if (err < 0 &&
(LastSocketError() == EWOULDBLOCK ||
LastSocketError() == EAGAIN)) {
err = 0;
}
}
#else
else { else {
// The socket was signalled // The socket was signalled
SOCKADDR_LEN len = sizeof(err); SOCKADDR_LEN len = sizeof(err);
@ -455,6 +487,7 @@ SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen,
err = (err != 0) ? err : LastSocketFail(); err = (err != 0) ? err : LastSocketFail();
} }
} }
#endif
// Disable non-blocking I/O now that the connection is established // Disable non-blocking I/O now that the connection is established
setSocketNonBlocking(s, false); setSocketNonBlocking(s, false);
@ -723,7 +756,7 @@ int initializePlatformSockets(void) {
#if defined(LC_WINDOWS) #if defined(LC_WINDOWS)
WSADATA data; WSADATA data;
return WSAStartup(MAKEWORD(2, 0), &data); return WSAStartup(MAKEWORD(2, 0), &data);
#elif defined(__vita__) || defined(__WIIU__) #elif defined(__vita__) || defined(__WIIU__) || defined(__3DS__)
return 0; // already initialized return 0; // already initialized
#elif defined(LC_POSIX) && !defined(LC_CHROME) #elif defined(LC_POSIX) && !defined(LC_CHROME)
// Disable SIGPIPE signals to avoid us getting // Disable SIGPIPE signals to avoid us getting

View File

@ -2,6 +2,15 @@
#include "Limelight.h" #include "Limelight.h"
#include "Platform.h" #include "Platform.h"
#ifdef __3DS__
#include <netinet/in.h>
#ifdef AF_INET6
#undef AF_INET6
#endif
extern in_port_t n3ds_udp_port;
#endif
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN

View File

@ -28,6 +28,13 @@ typedef struct _PLT_THREAD {
OSThread thread; OSThread thread;
int cancelled; int cancelled;
} PLT_THREAD; } PLT_THREAD;
#elif defined(__3DS__)
typedef LightLock PLT_MUTEX;
typedef CondVar PLT_COND;
typedef struct _PLT_THREAD {
Thread thread;
bool cancelled;
} PLT_THREAD;
#elif defined (LC_POSIX) #elif defined (LC_POSIX)
typedef pthread_mutex_t PLT_MUTEX; typedef pthread_mutex_t PLT_MUTEX;
typedef pthread_cond_t PLT_COND; typedef pthread_cond_t PLT_COND;