nn_fp: Full rework of friend service

This commit is contained in:
Exzap 2023-10-17 04:41:22 +02:00
parent 13a50a915e
commit 0d71885c88
37 changed files with 2862 additions and 1991 deletions

View File

@ -526,6 +526,13 @@ namespace CafeSystem
cemuLog_log(LogType::Force, "Platform: {}", platform); cemuLog_log(LogType::Force, "Platform: {}", platform);
} }
static std::vector<IOSUModule*> s_iosuModules =
{
// entries in this list are ordered by initialization order. Shutdown in reverse order
iosu::kernel::GetModule(),
iosu::fpd::GetModule()
};
// initialize all subsystems which are persistent and don't depend on a game running // initialize all subsystems which are persistent and don't depend on a game running
void Initialize() void Initialize()
{ {
@ -550,14 +557,15 @@ namespace CafeSystem
// allocate memory for all SysAllocators // allocate memory for all SysAllocators
// must happen before COS module init, but also before iosu::kernel::Initialize() // must happen before COS module init, but also before iosu::kernel::Initialize()
SysAllocatorContainer::GetInstance().Initialize(); SysAllocatorContainer::GetInstance().Initialize();
// init IOSU // init IOSU modules
for(auto& module : s_iosuModules)
module->SystemLaunch();
// init IOSU (deprecated manual init)
iosuCrypto_init(); iosuCrypto_init();
iosu::kernel::Initialize();
iosu::fsa::Initialize(); iosu::fsa::Initialize();
iosuIoctl_init(); iosuIoctl_init();
iosuAct_init_depr(); iosuAct_init_depr();
iosu::act::Initialize(); iosu::act::Initialize();
iosu::fpd::Initialize();
iosu::iosuMcp_init(); iosu::iosuMcp_init();
iosu::mcp::Init(); iosu::mcp::Init();
iosu::iosuAcp_init(); iosu::iosuAcp_init();
@ -593,11 +601,14 @@ namespace CafeSystem
// if a title is running, shut it down // if a title is running, shut it down
if (sSystemRunning) if (sSystemRunning)
ShutdownTitle(); ShutdownTitle();
// shutdown persistent subsystems // shutdown persistent subsystems (deprecated manual shutdown)
iosu::odm::Shutdown(); iosu::odm::Shutdown();
iosu::act::Stop(); iosu::act::Stop();
iosu::mcp::Shutdown(); iosu::mcp::Shutdown();
iosu::fsa::Shutdown(); iosu::fsa::Shutdown();
// shutdown IOSU modules
for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)
(*it)->SystemExit();
s_initialized = false; s_initialized = false;
} }
@ -821,7 +832,8 @@ namespace CafeSystem
void _LaunchTitleThread() void _LaunchTitleThread()
{ {
// init for(auto& module : s_iosuModules)
module->TitleStart();
cemu_initForGame(); cemu_initForGame();
// enter scheduler // enter scheduler
if (ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler) if (ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler)
@ -956,6 +968,8 @@ namespace CafeSystem
nn::save::ResetToDefaultState(); nn::save::ResetToDefaultState();
coreinit::__OSDeleteAllActivePPCThreads(); coreinit::__OSDeleteAllActivePPCThreads();
RPLLoader_ResetState(); RPLLoader_ResetState();
for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)
(*it)->TitleStop();
// stop time tracking // stop time tracking
iosu::pdm::Stop(); iosu::pdm::Stop();
// reset Cemu subsystems // reset Cemu subsystems

View File

@ -19,7 +19,7 @@ void PPCInterpreter_handleUnsupportedHLECall(PPCInterpreter_t* hCPU)
std::vector<void(*)(PPCInterpreter_t* hCPU)>* sPPCHLETable{}; std::vector<void(*)(PPCInterpreter_t* hCPU)>* sPPCHLETable{};
HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall) HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName)
{ {
if (!sPPCHLETable) if (!sPPCHLETable)
sPPCHLETable = new std::vector<void(*)(PPCInterpreter_t* hCPU)>(); sPPCHLETable = new std::vector<void(*)(PPCInterpreter_t* hCPU)>();

View File

@ -230,7 +230,7 @@ static inline float flushDenormalToZero(float f)
typedef void(*HLECALL)(PPCInterpreter_t* hCPU); typedef void(*HLECALL)(PPCInterpreter_t* hCPU);
typedef sint32 HLEIDX; typedef sint32 HLEIDX;
HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall); HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName);
HLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex); HLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex);
// HLE scheduler // HLE scheduler

View File

@ -1,6 +1,9 @@
#pragma once #pragma once
using IOSMsgQueueId = uint32; using IOSMsgQueueId = uint32;
using IOSTimerId = uint32;
static constexpr IOSTimerId IOSInvalidTimerId = 0xFFFFFFFF;
// returned for syscalls // returned for syscalls
// maybe also shared with IPC? // maybe also shared with IPC?
@ -20,3 +23,12 @@ inline bool IOS_ResultIsError(const IOS_ERROR err)
{ {
return (err & 0x80000000) != 0; return (err & 0x80000000) != 0;
} }
class IOSUModule
{
public:
virtual void SystemLaunch() {}; // CafeSystem is initialized
virtual void SystemExit() {}; // CafeSystem is shutdown
virtual void TitleStart() {}; // foreground title is launched
virtual void TitleStop() {}; // foreground title is closed
};

View File

@ -1,6 +1,8 @@
#include "iosu_kernel.h" #include "iosu_kernel.h"
#include "util/helpers/fspinlock.h" #include "util/helpers/fspinlock.h"
#include "util/helpers/helpers.h"
#include "Cafe/OS/libs/coreinit/coreinit_IPC.h" #include "Cafe/OS/libs/coreinit/coreinit_IPC.h"
#include "util/highresolutiontimer/HighResolutionTimer.h"
namespace iosu namespace iosu
{ {
@ -8,6 +10,9 @@ namespace iosu
{ {
std::mutex sInternalMutex; std::mutex sInternalMutex;
void IOS_DestroyResourceManagerForQueueId(IOSMsgQueueId msgQueueId);
void _IPCDestroyAllHandlesForMsgQueue(IOSMsgQueueId msgQueueId);
static void _assume_lock() static void _assume_lock()
{ {
#ifdef CEMU_DEBUG_ASSERT #ifdef CEMU_DEBUG_ASSERT
@ -84,6 +89,19 @@ namespace iosu
return queueHandle; return queueHandle;
} }
IOS_ERROR IOS_DestroyMessageQueue(IOSMsgQueueId msgQueueId)
{
std::unique_lock _l(sInternalMutex);
IOSMessageQueue* msgQueue = nullptr;
IOS_ERROR r = _IOS_GetMessageQueue(msgQueueId, msgQueue);
if (r != IOS_ERROR_OK)
return r;
msgQueue->msgArraySize = 0;
msgQueue->queueHandle = 0;
IOS_DestroyResourceManagerForQueueId(msgQueueId);
return IOS_ERROR_OK;
}
IOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags) IOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags)
{ {
std::unique_lock _l(sInternalMutex); std::unique_lock _l(sInternalMutex);
@ -146,6 +164,133 @@ namespace iosu
return IOS_ERROR_OK; return IOS_ERROR_OK;
} }
/* timer */
std::mutex sTimerMutex;
std::condition_variable sTimerCV;
std::atomic_bool sTimerThreadStop;
struct IOSTimer
{
IOSMsgQueueId queueId;
uint32 message;
HRTick nextFire;
HRTick repeat;
bool isValid;
};
std::vector<IOSTimer> sTimers;
std::vector<IOSTimerId> sTimersFreeHandles;
auto sTimerSortComparator = [](const IOSTimerId& idA, const IOSTimerId& idB)
{
// order by nextFire, then by timerId to avoid duplicate keys
IOSTimer& timerA = sTimers[idA];
IOSTimer& timerB = sTimers[idB];
if (timerA.nextFire != timerB.nextFire)
return timerA.nextFire < timerB.nextFire;
return idA < idB;
};
std::set<IOSTimerId, decltype(sTimerSortComparator)> sTimerByFireTime;
IOSTimer& IOS_GetFreeTimer()
{
cemu_assert_debug(!sTimerMutex.try_lock()); // lock must be held by current thread
if (sTimersFreeHandles.empty())
return sTimers.emplace_back();
IOSTimerId timerId = sTimersFreeHandles.back();
sTimersFreeHandles.pop_back();
return sTimers[timerId];
}
void IOS_TimerSetNextFireTime(IOSTimer& timer, HRTick nextFire)
{
cemu_assert_debug(!sTimerMutex.try_lock()); // lock must be held by current thread
IOSTimerId timerId = &timer - sTimers.data();
auto it = sTimerByFireTime.find(timerId);
if(it != sTimerByFireTime.end())
sTimerByFireTime.erase(it);
timer.nextFire = nextFire;
if(nextFire != 0)
sTimerByFireTime.insert(timerId);
}
void IOS_StopTimerInternal(IOSTimerId timerId)
{
cemu_assert_debug(!sTimerMutex.try_lock());
IOS_TimerSetNextFireTime(sTimers[timerId], 0);
}
IOS_ERROR IOS_CreateTimer(uint32 startMicroseconds, uint32 repeatMicroseconds, uint32 queueId, uint32 message)
{
std::unique_lock _l(sTimerMutex);
IOSTimer& timer = IOS_GetFreeTimer();
timer.queueId = queueId;
timer.message = message;
HRTick nextFire = HighResolutionTimer::now().getTick() + HighResolutionTimer::microsecondsToTicks(startMicroseconds);
timer.repeat = HighResolutionTimer::microsecondsToTicks(repeatMicroseconds);
IOS_TimerSetNextFireTime(timer, nextFire);
timer.isValid = true;
sTimerCV.notify_one();
return (IOS_ERROR)(&timer - sTimers.data());
}
IOS_ERROR IOS_StopTimer(IOSTimerId timerId)
{
std::unique_lock _l(sTimerMutex);
if (timerId >= sTimers.size() || !sTimers[timerId].isValid)
return IOS_ERROR_INVALID;
IOS_StopTimerInternal(timerId);
return IOS_ERROR_OK;
}
IOS_ERROR IOS_DestroyTimer(IOSTimerId timerId)
{
std::unique_lock _l(sTimerMutex);
if (timerId >= sTimers.size() || !sTimers[timerId].isValid)
return IOS_ERROR_INVALID;
IOS_StopTimerInternal(timerId);
sTimers[timerId].isValid = false;
sTimersFreeHandles.push_back(timerId);
return IOS_ERROR_OK;
}
void IOSTimerThread()
{
SetThreadName("IOS-Timer");
std::unique_lock _l(sTimerMutex);
while (!sTimerThreadStop)
{
if (sTimerByFireTime.empty())
{
sTimerCV.wait_for(_l, std::chrono::milliseconds(10000));
continue;
}
IOSTimerId timerId = *sTimerByFireTime.begin();
IOSTimer& timer = sTimers[timerId];
HRTick now = HighResolutionTimer::now().getTick();
if (now >= timer.nextFire)
{
if(timer.repeat == 0)
IOS_TimerSetNextFireTime(timer, 0);
else
IOS_TimerSetNextFireTime(timer, timer.nextFire + timer.repeat);
IOSMsgQueueId queueId = timer.queueId;
uint32 message = timer.message;
// fire timer
_l.unlock();
IOSMessage msg;
IOS_SendMessage(queueId, message, 1);
_l.lock();
continue;
}
else
{
sTimerCV.wait_for(_l, std::chrono::microseconds(HighResolutionTimer::ticksToMicroseconds(timer.nextFire - now)));
}
}
}
/* devices and IPC */ /* devices and IPC */
struct IOSResourceManager struct IOSResourceManager
@ -209,6 +354,23 @@ namespace iosu
return IOS_ERROR_OK; return IOS_ERROR_OK;
} }
void IOS_DestroyResourceManagerForQueueId(IOSMsgQueueId msgQueueId)
{
_assume_lock();
// destroy all IPC handles associated with this queue
_IPCDestroyAllHandlesForMsgQueue(msgQueueId);
// destroy device resource manager
for (auto& it : sDeviceResources)
{
if (it.isSet && it.msgQueueId == msgQueueId)
{
it.isSet = false;
it.path.clear();
it.msgQueueId = 0;
}
}
}
IOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id) IOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id)
{ {
// not yet implemented // not yet implemented
@ -344,6 +506,22 @@ namespace iosu
return IOS_ERROR_OK; return IOS_ERROR_OK;
} }
void _IPCDestroyAllHandlesForMsgQueue(IOSMsgQueueId msgQueueId)
{
_assume_lock();
for (auto& it : sActiveDeviceHandles)
{
if (it.isSet && it.msgQueueId == msgQueueId)
{
it.isSet = false;
it.path.clear();
it.handleCheckValue = 0;
it.hasDispatchTargetHandle = false;
it.msgQueueId = 0;
}
}
}
IOS_ERROR _IPCAssignDispatchTargetHandle(IOSDevHandle devHandle, IOSDevHandle internalHandle) IOS_ERROR _IPCAssignDispatchTargetHandle(IOSDevHandle devHandle, IOSDevHandle internalHandle)
{ {
std::unique_lock _lock(sInternalMutex); std::unique_lock _lock(sInternalMutex);
@ -453,7 +631,6 @@ namespace iosu
uint32 numIn = dispatchCmd->body.args[1]; uint32 numIn = dispatchCmd->body.args[1];
uint32 numOut = dispatchCmd->body.args[2]; uint32 numOut = dispatchCmd->body.args[2];
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>(cmd.args[3]).GetPtr(); IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>(cmd.args[3]).GetPtr();
// copy the vector array // copy the vector array
uint32 numVec = numIn + numOut; uint32 numVec = numIn + numOut;
if (numVec <= 8) if (numVec <= 8)
@ -466,8 +643,23 @@ namespace iosu
// reuse the original vector pointer // reuse the original vector pointer
cemuLog_log(LogType::Force, "Info: Ioctlv command with more than 8 vectors"); cemuLog_log(LogType::Force, "Info: Ioctlv command with more than 8 vectors");
} }
IOS_ERROR r = _IPCDispatchToResourceManager(dispatchCmd->body.devHandle, dispatchCmd); return _IPCDispatchToResourceManager(dispatchCmd->body.devHandle, dispatchCmd);
return r; }
// normally COS kernel handles this, but currently we skip the IPC getting proxied through it
IOS_ERROR _IPCHandlerIn_TranslateVectorAddresses(IOSDispatchableCommand* dispatchCmd)
{
uint32 numIn = dispatchCmd->body.args[1];
uint32 numOut = dispatchCmd->body.args[2];
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>(dispatchCmd->body.args[3]).GetPtr();
for (uint32 i = 0; i < numIn + numOut; i++)
{
if (vec[i].baseVirt == nullptr && vec[i].size != 0)
return IOS_ERROR_INVALID;
// todo - check for valid pointer range
vec[i].basePhys = vec[i].baseVirt;
}
return IOS_ERROR_OK;
} }
// called by COS directly // called by COS directly
@ -494,7 +686,11 @@ namespace iosu
r = _IPCHandlerIn_IOS_Ioctl(dispatchCmd); r = _IPCHandlerIn_IOS_Ioctl(dispatchCmd);
break; break;
case IPCCommandId::IOS_IOCTLV: case IPCCommandId::IOS_IOCTLV:
r = _IPCHandlerIn_IOS_Ioctlv(dispatchCmd); r = _IPCHandlerIn_TranslateVectorAddresses(dispatchCmd);
if(r < 0)
cemuLog_log(LogType::Force, "Ioctlv error");
else
r = _IPCHandlerIn_IOS_Ioctlv(dispatchCmd);
break; break;
default: default:
cemuLog_log(LogType::Force, "Invalid IPC command {}", (uint32)(IPCCommandId)cmd->cmdId); cemuLog_log(LogType::Force, "Invalid IPC command {}", (uint32)(IPCCommandId)cmd->cmdId);
@ -547,10 +743,34 @@ namespace iosu
return IOS_ERROR_OK; return IOS_ERROR_OK;
} }
void Initialize() class : public ::IOSUModule
{ {
_IPCInitDispatchablePool(); void SystemLaunch() override
{
_IPCInitDispatchablePool();
// start timer thread
sTimerThreadStop = false;
m_timerThread = std::thread(IOSTimerThread);
}
void SystemExit() override
{
// stop timer thread
sTimerThreadStop = true;
sTimerCV.notify_one();
m_timerThread.join();
// reset resources
// todo
}
std::thread m_timerThread;
}sIOSUModuleKernel;
IOSUModule* GetModule()
{
return static_cast<IOSUModule*>(&sIOSUModuleKernel);
} }
} }
} }

View File

@ -9,15 +9,20 @@ namespace iosu
using IOSMessage = uint32; using IOSMessage = uint32;
IOSMsgQueueId IOS_CreateMessageQueue(IOSMessage* messageArray, uint32 messageCount); IOSMsgQueueId IOS_CreateMessageQueue(IOSMessage* messageArray, uint32 messageCount);
IOS_ERROR IOS_DestroyMessageQueue(IOSMsgQueueId msgQueueId);
IOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags); IOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags);
IOS_ERROR IOS_ReceiveMessage(IOSMsgQueueId msgQueueId, IOSMessage* messageOut, uint32 flags); IOS_ERROR IOS_ReceiveMessage(IOSMsgQueueId msgQueueId, IOSMessage* messageOut, uint32 flags);
IOS_ERROR IOS_CreateTimer(uint32 startMicroseconds, uint32 repeatMicroseconds, uint32 queueId, uint32 message);
IOS_ERROR IOS_StopTimer(IOSTimerId timerId);
IOS_ERROR IOS_DestroyTimer(IOSTimerId timerId);
IOS_ERROR IOS_RegisterResourceManager(const char* devicePath, IOSMsgQueueId msgQueueId); IOS_ERROR IOS_RegisterResourceManager(const char* devicePath, IOSMsgQueueId msgQueueId);
IOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id); IOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id);
IOS_ERROR IOS_ResourceReply(IPCCommandBody* cmd, IOS_ERROR result); IOS_ERROR IOS_ResourceReply(IPCCommandBody* cmd, IOS_ERROR result);
void IPCSubmitFromCOS(uint32 ppcCoreIndex, IPCCommandBody* cmd); void IPCSubmitFromCOS(uint32 ppcCoreIndex, IPCCommandBody* cmd);
void Initialize(); IOSUModule* GetModule();
} }
} }

View File

@ -192,6 +192,15 @@ namespace iosu
return true; return true;
} }
// returns empty string if invalid
std::string getAccountId2(uint8 slot)
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
if (_actAccountData[accountIndex].isValid == false)
return {};
return {_actAccountData[accountIndex].accountId};
}
bool getMii(uint8 slot, FFLData_t* fflData) bool getMii(uint8 slot, FFLData_t* fflData)
{ {
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot); sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);

View File

@ -3,6 +3,8 @@
void iosuAct_init_depr(); void iosuAct_init_depr();
bool iosuAct_isInitialized(); bool iosuAct_isInitialized();
#define ACT_ACCOUNTID_LENGTH (17) // includes '\0'
// Mii // Mii
#define MII_FFL_STORAGE_SIZE (96) #define MII_FFL_STORAGE_SIZE (96)
@ -48,6 +50,8 @@ namespace iosu
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]); bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]);
bool getCountryIndex(uint8 slot, uint32* countryIndex); bool getCountryIndex(uint8 slot, uint32* countryIndex);
std::string getAccountId2(uint8 slot);
const uint8 ACT_SLOT_CURRENT = 0xFE; const uint8 ACT_SLOT_CURRENT = 0xFE;
void Initialize(); void Initialize();

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,12 @@
#pragma once #pragma once
#include "Cafe/IOSU/iosu_types_common.h"
#include "Common/CafeString.h"
namespace iosu namespace iosu
{ {
namespace fpd namespace fpd
{ {
typedef struct struct FPDDate
{ {
/* +0x0 */ uint16be year; /* +0x0 */ uint16be year;
/* +0x2 */ uint8 month; /* +0x2 */ uint8 month;
@ -13,13 +15,61 @@ namespace iosu
/* +0x5 */ uint8 minute; /* +0x5 */ uint8 minute;
/* +0x6 */ uint8 second; /* +0x6 */ uint8 second;
/* +0x7 */ uint8 padding; /* +0x7 */ uint8 padding;
}fpdDate_t; };
static_assert(sizeof(fpdDate_t) == 8); static_assert(sizeof(FPDDate) == 8);
typedef struct struct RecentPlayRecordEx
{ {
/* +0x000 */ uint8 type; // type(Non-Zero -> Friend, 0 -> Friend request ? ) /* +0x00 */ uint32be pid;
/* +0x04 */ uint8 ukn04;
/* +0x05 */ uint8 ukn05;
/* +0x06 */ uint8 ukn06[0x22];
/* +0x28 */ uint8 ukn28[0x22];
/* +0x4A */ uint8 _uknOrPadding4A[6];
/* +0x50 */ uint32be ukn50;
/* +0x54 */ uint32be ukn54;
/* +0x58 */ uint16be ukn58;
/* +0x5C */ uint8 _padding5C[4];
/* +0x60 */ iosu::fpd::FPDDate date;
};
static_assert(sizeof(RecentPlayRecordEx) == 0x68, "");
static_assert(offsetof(RecentPlayRecordEx, ukn06) == 0x06, "");
static_assert(offsetof(RecentPlayRecordEx, ukn50) == 0x50, "");
struct GameKey
{
/* +0x00 */ uint64be titleId;
/* +0x08 */ uint16be ukn08;
/* +0x0A */ uint8 _padding0A[6];
};
static_assert(sizeof(GameKey) == 0x10);
struct Profile
{
uint8be region;
uint8be regionSubcode;
uint8be platform;
uint8be ukn3;
};
static_assert(sizeof(Profile) == 0x4);
struct GameMode
{
/* +0x00 */ uint32be joinFlagMask;
/* +0x04 */ uint32be matchmakeType;
/* +0x08 */ uint32be joinGameId;
/* +0x0C */ uint32be joinGameMode;
/* +0x10 */ uint32be hostPid;
/* +0x14 */ uint32be groupId;
/* +0x18 */ uint8 appSpecificData[0x14];
};
static_assert(sizeof(GameMode) == 0x2C);
struct FriendData
{
/* +0x000 */ uint8 type; // type (Non-Zero -> Friend, 0 -> Friend request ? )
/* +0x001 */ uint8 _padding1[7]; /* +0x001 */ uint8 _padding1[7];
/* +0x008 */ uint32be pid; /* +0x008 */ uint32be pid;
/* +0x00C */ char nnid[0x10 + 1]; /* +0x00C */ char nnid[0x10 + 1];
@ -29,43 +79,29 @@ namespace iosu
/* +0x036 */ uint8 ukn036; /* +0x036 */ uint8 ukn036;
/* +0x037 */ uint8 _padding037; /* +0x037 */ uint8 _padding037;
/* +0x038 */ uint8 mii[0x60]; /* +0x038 */ uint8 mii[0x60];
/* +0x098 */ fpdDate_t uknDate; /* +0x098 */ FPDDate uknDate;
// sub struct (the part above seems to be shared with friend requests) // sub struct (the part above seems to be shared with friend requests)
union union
{ {
struct struct
{ {
/* +0x0A0 */ uint8 ukn0A0; // country code? /* +0x0A0 */ Profile profile; // this is returned for nn_fp.GetFriendProfile
/* +0x0A1 */ uint8 ukn0A1; // country subcode?
/* +0x0A2 */ uint8 _paddingA2[2];
/* +0x0A4 */ uint32be ukn0A4; /* +0x0A4 */ uint32be ukn0A4;
/* +0x0A8 */ uint64 gameKeyTitleId; /* +0x0A8 */ GameKey gameKey;
/* +0x0B0 */ uint16be gameKeyUkn; /* +0x0B8 */ GameMode gameMode;
/* +0x0B2 */ uint8 _paddingB2[6]; /* +0x0E4 */ CafeWideString<0x82> gameModeDescription;
/* +0x0B8 */ uint32 ukn0B8; /* +0x1E8 */ Profile profile1E8; // how does it differ from the one at 0xA0? Returned by GetFriendPresence
/* +0x0BC */ uint32 ukn0BC;
/* +0x0C0 */ uint32 ukn0C0;
/* +0x0C4 */ uint32 ukn0C4;
/* +0x0C8 */ uint32 ukn0C8;
/* +0x0CC */ uint32 ukn0CC;
/* +0x0D0 */ uint8 appSpecificData[0x14];
/* +0x0E4 */ uint8 ukn0E4;
/* +0x0E5 */ uint8 _paddingE5;
/* +0x0E6 */ uint16 uknStr[0x80]; // game mode description (could be larger)
/* +0x1E6 */ uint8 _padding1E6[0x1EC - 0x1E6];
/* +0x1EC */ uint8 isOnline; /* +0x1EC */ uint8 isOnline;
/* +0x1ED */ uint8 _padding1ED[3]; /* +0x1ED */ uint8 _padding1ED[3];
// some other sub struct? // some other sub struct?
/* +0x1F0 */ uint8 ukn1F0; /* +0x1F0 */ char comment[36]; // pops up every few seconds in friend list
/* +0x1F1 */ uint8 _padding1F1; /* +0x214 */ uint32be _padding214;
/* +0x1F2 */ uint16be statusMessage[16 + 1]; // pops up every few seconds in friend list (ingame character name?) /* +0x218 */ FPDDate approvalTime;
/* +0x214 */ uint8 _padding214[4]; /* +0x220 */ FPDDate lastOnline;
/* +0x218 */ fpdDate_t uknDate218;
/* +0x220 */ fpdDate_t lastOnline;
}friendExtraData; }friendExtraData;
struct struct
{ {
/* +0x0A0 */ uint64 messageId; // guessed /* +0x0A0 */ uint64be messageId; // guessed. If 0, then relationship is FRIENDSHIP_REQUEST_OUT, otherwise FRIENDSHIP_REQUEST_IN
/* +0x0A8 */ uint8 ukn0A8; /* +0x0A8 */ uint8 ukn0A8;
/* +0x0A9 */ uint8 ukn0A9; // comment language? (guessed) /* +0x0A9 */ uint8 ukn0A9; // comment language? (guessed)
/* +0x0AA */ uint16be comment[0x40]; /* +0x0AA */ uint16be comment[0x40];
@ -75,26 +111,23 @@ namespace iosu
/* +0x150 */ uint64 gameKeyTitleId; /* +0x150 */ uint64 gameKeyTitleId;
/* +0x158 */ uint16be gameKeyUkn; /* +0x158 */ uint16be gameKeyUkn;
/* +0x15A */ uint8 _padding[6]; /* +0x15A */ uint8 _padding[6];
/* +0x160 */ fpdDate_t uknData0; /* +0x160 */ FPDDate uknData0;
/* +0x168 */ fpdDate_t uknData1; /* +0x168 */ FPDDate uknData1;
}requestExtraData; }requestExtraData;
}; };
}friendData_t; };
static_assert(sizeof(FriendData) == 0x228);
static_assert(offsetof(FriendData, friendExtraData.gameKey) == 0x0A8);
static_assert(offsetof(FriendData, friendExtraData.gameModeDescription) == 0x0E4);
static_assert(offsetof(FriendData, friendExtraData.comment) == 0x1F0);
static_assert(sizeof(friendData_t) == 0x228, ""); static_assert(offsetof(FriendData, requestExtraData.messageId) == 0x0A0);
static_assert(offsetof(friendData_t, nnid) == 0x00C, ""); static_assert(offsetof(FriendData, requestExtraData.comment) == 0x0AA);
static_assert(offsetof(friendData_t, friendExtraData.gameKeyTitleId) == 0x0A8, ""); static_assert(offsetof(FriendData, requestExtraData.uknMessage) == 0x12C);
static_assert(offsetof(friendData_t, friendExtraData.appSpecificData) == 0x0D0, ""); static_assert(offsetof(FriendData, requestExtraData.gameKeyTitleId) == 0x150);
static_assert(offsetof(friendData_t, friendExtraData.uknStr) == 0x0E6, ""); static_assert(offsetof(FriendData, requestExtraData.uknData1) == 0x168);
static_assert(offsetof(friendData_t, friendExtraData.ukn1F0) == 0x1F0, "");
static_assert(offsetof(friendData_t, requestExtraData.messageId) == 0x0A0, ""); struct FriendBasicInfo
static_assert(offsetof(friendData_t, requestExtraData.comment) == 0x0AA, "");
static_assert(offsetof(friendData_t, requestExtraData.uknMessage) == 0x12C, "");
static_assert(offsetof(friendData_t, requestExtraData.gameKeyTitleId) == 0x150, "");
static_assert(offsetof(friendData_t, requestExtraData.uknData1) == 0x168, "");
typedef struct
{ {
/* +0x00 */ uint32be pid; /* +0x00 */ uint32be pid;
/* +0x04 */ char nnid[0x11]; /* +0x04 */ char nnid[0x11];
@ -104,17 +137,17 @@ namespace iosu
/* +0x2E */ uint8 ukn2E; // bool option /* +0x2E */ uint8 ukn2E; // bool option
/* +0x2F */ uint8 ukn2F; /* +0x2F */ uint8 ukn2F;
/* +0x30 */ uint8 miiData[0x60]; /* +0x30 */ uint8 miiData[0x60];
/* +0x90 */ fpdDate_t uknDate90; /* +0x90 */ FPDDate uknDate90;
}friendBasicInfo_t; // size is 0x98 };
static_assert(sizeof(friendBasicInfo_t) == 0x98, ""); static_assert(sizeof(FriendBasicInfo) == 0x98);
static_assert(offsetof(friendBasicInfo_t, nnid) == 0x04, ""); static_assert(offsetof(FriendBasicInfo, nnid) == 0x04);
static_assert(offsetof(friendBasicInfo_t, ukn15) == 0x15, ""); static_assert(offsetof(FriendBasicInfo, ukn15) == 0x15);
static_assert(offsetof(friendBasicInfo_t, screenname) == 0x18, ""); static_assert(offsetof(FriendBasicInfo, screenname) == 0x18);
static_assert(offsetof(friendBasicInfo_t, ukn2E) == 0x2E, ""); static_assert(offsetof(FriendBasicInfo, ukn2E) == 0x2E);
static_assert(offsetof(friendBasicInfo_t, miiData) == 0x30, ""); static_assert(offsetof(FriendBasicInfo, miiData) == 0x30);
typedef struct struct FriendRequest
{ {
/* +0x000 */ uint32be pid; /* +0x000 */ uint32be pid;
/* +0x004 */ uint8 nnid[17]; // guessed type /* +0x004 */ uint8 nnid[17]; // guessed type
@ -125,7 +158,7 @@ namespace iosu
/* +0x02E */ uint8 ukn2E; // bool option /* +0x02E */ uint8 ukn2E; // bool option
/* +0x02F */ uint8 ukn2F; // ukn /* +0x02F */ uint8 ukn2F; // ukn
/* +0x030 */ uint8 miiData[0x60]; /* +0x030 */ uint8 miiData[0x60];
/* +0x090 */ fpdDate_t uknDate; /* +0x090 */ FPDDate uknDate;
/* +0x098 */ uint64 ukn98; /* +0x098 */ uint64 ukn98;
/* +0x0A0 */ uint8 isMarkedAsReceived; /* +0x0A0 */ uint8 isMarkedAsReceived;
/* +0x0A1 */ uint8 uknA1; /* +0x0A1 */ uint8 uknA1;
@ -136,216 +169,98 @@ namespace iosu
/* +0x148 */ uint64 gameKeyTitleId; /* +0x148 */ uint64 gameKeyTitleId;
/* +0x150 */ uint16be gameKeyUkn; /* +0x150 */ uint16be gameKeyUkn;
/* +0x152 */ uint8 _padding152[6]; /* +0x152 */ uint8 _padding152[6];
/* +0x158 */ fpdDate_t uknDate2; /* +0x158 */ FPDDate uknDate2;
/* +0x160 */ fpdDate_t expireDate; /* +0x160 */ FPDDate expireDate;
}friendRequest_t; };
static_assert(sizeof(friendRequest_t) == 0x168, ""); static_assert(sizeof(FriendRequest) == 0x168);
static_assert(offsetof(friendRequest_t, uknDate) == 0x090, ""); static_assert(offsetof(FriendRequest, uknDate) == 0x090);
static_assert(offsetof(friendRequest_t, message) == 0x0A2, ""); static_assert(offsetof(FriendRequest, message) == 0x0A2);
static_assert(offsetof(friendRequest_t, uknString2) == 0x124, ""); static_assert(offsetof(FriendRequest, uknString2) == 0x124);
static_assert(offsetof(friendRequest_t, gameKeyTitleId) == 0x148, ""); static_assert(offsetof(FriendRequest, gameKeyTitleId) == 0x148);
typedef struct struct FriendPresence
{ {
/* +0x00 */ uint32be joinFlagMask; GameMode gameMode;
/* +0x04 */ uint32be matchmakeType; /* +0x2C */ Profile profile;
/* +0x08 */ uint32be joinGameId;
/* +0x0C */ uint32be joinGameMode;
/* +0x10 */ uint32be hostPid;
/* +0x14 */ uint32be groupId;
/* +0x18 */ uint8 appSpecificData[0x14];
}gameMode_t;
static_assert(sizeof(gameMode_t) == 0x2C, "");
typedef struct
{
gameMode_t gameMode;
/* +0x2C */ uint8 region;
/* +0x2D */ uint8 regionSubcode;
/* +0x2E */ uint8 platform;
/* +0x2F */ uint8 _padding2F;
/* +0x30 */ uint8 isOnline; /* +0x30 */ uint8 isOnline;
/* +0x31 */ uint8 isValid; /* +0x31 */ uint8 isValid;
/* +0x32 */ uint8 padding[2]; // guessed /* +0x32 */ uint8 padding[2]; // guessed
}friendPresence_t; };
static_assert(sizeof(FriendPresence) == 0x34);
static_assert(offsetof(FriendPresence, isOnline) == 0x30);
static_assert(sizeof(friendPresence_t) == 0x34, ""); struct FPDNotification
static_assert(offsetof(friendPresence_t, region) == 0x2C, ""); {
static_assert(offsetof(friendPresence_t, isOnline) == 0x30, ""); betype<uint32> type;
betype<uint32> pid;
};
static_assert(sizeof(FPDNotification) == 8);
struct FPDPreference
{
uint8be showOnline; // show online status to others
uint8be showGame; // show played game to others
uint8be blockFriendRequests; // block friend requests
uint8be ukn; // probably padding?
};
static_assert(sizeof(FPDPreference) == 4);
static const int RELATIONSHIP_INVALID = 0; static const int RELATIONSHIP_INVALID = 0;
static const int RELATIONSHIP_FRIENDREQUEST_OUT = 1; static const int RELATIONSHIP_FRIENDREQUEST_OUT = 1;
static const int RELATIONSHIP_FRIENDREQUEST_IN = 2; static const int RELATIONSHIP_FRIENDREQUEST_IN = 2;
static const int RELATIONSHIP_FRIEND = 3; static const int RELATIONSHIP_FRIEND = 3;
typedef struct static const int GAMEMODE_MAX_MESSAGE_LENGTH = 0x80; // limit includes null-terminator character, so only 0x7F actual characters can be used
enum class FPD_REQUEST_ID
{ {
uint32 requestCode; LoginAsync = 0x2775,
union HasLoggedIn = 0x2777,
{ IsOnline = 0x2778,
struct GetMyPrincipalId = 0x27D9,
{ GetMyAccountId = 0x27DA,
MEMPTR<void> ptr; GetMyScreenName = 0x27DB,
}common; GetMyMii = 0x27DC,
struct GetMyProfile = 0x27DD,
{ GetMyPreference = 0x27DE,
MPTR funcPtr; GetMyPresence = 0x27DF,
MPTR custom; IsPreferenceValid = 0x27E0,
}loginAsync; GetFriendList = 0x283D,
struct GetFriendListAll = 0x283E,
{ GetFriendAccountId = 0x283F,
MEMPTR<uint32be> pidList; GetFriendScreenName = 0x2840,
uint32 startIndex; GetFriendPresence = 0x2845,
uint32 maxCount; GetFriendRelationship = 0x2846,
}getFriendList; GetFriendMii = 0x2841,
struct GetBlackList = 0x28A1,
{ GetFriendRequestList = 0x2905,
MEMPTR<friendData_t> friendData; UpdateGameModeVariation1 = 0x2969, // there seem to be two different requestIds for the 2-param and 3-param version of UpdateGameMode,
MEMPTR<uint32be> pidList; UpdateGameModeVariation2 = 0x296A, // but the third parameter is never used and the same handler is used for both
uint32 count; AddFriendAsyncByPid = 0x29CD,
}getFriendListEx; AddFriendAsyncByXXX = 0x29CE, // probably by name?
struct GetRequestBlockSettingAsync = 0x2B5D,
{ GetMyComment = 0x4EE9,
MEMPTR<friendRequest_t> friendRequest; GetMyPlayingGame = 0x4EEA,
MEMPTR<uint32be> pidList; CheckSettingStatusAsync = 0x7596,
uint32 count; GetFriendListEx = 0x75F9,
}getFriendRequestListEx; GetFriendRequestListEx = 0x76C1,
struct UpdatePreferenceAsync = 0x7727,
{ RemoveFriendAsync = 0x7789,
uint32 pid; DeleteFriendFlagsAsync = 0x778A,
MPTR funcPtr; AddFriendRequestByPlayRecordAsync = 0x778B,
MPTR custom; CancelFriendRequestAsync = 0x778C,
}addOrRemoveFriend; AcceptFriendRequestAsync = 0x7851,
struct DeleteFriendRequestAsync = 0x7852,
{ MarkFriendRequestsAsReceivedAsync = 0x7854,
uint64 messageId; GetBasicInfoAsync = 0x7919,
MPTR funcPtr; SetLedEventMask = 0x9D0B,
MPTR custom; SetNotificationMask = 0x15ff5,
}cancelOrAcceptFriendRequest; GetNotificationAsync = 0x15FF6,
struct
{
uint32 pid;
MEMPTR<uint16be> message;
MPTR funcPtr;
MPTR custom;
}addFriendRequest;
struct
{
MEMPTR<uint64> messageIdList;
uint32 count;
MPTR funcPtr;
MPTR custom;
}markFriendRequest;
struct
{
MEMPTR<friendBasicInfo_t> basicInfo;
MEMPTR<uint32be> pidList;
sint32 count;
MPTR funcPtr;
MPTR custom;
}getBasicInfo;
struct
{
uint32 notificationMask;
MPTR funcPtr;
MPTR custom;
}setNotificationHandler;
struct
{
MEMPTR<char> accountIds;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendAccountId;
struct
{
MEMPTR<uint16be> nameList;
MEMPTR<uint32be> pidList;
sint32 count;
bool replaceNonAscii;
MEMPTR<uint8> languageList;
}getFriendScreenname;
struct
{
uint8* miiList;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendMii;
struct
{
uint8* presenceList;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendPresence;
struct
{
uint8* relationshipList;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendRelationship;
struct
{
MEMPTR<gameMode_t> gameMode;
MEMPTR<uint16be> gameModeMessage;
}updateGameMode;
};
// output
uint32 returnCode; // return value
union
{
struct
{
uint32 numReturnedCount;
}resultGetFriendList;
struct
{
uint32 u32;
}resultU32;
};
}iosuFpdCemuRequest_t;
// custom dev/fpd protocol (Cemu only)
#define IOSU_FPD_REQUEST_CEMU (0xEE)
// FPD request Cemu subcodes
enum
{
_IOSU_FPD_NONE,
IOSU_FPD_INITIALIZE,
IOSU_FPD_SET_NOTIFICATION_HANDLER,
IOSU_FPD_LOGIN_ASYNC,
IOSU_FPD_IS_ONLINE,
IOSU_FPD_IS_PREFERENCE_VALID,
IOSU_FPD_UPDATE_GAMEMODE,
IOSU_FPD_GET_MY_PRINCIPAL_ID,
IOSU_FPD_GET_MY_ACCOUNT_ID,
IOSU_FPD_GET_MY_MII,
IOSU_FPD_GET_MY_SCREENNAME,
IOSU_FPD_GET_FRIEND_ACCOUNT_ID,
IOSU_FPD_GET_FRIEND_SCREENNAME,
IOSU_FPD_GET_FRIEND_MII,
IOSU_FPD_GET_FRIEND_PRESENCE,
IOSU_FPD_GET_FRIEND_RELATIONSHIP,
IOSU_FPD_GET_FRIEND_LIST,
IOSU_FPD_GET_FRIENDREQUEST_LIST,
IOSU_FPD_GET_FRIEND_LIST_ALL,
IOSU_FPD_GET_FRIEND_LIST_EX,
IOSU_FPD_GET_FRIENDREQUEST_LIST_EX,
IOSU_FPD_ADD_FRIEND,
IOSU_FPD_ADD_FRIEND_REQUEST,
IOSU_FPD_REMOVE_FRIEND_ASYNC,
IOSU_FPD_CANCEL_FRIEND_REQUEST_ASYNC,
IOSU_FPD_ACCEPT_FRIEND_REQUEST_ASYNC,
IOSU_FPD_MARK_FRIEND_REQUEST_AS_RECEIVED_ASYNC,
IOSU_FPD_GET_BASIC_INFO_ASYNC,
}; };
void Initialize(); using FriendPID = uint32;
IOSUModule* GetModule();
} }
} }

View File

@ -1,5 +1,6 @@
#include "iosu_nn_service.h" #include "iosu_nn_service.h"
#include "../kernel/iosu_kernel.h" #include "../kernel/iosu_kernel.h"
#include "util/helpers/helpers.h"
using namespace iosu::kernel; using namespace iosu::kernel;
@ -7,6 +8,132 @@ namespace iosu
{ {
namespace nn namespace nn
{ {
/* IPCSimpleService */
void IPCSimpleService::Start()
{
if (m_isRunning.exchange(true))
return;
m_threadInitialized = false;
m_requestStop = false;
m_serviceThread = std::thread(&IPCSimpleService::ServiceThread, this);
while (!m_threadInitialized) std::this_thread::sleep_for(std::chrono::milliseconds(10));
StartService();
}
void IPCSimpleService::Stop()
{
if (!m_isRunning.exchange(false))
return;
m_requestStop = true;
StopService();
if(m_timerId != IOSInvalidTimerId)
IOS_DestroyTimer(m_timerId);
m_timerId = IOSInvalidTimerId;
IOS_SendMessage(m_msgQueueId, 0, 0); // wake up thread
m_serviceThread.join();
}
void IPCSimpleService::ServiceThread()
{
if(!GetThreadName().empty())
SetThreadName(GetThreadName().c_str());
m_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());
cemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));
IOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);
cemu_assert(!IOS_ResultIsError(r));
m_threadInitialized = true;
while (true)
{
IOSMessage msg;
r = IOS_ReceiveMessage(m_msgQueueId, &msg, 0);
cemu_assert(!IOS_ResultIsError(r));
if (msg == 0)
{
cemu_assert_debug(m_requestStop);
break;
}
else if(msg == 1)
{
TimerUpdate();
continue;
}
IPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();
if (cmd->cmdId == IPCCommandId::IOS_OPEN)
{
void* clientObject = CreateClientObject();
if(clientObject == nullptr)
{
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Maximum handle count reached or handle rejected", m_devicePath);
IOS_ResourceReply(cmd, IOS_ERROR_MAXIMUM_REACHED);
continue;
}
IOSDevHandle newHandle = GetFreeHandle();
m_clientObjects[newHandle] = clientObject;
IOS_ResourceReply(cmd, (IOS_ERROR)newHandle);
continue;
}
else if (cmd->cmdId == IPCCommandId::IOS_CLOSE)
{
void* clientObject = GetClientObjectByHandle(cmd->devHandle);
if (clientObject)
DestroyClientObject(clientObject);
IOS_ResourceReply(cmd, IOS_ERROR_OK);
continue;
}
else if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)
{
void* clientObject = GetClientObjectByHandle(cmd->devHandle);
if (!clientObject)
{
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Invalid IPC handle", m_devicePath);
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
continue;
}
uint32 requestId = cmd->args[0];
uint32 numIn = cmd->args[1];
uint32 numOut = cmd->args[2];
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();
IPCIoctlVector* vecIn = vec + 0; // the ordering of vecIn/vecOut differs from IPCService
IPCIoctlVector* vecOut = vec + numIn;
m_delayResponse = false;
m_activeCmd = cmd;
uint32 result = ServiceCall(clientObject, requestId, vecIn, numIn, vecOut, numOut);
if (!m_delayResponse)
IOS_ResourceReply(cmd, (IOS_ERROR)result);
m_activeCmd = nullptr;
continue;
}
else
{
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Unsupported IPC cmdId {}", m_devicePath, (uint32)cmd->cmdId.value());
cemu_assert_unimplemented();
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
}
}
IOS_DestroyMessageQueue(m_msgQueueId);
m_threadInitialized = false;
}
void IPCSimpleService::SetTimerUpdate(uint32 milliseconds)
{
if(m_timerId != IOSInvalidTimerId)
IOS_DestroyTimer(m_timerId);
m_timerId = IOS_CreateTimer(milliseconds * 1000, milliseconds * 1000, m_msgQueueId, 1);
}
IPCCommandBody* IPCSimpleService::ServiceCallDelayCurrentResponse()
{
cemu_assert_debug(m_activeCmd);
m_delayResponse = true;
return m_activeCmd;
}
void IPCSimpleService::ServiceCallAsyncRespond(IPCCommandBody* response, uint32 r)
{
IOS_ResourceReply(response, (IOS_ERROR)r);
}
/* IPCService */
void IPCService::Start() void IPCService::Start()
{ {
if (m_isRunning.exchange(true)) if (m_isRunning.exchange(true))

View File

@ -8,6 +8,71 @@ namespace iosu
{ {
namespace nn namespace nn
{ {
// a simple service interface which wraps handle management and Ioctlv/IoctlvAsync
class IPCSimpleService
{
public:
IPCSimpleService(std::string_view devicePath) : m_devicePath(devicePath) {};
virtual ~IPCSimpleService() {};
virtual void StartService() {};
virtual void StopService() {};
virtual std::string GetThreadName() = 0;
virtual void* CreateClientObject() = 0;
virtual void DestroyClientObject(void* clientObject) = 0;
virtual uint32 ServiceCall(void* clientObject, uint32 requestId, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut) = 0;
virtual void TimerUpdate() {};
IPCCommandBody* ServiceCallDelayCurrentResponse();
static void ServiceCallAsyncRespond(IPCCommandBody* response, uint32 r);
void Start();
void Stop();
void SetTimerUpdate(uint32 milliseconds);
private:
void ServiceThread();
IOSDevHandle GetFreeHandle()
{
while(m_clientObjects.find(m_nextHandle) != m_clientObjects.end() || m_nextHandle == 0)
{
m_nextHandle++;
m_nextHandle &= 0x7FFFFFFF;
}
IOSDevHandle newHandle = m_nextHandle;
m_nextHandle++;
m_nextHandle &= 0x7FFFFFFF;
return newHandle;
}
void* GetClientObjectByHandle(IOSDevHandle handle) const
{
auto it = m_clientObjects.find(handle);
if(it == m_clientObjects.end())
return nullptr;
return it->second;
}
std::string m_devicePath;
std::thread m_serviceThread;
std::atomic_bool m_requestStop{false};
std::atomic_bool m_isRunning{false};
std::atomic_bool m_threadInitialized{ false };
std::unordered_map<IOSDevHandle, void*> m_clientObjects;
IOSDevHandle m_nextHandle{1};
IOSTimerId m_timerId{IOSInvalidTimerId};
IPCCommandBody* m_activeCmd{nullptr};
bool m_delayResponse{false};
IOSMsgQueueId m_msgQueueId;
SysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer;
};
struct IPCServiceRequest struct IPCServiceRequest
{ {
uint32be ukn00; uint32be ukn00;
@ -23,6 +88,7 @@ namespace iosu
uint32be nnResultCode; uint32be nnResultCode;
}; };
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, ?
class IPCService class IPCService
{ {
public: public:
@ -60,5 +126,6 @@ namespace iosu
IOSMsgQueueId m_msgQueueId; IOSMsgQueueId m_msgQueueId;
SysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer; SysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer;
}; };
}; };
}; };

View File

@ -724,7 +724,7 @@ uint32 RPLLoader_MakePPCCallable(void(*ppcCallableExport)(PPCInterpreter_t* hCPU
if (it != g_map_callableExports.end()) if (it != g_map_callableExports.end())
return it->second; return it->second;
// get HLE function index // get HLE function index
sint32 functionIndex = PPCInterpreter_registerHLECall(ppcCallableExport); sint32 functionIndex = PPCInterpreter_registerHLECall(ppcCallableExport, fmt::format("PPCCallback{:x}", (uintptr_t)ppcCallableExport));
MPTR codeAddr = memory_getVirtualOffsetFromPointer(RPLLoader_AllocateTrampolineCodeSpace(4)); MPTR codeAddr = memory_getVirtualOffsetFromPointer(RPLLoader_AllocateTrampolineCodeSpace(4));
uint32 opcode = (1 << 26) | functionIndex; uint32 opcode = (1 << 26) | functionIndex;
memory_write<uint32>(codeAddr, opcode); memory_write<uint32>(codeAddr, opcode);

View File

@ -85,6 +85,7 @@ void osLib_addFunctionInternal(const char* libraryName, const char* functionName
uint32 funcHashA, funcHashB; uint32 funcHashA, funcHashB;
osLib_generateHashFromName(libraryName, &libHashA, &libHashB); osLib_generateHashFromName(libraryName, &libHashA, &libHashB);
osLib_generateHashFromName(functionName, &funcHashA, &funcHashB); osLib_generateHashFromName(functionName, &funcHashA, &funcHashB);
std::string hleName = fmt::format("{}.{}", libraryName, functionName);
// if entry already exists, update it // if entry already exists, update it
for (auto& it : *s_osFunctionTable) for (auto& it : *s_osFunctionTable)
{ {
@ -93,11 +94,11 @@ void osLib_addFunctionInternal(const char* libraryName, const char* functionName
it.funcHashA == funcHashA && it.funcHashA == funcHashA &&
it.funcHashB == funcHashB) it.funcHashB == funcHashB)
{ {
it.hleFunc = PPCInterpreter_registerHLECall(osFunction); it.hleFunc = PPCInterpreter_registerHLECall(osFunction, hleName);
return; return;
} }
} }
s_osFunctionTable->emplace_back(libHashA, libHashB, funcHashA, funcHashB, fmt::format("{}.{}", libraryName, functionName), PPCInterpreter_registerHLECall(osFunction)); s_osFunctionTable->emplace_back(libHashA, libHashB, funcHashA, funcHashB, hleName, PPCInterpreter_registerHLECall(osFunction, hleName));
} }
extern "C" DLLEXPORT void osLib_registerHLEFunction(const char* libraryName, const char* functionName, void(*osFunction)(PPCInterpreter_t * hCPU)) extern "C" DLLEXPORT void osLib_registerHLEFunction(const char* libraryName, const char* functionName, void(*osFunction)(PPCInterpreter_t * hCPU))

View File

@ -912,8 +912,8 @@ namespace coreinit
sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling) sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSOpenFileAsync(fsClient, fsCmdBlock, path, mode, fileHandle, errHandling, asyncParams); sint32 fsAsyncRet = FSOpenFileAsync(fsClient, fsCmdBlock, path, mode, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
} }
@ -941,8 +941,8 @@ namespace coreinit
sint32 FSOpenFileEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandleDepr_t* fileHandle, uint32 errHandling) sint32 FSOpenFileEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandleDepr_t* fileHandle, uint32 errHandling)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSOpenFileExAsync(fsClient, fsCmdBlock, path, mode, createMode, openFlag, preallocSize, fileHandle, errHandling, asyncParams); sint32 fsAsyncRet = FSOpenFileExAsync(fsClient, fsCmdBlock, path, mode, createMode, openFlag, preallocSize, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
} }
@ -975,8 +975,8 @@ namespace coreinit
sint32 FSCloseFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling) sint32 FSCloseFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSCloseFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, asyncParams); sint32 fsAsyncRet = FSCloseFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
} }
@ -1009,8 +1009,8 @@ namespace coreinit
sint32 FSFlushFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling) sint32 FSFlushFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSFlushFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, asyncParams); sint32 fsAsyncRet = FSFlushFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
} }
@ -1090,7 +1090,7 @@ namespace coreinit
sint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask) sint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSReadFileAsync(fsClient, fsCmdBlock, dst, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSReadFileAsync(fsClient, fsCmdBlock, dst, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1105,7 +1105,7 @@ namespace coreinit
sint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask) sint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSReadFileWithPosAsync(fsClient, fsCmdBlock, dst, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSReadFileWithPosAsync(fsClient, fsCmdBlock, dst, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1183,7 +1183,7 @@ namespace coreinit
sint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask) sint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSWriteFileAsync(fsClient, fsCmdBlock, src, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSWriteFileAsync(fsClient, fsCmdBlock, src, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1196,7 +1196,7 @@ namespace coreinit
sint32 FSWriteFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask) sint32 FSWriteFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1228,7 +1228,7 @@ namespace coreinit
{ {
// used by games: Mario Kart 8 // used by games: Mario Kart 8
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSSetPosFileAsync(fsClient, fsCmdBlock, fileHandle, filePos, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSSetPosFileAsync(fsClient, fsCmdBlock, fileHandle, filePos, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1259,7 +1259,7 @@ namespace coreinit
sint32 FSGetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask) sint32 FSGetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetPosFileAsync(fsClient, fsCmdBlock, fileHandle, returnedFilePos, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSGetPosFileAsync(fsClient, fsCmdBlock, fileHandle, returnedFilePos, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1307,8 +1307,8 @@ namespace coreinit
sint32 FSOpenDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask) sint32 FSOpenDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSOpenDirAsync(fsClient, fsCmdBlock, path, dirHandleOut, errorMask, asyncParams); sint32 fsAsyncRet = FSOpenDirAsync(fsClient, fsCmdBlock, path, dirHandleOut, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1337,8 +1337,8 @@ namespace coreinit
sint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) sint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSReadDirAsync(fsClient, fsCmdBlock, dirHandle, dirEntryOut, errorMask, asyncParams); sint32 fsAsyncRet = FSReadDirAsync(fsClient, fsCmdBlock, dirHandle, dirEntryOut, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1367,8 +1367,8 @@ namespace coreinit
sint32 FSCloseDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask) sint32 FSCloseDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSCloseDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, asyncParams); sint32 fsAsyncRet = FSCloseDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1400,8 +1400,8 @@ namespace coreinit
sint32 FSRewindDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask) sint32 FSRewindDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSRewindDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, asyncParams); sint32 fsAsyncRet = FSRewindDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1435,7 +1435,7 @@ namespace coreinit
sint32 FSAppendFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask) sint32 FSAppendFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSAppendFileAsync(fsClient, fsCmdBlock, size, count, fileHandle, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSAppendFileAsync(fsClient, fsCmdBlock, size, count, fileHandle, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1467,7 +1467,7 @@ namespace coreinit
sint32 FSTruncateFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask) sint32 FSTruncateFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSTruncateFileAsync(fsClient, fsCmdBlock, fileHandle, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSTruncateFileAsync(fsClient, fsCmdBlock, fileHandle, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1531,7 +1531,7 @@ namespace coreinit
sint32 FSRename(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask) sint32 FSRename(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSRenameAsync(fsClient, fsCmdBlock, srcPath, dstPath, errorMask, asyncParams.GetPointer()); sint32 fsAsyncRet = FSRenameAsync(fsClient, fsCmdBlock, srcPath, dstPath, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1582,8 +1582,8 @@ namespace coreinit
sint32 FSRemove(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask) sint32 FSRemove(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSRemoveAsync(fsClient, fsCmdBlock, filePath, errorMask, asyncParams); sint32 fsAsyncRet = FSRemoveAsync(fsClient, fsCmdBlock, filePath, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1634,8 +1634,8 @@ namespace coreinit
sint32 FSMakeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, uint32 errorMask) sint32 FSMakeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSMakeDirAsync(fsClient, fsCmdBlock, path, errorMask, asyncParams); sint32 fsAsyncRet = FSMakeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1683,8 +1683,8 @@ namespace coreinit
sint32 FSChangeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask) sint32 FSChangeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSChangeDirAsync(fsClient, fsCmdBlock, path, errorMask, asyncParams); sint32 fsAsyncRet = FSChangeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1718,8 +1718,8 @@ namespace coreinit
sint32 FSGetCwd(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask) sint32 FSGetCwd(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetCwdAsync(fsClient, fsCmdBlock, dirPathOut, dirPathMaxLen, errorMask, asyncParams); sint32 fsAsyncRet = FSGetCwdAsync(fsClient, fsCmdBlock, dirPathOut, dirPathMaxLen, errorMask, &asyncParams);
auto r = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); auto r = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
return r; return r;
} }
@ -1763,8 +1763,8 @@ namespace coreinit
sint32 FSFlushQuota(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask) sint32 FSFlushQuota(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t> asyncParams; StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSFlushQuotaAsync(fsClient, fsCmdBlock, path, errorMask, asyncParams); sint32 fsAsyncRet = FSFlushQuotaAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1821,8 +1821,8 @@ namespace coreinit
sint32 FSGetStat(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask) sint32 FSGetStat(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetStatAsync(fsClient, fsCmdBlock, path, statOut, errorMask, asyncParams); sint32 fsAsyncRet = FSGetStatAsync(fsClient, fsCmdBlock, path, statOut, errorMask, &asyncParams);
sint32 ret = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); sint32 ret = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
return ret; return ret;
} }
@ -1858,8 +1858,8 @@ namespace coreinit
sint32 FSGetStatFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask) sint32 FSGetStatFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetStatFileAsync(fsClient, fsCmdBlock, fileHandle, statOut, errorMask, asyncParams); sint32 fsAsyncRet = FSGetStatFileAsync(fsClient, fsCmdBlock, fileHandle, statOut, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1873,8 +1873,8 @@ namespace coreinit
sint32 FSGetFreeSpaceSize(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask) sint32 FSGetFreeSpaceSize(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetFreeSpaceSizeAsync(fsClient, fsCmdBlock, path, returnedFreeSize, errorMask, asyncParams); sint32 fsAsyncRet = FSGetFreeSpaceSizeAsync(fsClient, fsCmdBlock, path, returnedFreeSize, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }
@ -1908,8 +1908,8 @@ namespace coreinit
sint32 FSIsEof(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask) sint32 FSIsEof(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask)
{ {
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams; StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams); __FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSIsEofAsync(fsClient, fsCmdBlock, fileHandle, errorMask, asyncParams); sint32 fsAsyncRet = FSIsEofAsync(fsClient, fsCmdBlock, fileHandle, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
} }

View File

@ -355,23 +355,6 @@ namespace coreinit
IOS_ERROR _IPCDriver_SetupCmd_IOSIoctlv(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec) IOS_ERROR _IPCDriver_SetupCmd_IOSIoctlv(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec)
{ {
IPCCommandBody& cmdBody = requestDescriptor->resourcePtr->commandBody; IPCCommandBody& cmdBody = requestDescriptor->resourcePtr->commandBody;
// verify input and output vectors
IPCIoctlVector* vecIn = vec;
IPCIoctlVector* vecOut = vec + numIn;
for (uint32 i = 0; i < numIn; i++)
{
if (vecIn[i].baseVirt == nullptr && vecIn[i].size != 0)
return IOS_ERROR_INVALID_ARG;
vecIn[i].basePhys = vecIn[i].baseVirt;
vecIn[i].baseVirt = nullptr;
}
for (uint32 i = 0; i < numOut; i++)
{
if (vecOut[i].baseVirt == nullptr && vecOut[i].size != 0)
return IOS_ERROR_INVALID_ARG;
vecOut[i].basePhys = vecOut[i].baseVirt;
vecOut[i].baseVirt = nullptr;
}
// set args // set args
cmdBody.ppcVirt0 = MEMPTR<void>(vec).GetMPTR(); cmdBody.ppcVirt0 = MEMPTR<void>(vec).GetMPTR();
cmdBody.args[0] = requestId; cmdBody.args[0] = requestId;

View File

@ -195,7 +195,28 @@ namespace coreinit
else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && (formatStr[2] == 'x' || formatStr[2] == 'X'))) else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && (formatStr[2] == 'x' || formatStr[2] == 'X')))
{ {
formatStr += 3; formatStr += 3;
// number (64bit) // double (64bit)
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
if ((formatStr - formatStart) < sizeof(tempFormat))
tempFormat[(formatStr - formatStart)] = '\0';
else
tempFormat[sizeof(tempFormat) - 1] = '\0';
if (integerParamIndex & 1)
integerParamIndex++;
sint32 tempLen = sprintf(tempStr, tempFormat, PPCInterpreter_getCallParamU64(hCPU, integerParamIndex));
integerParamIndex += 2;
for (sint32 i = 0; i < tempLen; i++)
{
if (writeIndex >= maxLength)
break;
strOut[writeIndex] = tempStr[i];
writeIndex++;
}
}
else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && formatStr[2] == 'd'))
{
formatStr += 3;
// signed integer (64bit)
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart)); strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
if ((formatStr - formatStart) < sizeof(tempFormat)) if ((formatStr - formatStart) < sizeof(tempFormat))
tempFormat[(formatStr - formatStart)] = '\0'; tempFormat[(formatStr - formatStart)] = '\0';

View File

@ -859,10 +859,10 @@ namespace H264
return H264DEC_STATUS::SUCCESS; return H264DEC_STATUS::SUCCESS;
} }
StackAllocator<coreinit::OSEvent> executeDoneEvent; StackAllocator<coreinit::OSEvent> executeDoneEvent;
coreinit::OSInitEvent(executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::vector<H264AVCDecoder::DecodeResult> results; std::vector<H264AVCDecoder::DecodeResult> results;
auto asyncTask = std::async(std::launch::async, _async_H264DECEnd, executeDoneEvent.GetPointer(), session, ctx, &results); auto asyncTask = std::async(std::launch::async, _async_H264DECEnd, executeDoneEvent.GetPointer(), session, ctx, &results);
coreinit::OSWaitEvent(executeDoneEvent); coreinit::OSWaitEvent(&executeDoneEvent);
_ReleaseDecoderSession(session); _ReleaseDecoderSession(session);
if (!results.empty()) if (!results.empty())
{ {
@ -977,9 +977,9 @@ namespace H264
StackAllocator<H264DECFrameOutput, 8> stack_decodedFrameResult; StackAllocator<H264DECFrameOutput, 8> stack_decodedFrameResult;
for (sint32 i = 0; i < outputFrameCount; i++) for (sint32 i = 0; i < outputFrameCount; i++)
stack_resultPtrArray[i] = stack_decodedFrameResult + i; stack_resultPtrArray[i] = &stack_decodedFrameResult + i;
H264DECFrameOutput* frameOutput = stack_decodedFrameResult + 0; H264DECFrameOutput* frameOutput = &stack_decodedFrameResult + 0;
memset(frameOutput, 0x00, sizeof(H264DECFrameOutput)); memset(frameOutput, 0x00, sizeof(H264DECFrameOutput));
frameOutput->imagePtr = (uint8*)decodeResult.imageOutput; frameOutput->imagePtr = (uint8*)decodeResult.imageOutput;
frameOutput->result = 100; frameOutput->result = 100;
@ -1022,10 +1022,10 @@ namespace H264
return 0; return 0;
} }
StackAllocator<coreinit::OSEvent> executeDoneEvent; StackAllocator<coreinit::OSEvent> executeDoneEvent;
coreinit::OSInitEvent(executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
H264AVCDecoder::DecodeResult decodeResult; H264AVCDecoder::DecodeResult decodeResult;
auto asyncTask = std::async(std::launch::async, _async_H264DECExecute, executeDoneEvent.GetPointer(), session, ctx, imageOutput , &decodeResult); auto asyncTask = std::async(std::launch::async, _async_H264DECExecute, &executeDoneEvent, session, ctx, imageOutput , &decodeResult);
coreinit::OSWaitEvent(executeDoneEvent); coreinit::OSWaitEvent(&executeDoneEvent);
_ReleaseDecoderSession(session); _ReleaseDecoderSession(session);
if(decodeResult.frameReady) if(decodeResult.frameReady)
H264DoFrameOutputCallback(ctx, decodeResult); H264DoFrameOutputCallback(ctx, decodeResult);

View File

@ -391,7 +391,7 @@ void nnActExport_GetMiiName(PPCInterpreter_t* hCPU)
StackAllocator<FFLData_t> miiData; StackAllocator<FFLData_t> miiData;
uint32 r = nn::act::GetMiiEx(miiData, iosu::act::ACT_SLOT_CURRENT); uint32 r = nn::act::GetMiiEx(&miiData, iosu::act::ACT_SLOT_CURRENT);
// extract name // extract name
sint32 miiNameLength = 0; sint32 miiNameLength = 0;
for (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++) for (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++)
@ -414,7 +414,7 @@ void nnActExport_GetMiiNameEx(PPCInterpreter_t* hCPU)
StackAllocator<FFLData_t> miiData; StackAllocator<FFLData_t> miiData;
uint32 r = nn::act::GetMiiEx(miiData, slot); uint32 r = nn::act::GetMiiEx(&miiData, slot);
// extract name // extract name
sint32 miiNameLength = 0; sint32 miiNameLength = 0;
for (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++) for (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++)

File diff suppressed because it is too large Load Diff

View File

@ -47,10 +47,10 @@ namespace nn
InitializeOliveRequest(req); InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent; StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, DownloadCommunityDataList_AsyncRequest, std::future<sint32> requestRes = std::async(std::launch::async, DownloadCommunityDataList_AsyncRequest,
std::ref(req), reqUrl, requestDoneEvent.GetPointer(), pOutList, pOutNum, numMaxList, pParam); std::ref(req), reqUrl, requestDoneEvent.GetPointer(), pOutList, pOutNum, numMaxList, pParam);
coreinit::OSWaitEvent(requestDoneEvent); coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get(); return requestRes.get();
} }

View File

@ -199,9 +199,9 @@ namespace nn
InitializeOliveRequest(req); InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent; StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, MakeDiscoveryRequest_AsyncRequest, std::ref(req), requestUrl.c_str(), requestDoneEvent.GetPointer()); std::future<sint32> requestRes = std::async(std::launch::async, MakeDiscoveryRequest_AsyncRequest, std::ref(req), requestUrl.c_str(), requestDoneEvent.GetPointer());
coreinit::OSWaitEvent(requestDoneEvent); coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get(); return requestRes.get();
} }

View File

@ -25,7 +25,7 @@ namespace nn
// open archive // open archive
g_offlineDBArchive = ZArchiveReader::OpenFromFile(ActiveSettings::GetUserDataPath("resources/miiverse/OfflineDB.zar")); g_offlineDBArchive = ZArchiveReader::OpenFromFile(ActiveSettings::GetUserDataPath("resources/miiverse/OfflineDB.zar"));
if(!g_offlineDBArchive) if(!g_offlineDBArchive)
cemuLog_log(LogType::Force, "Failed to open resources/miiverse/OfflineDB.zar. Miiverse posts will not be available"); cemuLog_log(LogType::Force, "Offline miiverse posts are not available");
g_offlineDBInitialized = true; g_offlineDBInitialized = true;
} }
@ -175,9 +175,9 @@ namespace nn
return OLV_RESULT_SUCCESS; // the offlineDB doesn't contain any self posts return OLV_RESULT_SUCCESS; // the offlineDB doesn't contain any self posts
StackAllocator<coreinit::OSEvent> doneEvent; StackAllocator<coreinit::OSEvent> doneEvent;
coreinit::OSInitEvent(doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
auto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadPostDataList, doneEvent.GetPointer(), downloadedTopicData, downloadedPostData, postCountOut, maxCount, param); auto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadPostDataList, doneEvent.GetPointer(), downloadedTopicData, downloadedPostData, postCountOut, maxCount, param);
coreinit::OSWaitEvent(doneEvent); coreinit::OSWaitEvent(&doneEvent);
nnResult r = asyncTask.get(); nnResult r = asyncTask.get();
return r; return r;
} }
@ -204,9 +204,9 @@ namespace nn
nnResult OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize) nnResult OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize)
{ {
StackAllocator<coreinit::OSEvent> doneEvent; StackAllocator<coreinit::OSEvent> doneEvent;
coreinit::OSInitEvent(doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
auto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadExternalImageData, doneEvent.GetPointer(), _this, imageDataOut, imageSizeOut, maxSize); auto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadExternalImageData, doneEvent.GetPointer(), _this, imageDataOut, imageSizeOut, maxSize);
coreinit::OSWaitEvent(doneEvent); coreinit::OSWaitEvent(&doneEvent);
nnResult r = asyncTask.get(); nnResult r = asyncTask.get();
return r; return r;
} }

View File

@ -54,9 +54,9 @@ namespace nn
InitializeOliveRequest(req); InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent; StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, UploadCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam); std::future<sint32> requestRes = std::async(std::launch::async, UploadCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam);
coreinit::OSWaitEvent(requestDoneEvent); coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get(); return requestRes.get();
} }

View File

@ -44,9 +44,9 @@ namespace nn
InitializeOliveRequest(req); InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent; StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL); coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, UploadFavoriteToCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam); std::future<sint32> requestRes = std::async(std::launch::async, UploadFavoriteToCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam);
coreinit::OSWaitEvent(requestDoneEvent); coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get(); return requestRes.get();
} }

View File

@ -43,6 +43,7 @@ const std::map<LogType, std::string> g_logging_window_mapping
{LogType::CoreinitMP, "Coreinit MP"}, {LogType::CoreinitMP, "Coreinit MP"},
{LogType::CoreinitThread, "Coreinit Thread"}, {LogType::CoreinitThread, "Coreinit Thread"},
{LogType::NN_NFP, "nn::nfp"}, {LogType::NN_NFP, "nn::nfp"},
{LogType::NN_FP, "nn::fp"},
{LogType::GX2, "GX2"}, {LogType::GX2, "GX2"},
{LogType::SoundAPI, "Audio"}, {LogType::SoundAPI, "Audio"},
{LogType::InputAPI, "Input"}, {LogType::InputAPI, "Input"},

View File

@ -34,6 +34,7 @@ enum class LogType : sint32
NN_PDM = 21, NN_PDM = 21,
NN_OLV = 23, NN_OLV = 23,
NN_NFP = 13, NN_NFP = 13,
NN_FP = 24,
TextureReadback = 29, TextureReadback = 29,

View File

@ -358,7 +358,7 @@ namespace NAPI
std::string_view port = tokenNode.child_value("port"); std::string_view port = tokenNode.child_value("port");
std::string_view token = tokenNode.child_value("token"); std::string_view token = tokenNode.child_value("token");
std::memset(&result.nexToken, 0, sizeof(result.nexToken)); memset(&result.nexToken, 0, sizeof(ACTNexToken));
if (host.size() > 15) if (host.size() > 15)
cemuLog_log(LogType::Force, "NexToken response: host field too long"); cemuLog_log(LogType::Force, "NexToken response: host field too long");
if (nex_password.size() > 64) if (nex_password.size() > 64)

View File

@ -160,11 +160,10 @@ bool nexService::isMarkedForDestruction()
void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, void(*nexServiceResponse)(nexService* nex, nexServiceResponse_t* serviceResponse), void* custom, bool callHandlerIfError) void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, void(*nexServiceResponse)(nexService* nex, nexServiceResponse_t* serviceResponse), void* custom, bool callHandlerIfError)
{ {
// add to queue
queuedRequest_t queueRequest = { 0 }; queuedRequest_t queueRequest = { 0 };
queueRequest.protocolId = protocolId; queueRequest.protocolId = protocolId;
queueRequest.methodId = methodId; queueRequest.methodId = methodId;
queueRequest.parameterData = std::vector<uint8>(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex()); queueRequest.parameterData.assign(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());
queueRequest.nexServiceResponse = nexServiceResponse; queueRequest.nexServiceResponse = nexServiceResponse;
queueRequest.custom = custom; queueRequest.custom = custom;
queueRequest.callHandlerIfError = callHandlerIfError; queueRequest.callHandlerIfError = callHandlerIfError;
@ -175,11 +174,10 @@ void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer*
void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, std::function<void(nexServiceResponse_t*)> cb, bool callHandlerIfError) void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, std::function<void(nexServiceResponse_t*)> cb, bool callHandlerIfError)
{ {
// add to queue
queuedRequest_t queueRequest = { 0 }; queuedRequest_t queueRequest = { 0 };
queueRequest.protocolId = protocolId; queueRequest.protocolId = protocolId;
queueRequest.methodId = methodId; queueRequest.methodId = methodId;
queueRequest.parameterData = std::vector<uint8>(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex()); queueRequest.parameterData.assign(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());
queueRequest.nexServiceResponse = nullptr; queueRequest.nexServiceResponse = nullptr;
queueRequest.cb2 = cb; queueRequest.cb2 = cb;
queueRequest.callHandlerIfError = callHandlerIfError; queueRequest.callHandlerIfError = callHandlerIfError;

View File

@ -274,8 +274,7 @@ void NexFriends::handleResponse_getAllInformation(nexServiceResponse_t* response
return; return;
} }
NexFriends* session = (NexFriends*)nexFriends; NexFriends* session = (NexFriends*)nexFriends;
session->myPreference = nexPrincipalPreference(&response->data);
nexPrincipalPreference preference(&response->data);
nexComment comment(&response->data); nexComment comment(&response->data);
if (response->data.hasReadOutOfBounds()) if (response->data.hasReadOutOfBounds())
return; return;
@ -290,29 +289,21 @@ void NexFriends::handleResponse_getAllInformation(nexServiceResponse_t* response
uint32 friendCount = response->data.readU32(); uint32 friendCount = response->data.readU32();
session->list_friends.resize(friendCount); session->list_friends.resize(friendCount);
for (uint32 i = 0; i < friendCount; i++) for (uint32 i = 0; i < friendCount; i++)
{
session->list_friends[i].readData(&response->data); session->list_friends[i].readData(&response->data);
}
// friend requests (outgoing) // friend requests (outgoing)
uint32 friendRequestsOutCount = response->data.readU32(); uint32 friendRequestsOutCount = response->data.readU32();
if (response->data.hasReadOutOfBounds()) if (response->data.hasReadOutOfBounds())
{
return; return;
}
session->list_friendReqOutgoing.resize(friendRequestsOutCount); session->list_friendReqOutgoing.resize(friendRequestsOutCount);
for (uint32 i = 0; i < friendRequestsOutCount; i++) for (uint32 i = 0; i < friendRequestsOutCount; i++)
{
session->list_friendReqOutgoing[i].readData(&response->data); session->list_friendReqOutgoing[i].readData(&response->data);
}
// friend requests (incoming) // friend requests (incoming)
uint32 friendRequestsInCount = response->data.readU32(); uint32 friendRequestsInCount = response->data.readU32();
if (response->data.hasReadOutOfBounds()) if (response->data.hasReadOutOfBounds())
return; return;
session->list_friendReqIncoming.resize(friendRequestsInCount); session->list_friendReqIncoming.resize(friendRequestsInCount);
for (uint32 i = 0; i < friendRequestsInCount; i++) for (uint32 i = 0; i < friendRequestsInCount; i++)
{
session->list_friendReqIncoming[i].readData(&response->data); session->list_friendReqIncoming[i].readData(&response->data);
}
if (response->data.hasReadOutOfBounds()) if (response->data.hasReadOutOfBounds())
return; return;
// blacklist // blacklist
@ -336,7 +327,7 @@ void NexFriends::handleResponse_getAllInformation(nexServiceResponse_t* response
if (isPreferenceInvalid) if (isPreferenceInvalid)
{ {
cemuLog_log(LogType::Force, "NEX: First time login into friend account, setting up default preferences"); cemuLog_log(LogType::Force, "NEX: First time login into friend account, setting up default preferences");
session->updatePreferences(nexPrincipalPreference(1, 1, 0)); session->updatePreferencesAsync(nexPrincipalPreference(1, 1, 0), [](RpcErrorCode err){});
} }
if (session->firstInformationRequest == false) if (session->firstInformationRequest == false)
@ -377,20 +368,27 @@ bool NexFriends::requestGetAllInformation(std::function<void(uint32)> cb)
return true; return true;
} }
void NexFriends::handleResponse_updatePreferences(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb) bool NexFriends::updatePreferencesAsync(nexPrincipalPreference newPreferences, std::function<void(RpcErrorCode)> cb)
{
// todo
}
bool NexFriends::updatePreferences(const nexPrincipalPreference& newPreferences)
{ {
uint8 tempNexBufferArray[1024]; uint8 tempNexBufferArray[1024];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
newPreferences.writeData(&packetBuffer); newPreferences.writeData(&packetBuffer);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 16, &packetBuffer, std::bind(handleResponse_updatePreferences, std::placeholders::_1, this, nullptr), true); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 16, &packetBuffer, [this, cb, newPreferences](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
this->myPreference = newPreferences;
return cb(NexFriends::ERR_NONE);
}, true);
// TEST
return true; return true;
} }
void NexFriends::getMyPreference(nexPrincipalPreference& preference)
{
preference = myPreference;
}
bool NexFriends::addProvisionalFriendByPidGuessed(uint32 principalId) bool NexFriends::addProvisionalFriendByPidGuessed(uint32 principalId)
{ {
uint8 tempNexBufferArray[512]; uint8 tempNexBufferArray[512];
@ -401,6 +399,7 @@ bool NexFriends::addProvisionalFriendByPidGuessed(uint32 principalId)
return true; return true;
} }
// returns true once connection is established and friend list data is available
bool NexFriends::isOnline() bool NexFriends::isOnline()
{ {
return isCurrentlyConnected && hasData; return isCurrentlyConnected && hasData;
@ -683,7 +682,7 @@ bool NexFriends::getFriendRequestByPID(nexFriendRequest& friendRequestData, bool
{ {
friendRequestData = it; friendRequestData = it;
if (isIncoming) if (isIncoming)
*isIncoming = false; *isIncoming = false;
return true; return true;
} }
} }
@ -731,7 +730,7 @@ void addProvisionalFriendHandler(nexServiceResponse_t* nexResponse, std::functio
} }
} }
bool NexFriends::addProvisionalFriend(char* name, std::function<void(uint32)> cb) bool NexFriends::addProvisionalFriend(char* name, std::function<void(RpcErrorCode)> cb)
{ {
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED) if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{ {
@ -754,12 +753,11 @@ void addFriendRequestHandler(nexServiceResponse_t* nexResponse, NexFriends* nexF
{ {
// todo: Properly handle returned error code // todo: Properly handle returned error code
cb(NexFriends::ERR_RPC_FAILED); cb(NexFriends::ERR_RPC_FAILED);
// refresh the list nexFriends->requestGetAllInformation(); // refresh friend list and send add/remove notifications
nexFriends->requestGetAllInformation();
} }
} }
void NexFriends::addFriendRequest(uint32 pid, const char* comment, std::function<void(uint32)> cb) void NexFriends::addFriendRequest(uint32 pid, const char* comment, std::function<void(RpcErrorCode)> cb)
{ {
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED) if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{ {
@ -779,72 +777,31 @@ void NexFriends::addFriendRequest(uint32 pid, const char* comment, std::function
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 5, &packetBuffer, std::bind(addFriendRequestHandler, std::placeholders::_1, this, cb), true); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 5, &packetBuffer, std::bind(addFriendRequestHandler, std::placeholders::_1, this, cb), true);
} }
typedef struct void NexFriends::requestPrincipleBaseInfoByPID(uint32* pidList, sint32 count, const std::function<void(RpcErrorCode result, std::span<nexPrincipalBasicInfo> basicInfo)>& cb)
{
NEXFRIENDS_CALLBACK cb;
void* customParam;
NexFriends* nexFriends;
// command specific
struct
{
nexPrincipalBasicInfo* basicInfo;
sint32 count;
}principalBaseInfo;
}nexFriendsCallInfo_t;
void NexFriends_handleResponse_requestPrincipleBaseInfoByPID(nexService* nex, nexServiceResponse_t* response)
{
nexFriendsCallInfo_t* callInfo = (nexFriendsCallInfo_t*)response->custom;
if (response->isSuccessful == false)
{
// handle error case
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_RPC_FAILED, callInfo->customParam);
free(callInfo);
return;
}
// process result
uint32 count = response->data.readU32();
if (count != callInfo->principalBaseInfo.count)
{
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_UNEXPECTED_RESULT, callInfo->customParam);
free(callInfo);
return;
}
for (uint32 i = 0; i < count; i++)
{
callInfo->principalBaseInfo.basicInfo[i].readData(&response->data);
}
if (response->data.hasReadOutOfBounds())
{
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_UNEXPECTED_RESULT, callInfo->customParam);
free(callInfo);
return;
}
// callback
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_NONE, callInfo->customParam);
free(callInfo);
}
void NexFriends::requestPrincipleBaseInfoByPID(nexPrincipalBasicInfo* basicInfo, uint32* pidList, sint32 count, NEXFRIENDS_CALLBACK cb, void* customParam)
{ {
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED) if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{ return cb(ERR_NOT_CONNECTED, {});
// not connected
cb(this, ERR_NOT_CONNECTED, customParam);
return;
}
uint8 tempNexBufferArray[512]; uint8 tempNexBufferArray[512];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(count); packetBuffer.writeU32(count);
for(sint32 i=0; i<count; i++) for(sint32 i=0; i<count; i++)
packetBuffer.writeU32(pidList[i]); packetBuffer.writeU32(pidList[i]);
nexFriendsCallInfo_t* callInfo = (nexFriendsCallInfo_t*)malloc(sizeof(nexFriendsCallInfo_t)); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 17, &packetBuffer, [cb, count](nexServiceResponse_t* response)
callInfo->principalBaseInfo.basicInfo = basicInfo; {
callInfo->principalBaseInfo.count = count; if (!response->isSuccessful)
callInfo->cb = cb; return cb(NexFriends::ERR_RPC_FAILED, {});
callInfo->customParam = customParam; // process result
callInfo->nexFriends = this; uint32 resultCount = response->data.readU32();
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 17, &packetBuffer, NexFriends_handleResponse_requestPrincipleBaseInfoByPID, callInfo, true); if (resultCount != count)
return cb(NexFriends::ERR_UNEXPECTED_RESULT, {});
std::vector<nexPrincipalBasicInfo> nexBasicInfo;
nexBasicInfo.resize(count);
for (uint32 i = 0; i < resultCount; i++)
nexBasicInfo[i].readData(&response->data);
if (response->data.hasReadOutOfBounds())
return cb(NexFriends::ERR_UNEXPECTED_RESULT, {});
return cb(NexFriends::ERR_NONE, nexBasicInfo);
}, true);
} }
void genericFriendServiceNoResponseHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb) void genericFriendServiceNoResponseHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb)
@ -858,7 +815,7 @@ void genericFriendServiceNoResponseHandler(nexServiceResponse_t* nexResponse, st
} }
} }
void NexFriends::removeFriend(uint32 pid, std::function<void(uint32)> cb) void NexFriends::removeFriend(uint32 pid, std::function<void(RpcErrorCode)> cb)
{ {
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED) if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{ {
@ -869,10 +826,20 @@ void NexFriends::removeFriend(uint32 pid, std::function<void(uint32)> cb)
uint8 tempNexBufferArray[512]; uint8 tempNexBufferArray[512];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(pid); packetBuffer.writeU32(pid);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, std::bind(genericFriendServiceNoResponseHandler, std::placeholders::_1, cb), true); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, [this, cb](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
else
{
cb(NexFriends::ERR_NONE);
this->requestGetAllInformation(); // refresh friend list and send add/remove notifications
return;
}
}, true);
} }
void NexFriends::cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(uint32)> cb) void NexFriends::cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(RpcErrorCode)> cb)
{ {
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED) if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{ {
@ -883,53 +850,63 @@ void NexFriends::cancelOutgoingProvisionalFriendRequest(uint32 pid, std::functio
uint8 tempNexBufferArray[512]; uint8 tempNexBufferArray[512];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(pid); packetBuffer.writeU32(pid);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, std::bind(genericFriendServiceNoResponseHandler, std::placeholders::_1, cb), true); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, [cb](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
else
return cb(NexFriends::ERR_NONE);
}, true);
} }
void NexFriends::acceptFriendRequest(uint64 messageId, std::function<void(uint32)> cb) void NexFriends::acceptFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb)
{ {
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED) if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{ return cb(ERR_NOT_CONNECTED);
// not connected
cb(ERR_NOT_CONNECTED);
return;
}
uint8 tempNexBufferArray[128]; uint8 tempNexBufferArray[128];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU64(messageId); packetBuffer.writeU64(messageId);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 7, &packetBuffer, std::bind(genericFriendServiceNoResponseHandler, std::placeholders::_1, cb), true); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 7, &packetBuffer, [cb](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
else
return cb(NexFriends::ERR_NONE);
}, true);
} }
void markFriendRequestsAsReceivedHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb) void NexFriends::deleteFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb)
{
if (nexResponse->isSuccessful)
cb(0);
else
{
// todo: Properly handle returned error code
cb(NexFriends::ERR_RPC_FAILED);
}
}
void NexFriends::markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(uint32)> cb)
{ {
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED) if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{ return cb(ERR_NOT_CONNECTED);
// not connected uint8 tempNexBufferArray[128];
cb(ERR_NOT_CONNECTED); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
return; packetBuffer.writeU64(messageId);
} nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 8, &packetBuffer, [this, cb](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
cb(NexFriends::ERR_NONE);
this->requestGetAllInformation(); // refresh friend list and send add/remove notifications
}, true);
}
void NexFriends::markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
return cb(ERR_NOT_CONNECTED);
uint8 tempNexBufferArray[1024]; uint8 tempNexBufferArray[1024];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(count); packetBuffer.writeU32(count);
for(sint32 i=0; i<count; i++) for(sint32 i=0; i<count; i++)
packetBuffer.writeU64(messageIdList[i]); packetBuffer.writeU64(messageIdList[i]);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 10, &packetBuffer, std::bind(markFriendRequestsAsReceivedHandler, std::placeholders::_1, cb), true); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 10, &packetBuffer, [cb](nexServiceResponse_t* response) -> void
} {
if (!response->isSuccessful)
void genericFriendServiceNoResponseHandlerWithoutCB(nexServiceResponse_t* nexResponse) return cb(NexFriends::ERR_RPC_FAILED);
{ else
return cb(NexFriends::ERR_NONE);
}, true);
} }
void NexFriends::updateMyPresence(nexPresenceV2& myPresence) void NexFriends::updateMyPresence(nexPresenceV2& myPresence)
@ -943,7 +920,7 @@ void NexFriends::updateMyPresence(nexPresenceV2& myPresence)
uint8 tempNexBufferArray[1024]; uint8 tempNexBufferArray[1024];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true); nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
myPresence.writeData(&packetBuffer); myPresence.writeData(&packetBuffer);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 13, &packetBuffer, std::bind(genericFriendServiceNoResponseHandlerWithoutCB, std::placeholders::_1), false); nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 13, &packetBuffer, +[](nexServiceResponse_t* nexResponse){}, false);
} }
void NexFriends::update() void NexFriends::update()

View File

@ -248,9 +248,9 @@ public:
nexPrincipalPreference(uint8 ukn0, uint8 ukn1, uint8 ukn2) nexPrincipalPreference(uint8 ukn0, uint8 ukn1, uint8 ukn2)
{ {
this->ukn0 = ukn0; this->showOnline = ukn0;
this->ukn1 = ukn1; this->showGame = ukn1;
this->ukn2 = ukn2; this->blockFriendRequests = ukn2;
} }
nexPrincipalPreference(nexPacketBuffer* pb) nexPrincipalPreference(nexPacketBuffer* pb)
@ -260,21 +260,21 @@ public:
void writeData(nexPacketBuffer* pb) const override void writeData(nexPacketBuffer* pb) const override
{ {
pb->writeU8(ukn0); pb->writeU8(showOnline);
pb->writeU8(ukn1); pb->writeU8(showGame);
pb->writeU8(ukn2); pb->writeU8(blockFriendRequests);
} }
void readData(nexPacketBuffer* pb) override void readData(nexPacketBuffer* pb) override
{ {
ukn0 = pb->readU8(); showOnline = pb->readU8();
ukn1 = pb->readU8(); showGame = pb->readU8();
ukn2 = pb->readU8(); blockFriendRequests = pb->readU8();
} }
public: public:
uint8 ukn0; uint8 showOnline;
uint8 ukn1; uint8 showGame;
uint8 ukn2; uint8 blockFriendRequests;
}; };
class nexComment : public nexType class nexComment : public nexType
@ -505,13 +505,12 @@ public:
uint32 type; uint32 type;
std::string msg; std::string msg;
}; };
class NexFriends;
typedef void (*NEXFRIENDS_CALLBACK)(NexFriends* nexFriends, uint32 result, void* custom);
class NexFriends class NexFriends
{ {
public: public:
using RpcErrorCode = int; // replace with enum class later
static const int ERR_NONE = 0; static const int ERR_NONE = 0;
static const int ERR_RPC_FAILED = 1; static const int ERR_RPC_FAILED = 1;
static const int ERR_UNEXPECTED_RESULT = 2; static const int ERR_UNEXPECTED_RESULT = 2;
@ -544,27 +543,29 @@ public:
int getPendingFriendRequestCount(); int getPendingFriendRequestCount();
bool requestGetAllInformation(); bool requestGetAllInformation();
bool requestGetAllInformation(std::function<void(uint32)> cb);
bool addProvisionalFriendByPidGuessed(uint32 principalId); bool addProvisionalFriendByPidGuessed(uint32 principalId);
void acceptFriendRequest(uint64 messageId, std::function<void(uint32)> cb);
bool isOnline();
// synchronous API (returns immediately)
bool requestGetAllInformation(std::function<void(uint32)> cb);
void getFriendPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeFriendRequests); void getFriendPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeFriendRequests);
void getFriendRequestPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeIncoming, bool includeOutgoing); void getFriendRequestPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeIncoming, bool includeOutgoing);
bool getFriendByPID(nexFriend& friendData, uint32 pid); bool getFriendByPID(nexFriend& friendData, uint32 pid);
bool getFriendRequestByPID(nexFriendRequest& friendRequestData, bool* isIncoming, uint32 searchedPid); bool getFriendRequestByPID(nexFriendRequest& friendRequestData, bool* isIncoming, uint32 searchedPid);
bool getFriendRequestByMessageId(nexFriendRequest& friendRequestData, bool* isIncoming, uint64 messageId); bool getFriendRequestByMessageId(nexFriendRequest& friendRequestData, bool* isIncoming, uint64 messageId);
bool isOnline();
void getMyPreference(nexPrincipalPreference& preference);
bool addProvisionalFriend(char* name, std::function<void(uint32)> cb); // asynchronous API (data has to be requested)
void addFriendRequest(uint32 pid, const char* comment, std::function<void(uint32)> cb); bool addProvisionalFriend(char* name, std::function<void(RpcErrorCode)> cb);
void addFriendRequest(uint32 pid, const char* comment, std::function<void(RpcErrorCode)> cb);
void requestPrincipleBaseInfoByPID(nexPrincipalBasicInfo* basicInfo, uint32* pidList, sint32 count, NEXFRIENDS_CALLBACK cb, void* customParam); void requestPrincipleBaseInfoByPID(uint32* pidList, sint32 count, const std::function<void(RpcErrorCode result, std::span<nexPrincipalBasicInfo> basicInfo)>& cb);
void removeFriend(uint32 pid, std::function<void(uint32)> cb); void removeFriend(uint32 pid, std::function<void(RpcErrorCode)> cb);
void cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(uint32)> cb); void cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(RpcErrorCode)> cb);
void markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(uint32)> cb); void markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(RpcErrorCode)> cb);
void acceptFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb);
void deleteFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb); // rejecting incoming friend request (differs from blocking friend requests)
bool updatePreferencesAsync(const nexPrincipalPreference newPreferences, std::function<void(RpcErrorCode)> cb);
void updateMyPresence(nexPresenceV2& myPresence); void updateMyPresence(nexPresenceV2& myPresence);
bool updatePreferences(const nexPrincipalPreference& newPreferences);
void setNotificationHandler(void(*notificationHandler)(NOTIFICATION_TYPE notificationType, uint32 pid)); void setNotificationHandler(void(*notificationHandler)(NOTIFICATION_TYPE notificationType, uint32 pid));
@ -578,7 +579,6 @@ private:
static void handleResponse_acceptFriendRequest(nexService* nex, nexServiceResponse_t* response); static void handleResponse_acceptFriendRequest(nexService* nex, nexServiceResponse_t* response);
static void handleResponse_getAllInformation(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb); static void handleResponse_getAllInformation(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb);
static void handleResponse_updatePreferences(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb);
void generateNotification(NOTIFICATION_TYPE notificationType, uint32 pid); void generateNotification(NOTIFICATION_TYPE notificationType, uint32 pid);
void trackNotifications(); void trackNotifications();
@ -618,6 +618,7 @@ private:
}auth; }auth;
// local friend state // local friend state
nexPresenceV2 myPresence; nexPresenceV2 myPresence;
nexPrincipalPreference myPreference;
std::recursive_mutex mtx_lists; std::recursive_mutex mtx_lists;
std::vector<nexFriend> list_friends; std::vector<nexFriend> list_friends;

View File

@ -20,6 +20,7 @@ add_library(CemuCommon
StackAllocator.h StackAllocator.h
SysAllocator.cpp SysAllocator.cpp
SysAllocator.h SysAllocator.h
CafeString.h
version.h version.h
) )

73
src/Common/CafeString.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#include "betype.h"
#include "util/helpers/StringHelpers.h"
/* Helper classes to represent CafeOS strings in emulated memory */
template <size_t N>
class CafeString // fixed buffer size, null-terminated, PPC char
{
public:
bool assign(std::string_view sv)
{
if (sv.size()+1 >= N)
{
memcpy(data, sv.data(), sv.size()-1);
data[sv.size()-1] = '\0';
return false;
}
memcpy(data, sv.data(), sv.size());
data[sv.size()] = '\0';
return true;
}
uint8be data[N];
};
template <size_t N>
class CafeWideString // fixed buffer size, null-terminated, PPC wchar_t (16bit big-endian)
{
public:
bool assign(const uint16be* input)
{
size_t i = 0;
while(input[i])
{
if(i >= N-1)
{
data[N-1] = 0;
return false;
}
data[i] = input[i];
i++;
}
data[i] = 0;
return true;
}
bool assignFromUTF8(std::string_view sv)
{
std::basic_string<uint16be> beStr = StringHelpers::FromUtf8(sv);
if(beStr.length() > N-1)
{
memcpy(data, beStr.data(), (N-1)*sizeof(uint16be));
data[N-1] = 0;
return false;
}
memcpy(data, beStr.data(), beStr.length()*sizeof(uint16be));
data[beStr.length()] = '\0';
return true;
}
uint16be data[N];
};
namespace CafeStringHelpers
{
static uint32 Length(const uint16be* input, uint32 maxLength)
{
uint32 i = 0;
while(input[i] && i < maxLength)
i++;
return i;
}
};

View File

@ -30,8 +30,35 @@ public:
uint32 GetMPTR() const { return MEMPTR<T>(m_ptr).GetMPTR(); } uint32 GetMPTR() const { return MEMPTR<T>(m_ptr).GetMPTR(); }
uint32 GetMPTRBE() const { return MEMPTR<T>(m_ptr).GetMPTRBE(); } uint32 GetMPTRBE() const { return MEMPTR<T>(m_ptr).GetMPTRBE(); }
operator T*() const { return GetPointer(); } T* operator&() { return GetPointer(); }
explicit operator T*() const { return GetPointer(); }
explicit operator uint32() const { return GetMPTR(); } explicit operator uint32() const { return GetMPTR(); }
explicit operator bool() const { return *m_ptr != 0; }
// for arrays (count > 1) allow direct access via [] operator
template<int c = count>
requires (c > 1)
T& operator[](const uint32 index)
{
return m_ptr[index];
}
// if count is 1, then allow direct value assignment via = operator
template<int c = count>
requires (c == 1)
T& operator=(const T& rhs)
{
*m_ptr = rhs;
return *m_ptr;
}
// if count is 1, then allow == and != operators
template<int c = count>
requires (c == 1)
bool operator==(const T& rhs) const
{
return *m_ptr == rhs;
}
private: private:
static const uint32 kStaticMemOffset = 64; static const uint32 kStaticMemOffset = 64;

View File

@ -2198,6 +2198,7 @@ void MainWindow::RecreateMenu()
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMP), _("&Coreinit MP API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMP)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMP), _("&Coreinit MP API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMP));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThread), _("&Coreinit Thread API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThread)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThread), _("&Coreinit Thread API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThread));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_NFP), _("&NN NFP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_NFP)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_NFP), _("&NN NFP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_NFP));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_FP), _("&NN FP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_FP));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _("&GX2 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::GX2)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _("&GX2 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::GX2));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _("&Audio API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _("&Audio API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _("&Input API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::InputAPI)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _("&Input API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::InputAPI));

View File

@ -2,6 +2,7 @@
#include "boost/nowide/convert.hpp" #include "boost/nowide/convert.hpp"
#include <charconv> #include <charconv>
// todo - move the Cafe/PPC specific parts to CafeString.h eventually
namespace StringHelpers namespace StringHelpers
{ {
// convert Wii U big-endian wchar_t string to utf8 string // convert Wii U big-endian wchar_t string to utf8 string

View File

@ -36,6 +36,16 @@ public:
static HighResolutionTimer now(); static HighResolutionTimer now();
static HRTick getFrequency(); static HRTick getFrequency();
static HRTick microsecondsToTicks(uint64 microseconds)
{
return microseconds * m_freq / 1000000;
}
static uint64 ticksToMicroseconds(HRTick ticks)
{
return ticks * 1000000 / m_freq;
}
private: private:
HighResolutionTimer(uint64 timePoint) : m_timePoint(timePoint) {}; HighResolutionTimer(uint64 timePoint) : m_timePoint(timePoint) {};