161 lines
3.8 KiB
C++
161 lines
3.8 KiB
C++
/*
|
|
Copyright 2016-2024 melonDS team
|
|
|
|
This file is part of melonDS.
|
|
|
|
melonDS is free software: you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option)
|
|
any later version.
|
|
|
|
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
*/
|
|
|
|
#include "PacketDispatcher.h"
|
|
|
|
using namespace melonDS;
|
|
|
|
struct PacketHeader
|
|
{
|
|
u32 magic;
|
|
u32 senderID;
|
|
u32 headerLength;
|
|
u32 dataLength;
|
|
};
|
|
|
|
const u32 kPacketMagic = 0x4B504C4D;
|
|
|
|
|
|
PacketDispatcher::PacketDispatcher() : mutex(Platform::Mutex_Create())
|
|
{
|
|
instanceMask = 0;
|
|
}
|
|
|
|
PacketDispatcher::~PacketDispatcher()
|
|
{
|
|
Platform::Mutex_Free(mutex);
|
|
}
|
|
|
|
|
|
void PacketDispatcher::registerInstance(int inst)
|
|
{
|
|
Mutex_Lock(mutex);
|
|
|
|
instanceMask |= (1 << inst);
|
|
packetQueues[inst] = std::make_unique<PacketQueue>();
|
|
|
|
Mutex_Unlock(mutex);
|
|
}
|
|
|
|
void PacketDispatcher::unregisterInstance(int inst)
|
|
{
|
|
Mutex_Lock(mutex);
|
|
|
|
instanceMask &= ~(1 << inst);
|
|
packetQueues[inst] = nullptr;
|
|
|
|
Mutex_Unlock(mutex);
|
|
}
|
|
|
|
|
|
void PacketDispatcher::clear()
|
|
{
|
|
Mutex_Lock(mutex);
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
if (!(instanceMask & (1 << i)))
|
|
continue;
|
|
|
|
packetQueues[i]->Clear();
|
|
}
|
|
Mutex_Unlock(mutex);
|
|
}
|
|
|
|
|
|
void PacketDispatcher::sendPacket(const void* header, int headerlen, const void* data, int datalen, int sender, u16 recv_mask)
|
|
{
|
|
if (!header) headerlen = 0;
|
|
if (!data) datalen = 0;
|
|
if ((!headerlen) && (!datalen)) return;
|
|
if ((sizeof(PacketHeader) + headerlen + datalen) >= 0x8000) return;
|
|
if (sender < 0 || sender > 16) return;
|
|
|
|
recv_mask &= instanceMask;
|
|
if (sender < 16) recv_mask &= ~(1 << sender);
|
|
if (!recv_mask) return;
|
|
|
|
PacketHeader phdr;
|
|
phdr.magic = kPacketMagic;
|
|
phdr.senderID = sender;
|
|
phdr.headerLength = headerlen;
|
|
phdr.dataLength = datalen;
|
|
|
|
int totallen = sizeof(phdr) + headerlen + datalen;
|
|
|
|
Mutex_Lock(mutex);
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
if (!(recv_mask & (1 << i)))
|
|
continue;
|
|
|
|
PacketQueue* queue = packetQueues[i].get();
|
|
|
|
// if we run out of space: discard old packets
|
|
while (!queue->CanFit(totallen))
|
|
{
|
|
PacketHeader tmp;
|
|
queue->Read(&tmp, sizeof(tmp));
|
|
queue->Skip(tmp.headerLength + tmp.dataLength);
|
|
}
|
|
|
|
queue->Write(&phdr, sizeof(phdr));
|
|
if (headerlen) queue->Write(header, headerlen);
|
|
if (datalen) queue->Write(data, datalen);
|
|
}
|
|
Mutex_Unlock(mutex);
|
|
}
|
|
|
|
bool PacketDispatcher::recvPacket(void *header, int *headerlen, void *data, int *datalen, int receiver)
|
|
{
|
|
if ((!header) && (!data)) return false;
|
|
if (receiver < 0 || receiver > 15) return false;
|
|
|
|
Mutex_Lock(mutex);
|
|
PacketQueue* queue = packetQueues[receiver].get();
|
|
|
|
PacketHeader phdr;
|
|
if (!queue->Read(&phdr, sizeof(phdr)))
|
|
{
|
|
Mutex_Unlock(mutex);
|
|
return false;
|
|
}
|
|
|
|
if (phdr.magic != kPacketMagic)
|
|
{
|
|
Mutex_Unlock(mutex);
|
|
return false;
|
|
}
|
|
|
|
if (phdr.headerLength)
|
|
{
|
|
if (headerlen) *headerlen = phdr.headerLength;
|
|
if (header) queue->Read(header, phdr.headerLength);
|
|
else queue->Skip(phdr.headerLength);
|
|
}
|
|
|
|
if (phdr.dataLength)
|
|
{
|
|
if (datalen) *datalen = phdr.dataLength;
|
|
if (data) queue->Read(data, phdr.dataLength);
|
|
else queue->Skip(phdr.dataLength);
|
|
}
|
|
|
|
Mutex_Unlock(mutex);
|
|
return true;
|
|
}
|