merge local_wifi (#1516)

* attempt at betterer wifi

* add preliminary sync mechanism
* fix gaps in wifi implementation

* move local-MP comm to its own module instead of cramping Platform.cpp

* remove some stupid cruft

* as you wish, Sorer

(starting work on shared-memory system)

* shared-memory IPC that actually works (albeit Windows-only for now)

* shut up logging from NULL writes on ARM7 (ffs Nintendo learn to code)

* get this somewhat good

* leave client sync mode when host deauths. makes download play actually work.

* start implementing MP-comm error handling

* * add MP-reply error counters
* feeble attempt at fixing slowdown/desync/etc problems

* somewhat better exchange/sync method

* * when entering power-saving mode, be sure to finish transferring the current frame first
* fix misc bug due to old cruft leftover

makes for a more stable connection

* remove a bunch of cruft

* set wifi time interval to 34 cycles instead of 33. games seem sensitive to the general timing of wifi vs the rest of the system, and this seems to make things run better, atleast until I rewrite this to use a proper scheduler.

* more graceful handling of disconnects

* deal with FIFO overflow more gracefully

* BAHAHAHAHAHAHAHAHHHH

THE SNEAKY BASTARDS

so, when the DS receives a beacon with the right BSSID

that beacon's timestamp is copied to USCOUNTER

* attempt at making the connection process smoother for weird games

* * begin adding POWCNT2, only applies to wifi for now
* begin work on wifi scheduler

* implement the shitty timers

* add the RF wakeup thing

* begin work on receiving frames. for now it can just receive melonAP beacons, but hey, it's a start.

* add enough TX functionality that online wifi is a possibility again.

* there are problems with this scheduler thing. committing it anyway

* kind of a rollback... we're gonna work out a compromise on this, I guess

* don't transmit shit if RXCNT.bit15 isn't set

* move RX-finish to its own function. more accurate filtering. implement RXFILTER.

* remove some cruft

* fix some of the shittiness when trying to connect more than two players

* fix some more shittiness

* fix more wifi shittiness (mainly don't try to receive shit while sending a frame)

* run wifi every 8µs. improves performance.

* fix IRQ14/IRQ15

* make this work under Linux

* Make it work on macOS, for now using a custom sem_timedwait
implementation.

If anyone knows anything about mach ports and have an idea for how to
make this work using mach IPC, please do let me know.

* 25ms seems like a good timeout

* begin work on proper multiplayer UI shito.

for now, determine a global instance ID, and derivate the system MAC from it. remove 'randomize MAC' option.

* finish removing RandomizeMAC

* lay groundwork for instance-unique config

* work some on the UI... make it not labelled Fart

* more UI work: make it explicit that some things are instance-unique

* separate firmware files for multiplayer instances

* make instances save to different save files, too

* more UI work, make things somewhat less shitty

* lay base for the multiplayer settings dialog

* actually hook up most of that dialog

* actually implement the fun audio settings

* ensure all the wifi shit is properly savestated and reset. properly update timings for the wifi region when wifi is disabled.

* add more fun labels

* * ignore WEP frames if WEP is off
* implement RX_LEN_CROP

* fake enough of WEP processing to make Inazuma Eleven work

* * do not copy more ROM banner data than actually needed
* avoid trying to read out of bounds if the banner offset is bad

* Fix oversight with the preferences action causing the build to fail on macOS

Co-authored-by: Nadia Holmquist Pedersen <nadia@nhp.sh>
This commit is contained in:
Arisotura
2022-09-22 20:32:27 +02:00
committed by GitHub
parent b5073e6014
commit b1e4bd5520
39 changed files with 3468 additions and 1068 deletions

View File

@ -20,28 +20,7 @@
#include <stdlib.h>
#include <string.h>
#ifdef __WIN32__
#define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK
#include <winsock2.h>
#include <windows.h>
//#include <knownfolders.h> // FUCK THAT SHIT
#include <shlobj.h>
#include <ws2tcpip.h>
#include <io.h>
#define dup _dup
#define socket_t SOCKET
#define sockaddr_t SOCKADDR
#else
#include <unistd.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#define socket_t int
#define sockaddr_t struct sockaddr
#define closesocket close
#endif
#include <string>
#include <QStandardPaths>
#include <QString>
#include <QDir>
@ -49,32 +28,80 @@
#include <QSemaphore>
#include <QMutex>
#include <QOpenGLContext>
#include <QSharedMemory>
#include "Platform.h"
#include "Config.h"
#include "ROMManager.h"
#include "LAN_Socket.h"
#include "LAN_PCap.h"
#include <string>
#ifndef INVALID_SOCKET
#define INVALID_SOCKET (socket_t)-1
#endif
#include "LocalMP.h"
std::string EmuDirectory;
void emuStop();
namespace Platform
{
socket_t MPSocket;
sockaddr_t MPSendAddr;
u8 PacketBuffer[2048];
QSharedMemory* IPCBuffer = nullptr;
int IPCInstanceID;
#define NIFI_VER 1
void IPCInit()
{
IPCInstanceID = 0;
IPCBuffer = new QSharedMemory("melonIPC");
if (!IPCBuffer->attach())
{
printf("IPC sharedmem doesn't exist. creating\n");
if (!IPCBuffer->create(1024))
{
printf("IPC sharedmem create failed :(\n");
delete IPCBuffer;
IPCBuffer = nullptr;
return;
}
IPCBuffer->lock();
memset(IPCBuffer->data(), 0, IPCBuffer->size());
IPCBuffer->unlock();
}
IPCBuffer->lock();
u8* data = (u8*)IPCBuffer->data();
u16 mask = *(u16*)&data[0];
for (int i = 0; i < 16; i++)
{
if (!(mask & (1<<i)))
{
IPCInstanceID = i;
*(u16*)&data[0] |= (1<<i);
break;
}
}
IPCBuffer->unlock();
printf("IPC: instance ID %d\n", IPCInstanceID);
}
void IPCDeInit()
{
if (IPCBuffer)
{
IPCBuffer->lock();
u8* data = (u8*)IPCBuffer->data();
*(u16*)&data[0] &= ~(1<<IPCInstanceID);
IPCBuffer->unlock();
IPCBuffer->detach();
delete IPCBuffer;
}
IPCBuffer = nullptr;
}
void Init(int argc, char** argv)
@ -110,10 +137,13 @@ void Init(int argc, char** argv)
confdir = config.absolutePath() + "/melonDS/";
EmuDirectory = confdir.toStdString();
#endif
IPCInit();
}
void DeInit()
{
IPCDeInit();
}
@ -123,6 +153,22 @@ void StopEmu()
}
int InstanceID()
{
return IPCInstanceID;
}
std::string InstanceFileSuffix()
{
int inst = IPCInstanceID;
if (inst == 0) return "";
char suffix[16] = {0};
snprintf(suffix, 15, ".%d", inst+1);
return suffix;
}
int GetConfigInt(ConfigEntry entry)
{
const int imgsizes[] = {0, 256, 512, 1024, 2048, 4096};
@ -169,7 +215,6 @@ bool GetConfigBool(ConfigEntry entry)
case DSiSD_ReadOnly: return Config::DSiSDReadOnly != 0;
case DSiSD_FolderSync: return Config::DSiSDFolderSync != 0;
case Firm_RandomizeMAC: return Config::RandomizeMAC != 0;
case Firm_OverrideSettings: return Config::FirmwareOverrideSettings != 0;
}
@ -372,6 +417,11 @@ bool Mutex_TryLock(Mutex* mutex)
return ((QMutex*) mutex)->try_lock();
}
void Sleep(u64 usecs)
{
QThread::usleep(usecs);
}
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
{
@ -386,146 +436,60 @@ void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen
}
bool MP_Init()
{
int opt_true = 1;
int res;
#ifdef __WIN32__
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
{
return false;
}
#endif // __WIN32__
MPSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (MPSocket < 0)
{
return false;
}
res = setsockopt(MPSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt_true, sizeof(int));
if (res < 0)
{
closesocket(MPSocket);
MPSocket = INVALID_SOCKET;
return false;
}
#if defined(BSD) || defined(__APPLE__)
res = setsockopt(MPSocket, SOL_SOCKET, SO_REUSEPORT, (const char*)&opt_true, sizeof(int));
if (res < 0)
{
closesocket(MPSocket);
MPSocket = INVALID_SOCKET;
return false;
}
#endif
sockaddr_t saddr;
saddr.sa_family = AF_INET;
*(u32*)&saddr.sa_data[2] = htonl(Config::SocketBindAnyAddr ? INADDR_ANY : INADDR_LOOPBACK);
*(u16*)&saddr.sa_data[0] = htons(7064);
res = bind(MPSocket, &saddr, sizeof(sockaddr_t));
if (res < 0)
{
closesocket(MPSocket);
MPSocket = INVALID_SOCKET;
return false;
}
res = setsockopt(MPSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&opt_true, sizeof(int));
if (res < 0)
{
closesocket(MPSocket);
MPSocket = INVALID_SOCKET;
return false;
}
MPSendAddr.sa_family = AF_INET;
*(u32*)&MPSendAddr.sa_data[2] = htonl(INADDR_BROADCAST);
*(u16*)&MPSendAddr.sa_data[0] = htons(7064);
return true;
return LocalMP::Init();
}
void MP_DeInit()
{
if (MPSocket >= 0)
closesocket(MPSocket);
#ifdef __WIN32__
WSACleanup();
#endif // __WIN32__
return LocalMP::DeInit();
}
int MP_SendPacket(u8* data, int len)
void MP_Begin()
{
if (MPSocket < 0)
return 0;
if (len > 2048-8)
{
printf("MP_SendPacket: error: packet too long (%d)\n", len);
return 0;
}
*(u32*)&PacketBuffer[0] = htonl(0x4946494E); // NIFI
PacketBuffer[4] = NIFI_VER;
PacketBuffer[5] = 0;
*(u16*)&PacketBuffer[6] = htons(len);
memcpy(&PacketBuffer[8], data, len);
int slen = sendto(MPSocket, (const char*)PacketBuffer, len+8, 0, &MPSendAddr, sizeof(sockaddr_t));
if (slen < 8) return 0;
return slen - 8;
return LocalMP::Begin();
}
int MP_RecvPacket(u8* data, bool block)
void MP_End()
{
if (MPSocket < 0)
return 0;
return LocalMP::End();
}
fd_set fd;
struct timeval tv;
int MP_SendPacket(u8* data, int len, u64 timestamp)
{
return LocalMP::SendPacket(data, len, timestamp);
}
FD_ZERO(&fd);
FD_SET(MPSocket, &fd);
tv.tv_sec = 0;
tv.tv_usec = block ? 5000 : 0;
int MP_RecvPacket(u8* data, u64* timestamp)
{
return LocalMP::RecvPacket(data, timestamp);
}
if (!select(MPSocket+1, &fd, 0, 0, &tv))
{
return 0;
}
int MP_SendCmd(u8* data, int len, u64 timestamp)
{
return LocalMP::SendCmd(data, len, timestamp);
}
sockaddr_t fromAddr;
socklen_t fromLen = sizeof(sockaddr_t);
int rlen = recvfrom(MPSocket, (char*)PacketBuffer, 2048, 0, &fromAddr, &fromLen);
if (rlen < 8+24)
{
return 0;
}
rlen -= 8;
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid)
{
return LocalMP::SendReply(data, len, timestamp, aid);
}
if (ntohl(*(u32*)&PacketBuffer[0]) != 0x4946494E)
{
return 0;
}
int MP_SendAck(u8* data, int len, u64 timestamp)
{
return LocalMP::SendAck(data, len, timestamp);
}
if (PacketBuffer[4] != NIFI_VER)
{
return 0;
}
int MP_RecvHostPacket(u8* data, u64* timestamp)
{
return LocalMP::RecvHostPacket(data, timestamp);
}
if (ntohs(*(u16*)&PacketBuffer[6]) != rlen)
{
return 0;
}
memcpy(data, &PacketBuffer[8], rlen);
return rlen;
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask)
{
return LocalMP::RecvReplies(data, timestamp, aidmask);
}
@ -573,9 +537,4 @@ int LAN_RecvPacket(u8* data)
return LAN_Socket::RecvPacket(data);
}
void Sleep(u64 usecs)
{
QThread::usleep(usecs);
}
}