mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-07-11 01:24:28 +02:00
NP Part 1: NpSignaling (#4549)
* NP Part 1: NPSignaling PR Split 1 of X, adds the NPSignaling Library and some of the dependencies. Any stubs are highlighted by the stubs files and will be resolved upon other PRs. (Dependencies are to shadnet and further PR's to Matching2) * PR Corrections * PR Corrections 2 * PR Corrections 3 * clang fix * Move to folder per request
This commit is contained in:
@@ -628,6 +628,14 @@ set(NP_LIBS src/core/libraries/np/np_error.h
|
||||
src/core/libraries/np/np_manager.h
|
||||
src/core/libraries/np/np_matching2.cpp
|
||||
src/core/libraries/np/np_matching2.h
|
||||
src/core/libraries/np/np_signaling/np_signaling.cpp
|
||||
src/core/libraries/np/np_signaling/np_signaling.h
|
||||
src/core/libraries/np/np_signaling/np_signaling_state.cpp
|
||||
src/core/libraries/np/np_signaling/np_signaling_state.h
|
||||
src/core/libraries/np/np_signaling/np_signaling_helpers.cpp
|
||||
src/core/libraries/np/np_signaling/np_signaling_helpers.h
|
||||
src/core/libraries/np/np_signaling/np_signaling_stubs.cpp
|
||||
src/core/libraries/np/np_signaling/np_signaling_stubs.h
|
||||
src/core/libraries/np/np_trophy.cpp
|
||||
src/core/libraries/np/np_trophy.h
|
||||
src/core/libraries/np/np_tus.cpp
|
||||
|
||||
@@ -66,6 +66,7 @@ constexpr auto Lib_NpCommerce = "Lib.NpCommerce"; ///< The Lib
|
||||
constexpr auto Lib_NpCommon = "Lib.NpCommon"; ///< The LibSceNpCommon implementation
|
||||
constexpr auto Lib_NpManager = "Lib.NpManager"; ///< The LibSceNpManager implementation
|
||||
constexpr auto Lib_NpMatching2 = "Lib.NpMatching2"; ///< The LibSceNpMatching2 implementation
|
||||
constexpr auto Lib_NpSignaling = "Lib.NpSignaling"; ///< The LibSceNpSignaling implementation
|
||||
constexpr auto Lib_NpPartner = "Lib.NpPartner"; ///< The LibSceNpPartner implementation
|
||||
constexpr auto Lib_NpParty = "Lib.NpParty"; ///< The LibSceNpParty implementation
|
||||
constexpr auto Lib_NpProfileDialog = "Lib.NpProfileDialog"; ///< The LibSceNpProfileDialog implementation
|
||||
|
||||
@@ -88,6 +88,7 @@ std::unordered_map<std::string_view, std::shared_ptr<spdlog::logger>> ALL_LOGGER
|
||||
{Class::Lib_NpCommon, nullptr},
|
||||
{Class::Lib_NpManager, nullptr},
|
||||
{Class::Lib_NpMatching2, nullptr},
|
||||
{Class::Lib_NpSignaling, nullptr},
|
||||
{Class::Lib_NpPartner, nullptr},
|
||||
{Class::Lib_NpParty, nullptr},
|
||||
{Class::Lib_NpProfileDialog, nullptr},
|
||||
|
||||
@@ -39,6 +39,26 @@ int PS4_SYSV_ABI scePthreadMutexInit(PthreadMutexT* mutex, const PthreadMutexAtt
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_lock(PthreadMutexT* mutex);
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_unlock(PthreadMutexT* mutex);
|
||||
int PS4_SYSV_ABI posix_pthread_mutex_destroy(PthreadMutexT* mutex);
|
||||
s32 PS4_SYSV_ABI posix_pthread_mutex_trylock(PthreadMutexT* mutex);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_condattr_init(PthreadCondAttrT* attr);
|
||||
int PS4_SYSV_ABI posix_pthread_condattr_destroy(PthreadCondAttrT* attr);
|
||||
int PS4_SYSV_ABI scePthreadCondInit(PthreadCondT* cond, const PthreadCondAttrT* cond_attr,
|
||||
const char* name);
|
||||
int PS4_SYSV_ABI posix_pthread_cond_destroy(PthreadCondT* cond);
|
||||
int PS4_SYSV_ABI posix_pthread_cond_signal(PthreadCondT* cond);
|
||||
int PS4_SYSV_ABI posix_pthread_cond_wait(PthreadCondT* cond, PthreadMutexT* mutex);
|
||||
int PS4_SYSV_ABI posix_pthread_cond_reltimedwait_np(PthreadCondT* cond, PthreadMutexT* mutex,
|
||||
u64 usec);
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setstacksize(PthreadAttrT* attr, size_t stacksize);
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setinheritsched(PthreadAttrT* attr, int sched_inherit);
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setschedpolicy(PthreadAttrT* attr, SchedPolicy policy);
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setschedparam(PthreadAttrT* attr, SchedParam* param);
|
||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const u64 mask);
|
||||
int PS4_SYSV_ABI posix_pthread_create_name_np(PthreadT* thread, const PthreadAttrT* attr,
|
||||
PthreadEntryFunc start_routine, void* arg,
|
||||
const char* name);
|
||||
|
||||
void RegisterThreads(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "core/libraries/np/np_party.h"
|
||||
#include "core/libraries/np/np_profile_dialog/np_profile_dialog.h"
|
||||
#include "core/libraries/np/np_score/np_score.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling.h"
|
||||
#include "core/libraries/np/np_sns_facebook_dialog.h"
|
||||
#include "core/libraries/np/np_trophy.h"
|
||||
#include "core/libraries/np/np_tus.h"
|
||||
@@ -103,6 +104,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
||||
Libraries::Np::NpCommon::RegisterLib(sym);
|
||||
Libraries::Np::NpManager::RegisterLib(sym);
|
||||
Libraries::Np::NpMatching2::RegisterLib(sym);
|
||||
Libraries::Np::NpSignaling::RegisterLib(sym);
|
||||
Libraries::Np::NpScore::RegisterLib(sym);
|
||||
Libraries::Np::NpTrophy::RegisterLib(sym);
|
||||
Libraries::Np::NpWebApi::RegisterLib(sym);
|
||||
|
||||
@@ -8,6 +8,7 @@ constexpr int ORBIS_NET_CTL_ERROR_CALLBACK_MAX = 0x80412103;
|
||||
constexpr int ORBIS_NET_CTL_ERROR_ID_NOT_FOUND = 0x80412104;
|
||||
constexpr int ORBIS_NET_CTL_ERROR_INVALID_ID = 0x80412105;
|
||||
constexpr int ORBIS_NET_CTL_ERROR_INVALID_ADDR = 0x80412107;
|
||||
constexpr int ORBIS_NET_CTL_ERROR_INVALID_SIZE = 0x80412111;
|
||||
constexpr int ORBIS_NET_CTL_ERROR_NOT_CONNECTED = 0x80412108;
|
||||
constexpr int ORBIS_NET_CTL_ERROR_NOT_AVAIL = 0x80412109;
|
||||
constexpr int ORBIS_NET_CTL_ERROR_NETWORK_DISABLED = 0x8041210D;
|
||||
|
||||
@@ -334,6 +334,18 @@ const std::string& NetUtilInternal::GetIp() const {
|
||||
return ip;
|
||||
}
|
||||
|
||||
u32 NetUtilInternal::GetExternalIp() const {
|
||||
return external_ip;
|
||||
}
|
||||
|
||||
void NetUtilInternal::SetExternalIp(u32 addr) {
|
||||
external_ip = addr;
|
||||
}
|
||||
|
||||
u32 NetUtilInternal::GetNatType() const {
|
||||
return nat_type;
|
||||
}
|
||||
|
||||
bool NetUtilInternal::RetrieveIp() {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ private:
|
||||
std::string default_gateway{};
|
||||
std::string netmask{};
|
||||
std::string ip{};
|
||||
u32 external_ip{0};
|
||||
u32 nat_type{0};
|
||||
std::mutex m_mutex;
|
||||
|
||||
public:
|
||||
@@ -29,6 +31,9 @@ public:
|
||||
const std::string& GetDefaultGateway() const;
|
||||
const std::string& GetNetmask() const;
|
||||
const std::string& GetIp() const;
|
||||
u32 GetExternalIp() const;
|
||||
void SetExternalIp(u32 addr);
|
||||
u32 GetNatType() const;
|
||||
bool RetrieveEthernetAddr();
|
||||
bool RetrieveDefaultGateway();
|
||||
bool RetrieveNetmask();
|
||||
|
||||
@@ -258,8 +258,30 @@ int PS4_SYSV_ABI sceNetCtlGetInfoV6IpcInt() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetCtlGetNatInfo() {
|
||||
LOG_ERROR(Lib_NetCtl, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceNetCtlGetNatInfo(OrbisNetCtlNatInfo* nat_info) {
|
||||
if (!nat_info) {
|
||||
return ORBIS_NET_CTL_ERROR_INVALID_ADDR;
|
||||
}
|
||||
if (nat_info->size != sizeof(OrbisNetCtlNatInfo)) {
|
||||
return ORBIS_NET_CTL_ERROR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
|
||||
nat_info->nat_type = netinfo->GetNatType();
|
||||
const u32 ext_ip = netinfo->GetExternalIp();
|
||||
if (ext_ip != 0) {
|
||||
nat_info->stun_status = 1;
|
||||
nat_info->mapped_addr = ext_ip;
|
||||
} else {
|
||||
nat_info->stun_status = 0;
|
||||
nat_info->mapped_addr = inet_addr("127.0.0.1");
|
||||
if (netinfo->RetrieveIp()) {
|
||||
nat_info->mapped_addr = inet_addr(netinfo->GetIp().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG(Lib_NetCtl, "stun_status={} nat_type={} mapped_addr={:#x}", nat_info->stun_status,
|
||||
nat_info->nat_type, nat_info->mapped_addr);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,14 @@ union OrbisNetCtlInfo {
|
||||
u16 http_proxy_port;
|
||||
};
|
||||
|
||||
struct OrbisNetCtlNatInfo {
|
||||
u32 size;
|
||||
s32 stun_status;
|
||||
s32 nat_type;
|
||||
u32 mapped_addr;
|
||||
};
|
||||
static_assert(sizeof(OrbisNetCtlNatInfo) == 0x10);
|
||||
|
||||
// GetInfo codes
|
||||
constexpr int ORBIS_NET_CTL_INFO_DEVICE = 1;
|
||||
constexpr int ORBIS_NET_CTL_INFO_ETHER_ADDR = 2;
|
||||
@@ -100,7 +108,7 @@ int PS4_SYSV_ABI sceNetCtlGetIfStat();
|
||||
int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info);
|
||||
int PS4_SYSV_ABI sceNetCtlGetInfoIpcInt();
|
||||
int PS4_SYSV_ABI sceNetCtlGetInfoV6IpcInt();
|
||||
int PS4_SYSV_ABI sceNetCtlGetNatInfo();
|
||||
int PS4_SYSV_ABI sceNetCtlGetNatInfo(OrbisNetCtlNatInfo* nat_info);
|
||||
int PS4_SYSV_ABI sceNetCtlGetNatInfoIpcInt();
|
||||
int PS4_SYSV_ABI sceNetCtlGetNetEvConfigInfoIpcInt();
|
||||
int PS4_SYSV_ABI sceNetCtlGetResult(int eventType, int* errorCode);
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/process.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
#include "core/libraries/kernel/threads/pthread.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/np/np_common.h"
|
||||
#include "core/libraries/np/np_error.h"
|
||||
@@ -10,24 +18,94 @@
|
||||
|
||||
namespace Libraries::Np::NpCommon {
|
||||
|
||||
namespace {
|
||||
static_assert(sizeof(OrbisNpCalloutEntry) == 0x20);
|
||||
static_assert(offsetof(OrbisNpCalloutContext, thread) == 0x00);
|
||||
static_assert(offsetof(OrbisNpCalloutContext, mutex) == 0x08);
|
||||
static_assert(offsetof(OrbisNpCalloutContext, cond) == 0x10);
|
||||
static_assert(offsetof(OrbisNpCalloutContext, active) == 0x18);
|
||||
static_assert(offsetof(OrbisNpCalloutContext, stop_requested) == 0x1c);
|
||||
static_assert(offsetof(OrbisNpCalloutContext, head) == 0x20);
|
||||
static_assert(sizeof(OrbisNpCalloutContext) == 0x28);
|
||||
|
||||
s32 NormalizeNpCommonResult(int rc) {
|
||||
if (rc <= 0) {
|
||||
return rc;
|
||||
}
|
||||
return Libraries::Kernel::ErrnoToSceKernelError(rc);
|
||||
}
|
||||
|
||||
u32 NormalizeNpTryLockResult(int rc) {
|
||||
const s32 sce_rc = NormalizeNpCommonResult(rc);
|
||||
if (sce_rc == ORBIS_KERNEL_ERROR_EBUSY) {
|
||||
return ORBIS_NP_LW_MUTEX_ERROR_BUSY;
|
||||
}
|
||||
return static_cast<u32>(sce_rc);
|
||||
}
|
||||
|
||||
void* PS4_SYSV_ABI NpCalloutThreadMain(void* arg) {
|
||||
auto* ctx = static_cast<OrbisNpCalloutContext*>(arg);
|
||||
const auto mutex = &ctx->mutex;
|
||||
sceNpMutexLock(mutex);
|
||||
|
||||
for (;;) {
|
||||
s64 now_usec = 0;
|
||||
sceNpGetSystemClockUsec(&now_usec);
|
||||
|
||||
auto* entry = ctx->head;
|
||||
u32 wait_usec = 0;
|
||||
|
||||
if (entry == nullptr) {
|
||||
if (ctx->stop_requested > 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
const u64 deadline = static_cast<u64>(entry->deadline_usec);
|
||||
const u64 now = static_cast<u64>(now_usec);
|
||||
const u64 remaining = deadline - now;
|
||||
if (deadline < now || remaining == 0) {
|
||||
ctx->head = entry->next;
|
||||
sceNpMutexUnlock(mutex);
|
||||
if (entry->handler != nullptr) {
|
||||
entry->handler(entry->arg);
|
||||
}
|
||||
sceNpMutexLock(mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->stop_requested > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
wait_usec = static_cast<u32>(remaining > 0xffffffffULL ? 0xffffffffULL : remaining);
|
||||
}
|
||||
|
||||
sceNpCondTimedwait(&ctx->cond, mutex, wait_usec);
|
||||
if (ctx->stop_requested > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sceNpMutexUnlock(mutex);
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCmpNpId(OrbisNpId* np_id1, OrbisNpId* np_id2) {
|
||||
if (np_id1 == nullptr || np_id2 == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
// Compare data
|
||||
if (std::strncmp(np_id1->handle.data, np_id2->handle.data, ORBIS_NP_ONLINEID_MAX_LENGTH) != 0) {
|
||||
return ORBIS_NP_UTIL_ERROR_NOT_MATCH;
|
||||
}
|
||||
|
||||
// Compare opt
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
if (np_id1->opt[i] != np_id2->opt[i]) {
|
||||
return ORBIS_NP_UTIL_ERROR_NOT_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare reserved
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
if (np_id1->reserved[i] != np_id2->reserved[i]) {
|
||||
return ORBIS_NP_UTIL_ERROR_NOT_MATCH;
|
||||
@@ -42,7 +120,6 @@ s32 PS4_SYSV_ABI sceNpCmpNpIdInOrder(OrbisNpId* np_id1, OrbisNpId* np_id2, u32*
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
// Compare data
|
||||
u32 compare =
|
||||
std::strncmp(np_id1->handle.data, np_id2->handle.data, ORBIS_NP_ONLINEID_MAX_LENGTH);
|
||||
if (compare < 0) {
|
||||
@@ -53,7 +130,6 @@ s32 PS4_SYSV_ABI sceNpCmpNpIdInOrder(OrbisNpId* np_id1, OrbisNpId* np_id2, u32*
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
// Compare opt
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
if (np_id1->opt[i] < np_id2->opt[i]) {
|
||||
*out_result = -1;
|
||||
@@ -64,7 +140,6 @@ s32 PS4_SYSV_ABI sceNpCmpNpIdInOrder(OrbisNpId* np_id1, OrbisNpId* np_id2, u32*
|
||||
}
|
||||
}
|
||||
|
||||
// Compare reserved
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
if (np_id1->reserved[i] < np_id2->reserved[i]) {
|
||||
*out_result = -1;
|
||||
@@ -90,13 +165,441 @@ s32 PS4_SYSV_ABI sceNpCmpOnlineId(OrbisNpOnlineId* online_id1, OrbisNpOnlineId*
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpMutexLock(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_TRACE(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return static_cast<u32>(
|
||||
NormalizeNpCommonResult(Libraries::Kernel::posix_pthread_mutex_lock(mutex)));
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpMutexUnlock(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_TRACE(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return static_cast<u32>(
|
||||
NormalizeNpCommonResult(Libraries::Kernel::posix_pthread_mutex_unlock(mutex)));
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpMutexInit(Libraries::Kernel::PthreadMutexT* mutex, const char* name,
|
||||
u64 flags) {
|
||||
LOG_DEBUG(Lib_NpCommon, "mutex={:p} name={:p} flags={:#x}", fmt::ptr(mutex), fmt::ptr(name),
|
||||
flags);
|
||||
|
||||
Libraries::Kernel::PthreadMutexAttrT attr = nullptr;
|
||||
int rc = Libraries::Kernel::posix_pthread_mutexattr_init(&attr);
|
||||
if (rc == 0) {
|
||||
if ((flags & 1) != 0) {
|
||||
rc = Libraries::Kernel::posix_pthread_mutexattr_settype(
|
||||
&attr, Libraries::Kernel::PthreadMutexType::Recursive);
|
||||
}
|
||||
if (rc == 0) {
|
||||
rc = Libraries::Kernel::scePthreadMutexInit(mutex, &attr, name);
|
||||
}
|
||||
Libraries::Kernel::posix_pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
return static_cast<u32>(NormalizeNpCommonResult(rc));
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpMutexDestroy(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_DEBUG(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return NormalizeNpCommonResult(Libraries::Kernel::posix_pthread_mutex_destroy(mutex));
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpMutexTryLock(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_TRACE(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return NormalizeNpTryLockResult(Libraries::Kernel::posix_pthread_mutex_trylock(mutex));
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexLock(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_TRACE(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return sceNpMutexLock(mutex);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexUnlock(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_TRACE(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return sceNpMutexUnlock(mutex);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexInit(Libraries::Kernel::PthreadMutexT* mutex, const char* name,
|
||||
u64 flags) {
|
||||
LOG_DEBUG(Lib_NpCommon, "mutex={:p} name={:p} flags={:#x}", fmt::ptr(mutex), fmt::ptr(name),
|
||||
flags);
|
||||
return sceNpMutexInit(mutex, name, flags);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpLwMutexDestroy(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_DEBUG(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return sceNpMutexDestroy(mutex);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexTryLock(Libraries::Kernel::PthreadMutexT* mutex) {
|
||||
LOG_TRACE(Lib_NpCommon, "mutex={:p}", fmt::ptr(mutex));
|
||||
return sceNpMutexTryLock(mutex);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCondInit(Libraries::Kernel::PthreadCondT* cond, const char* name, u64 flags) {
|
||||
LOG_DEBUG(Lib_NpCommon, "cond={:p} name={:p} flags={:#x}", fmt::ptr(cond), fmt::ptr(name),
|
||||
flags);
|
||||
|
||||
Libraries::Kernel::PthreadCondAttrT attr = nullptr;
|
||||
int rc = Libraries::Kernel::posix_pthread_condattr_init(&attr);
|
||||
if (rc == 0) {
|
||||
rc = Libraries::Kernel::scePthreadCondInit(cond, &attr, name);
|
||||
Libraries::Kernel::posix_pthread_condattr_destroy(&attr);
|
||||
}
|
||||
return NormalizeNpCommonResult(rc);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCondDestroy(Libraries::Kernel::PthreadCondT* cond) {
|
||||
LOG_DEBUG(Lib_NpCommon, "cond={:p}", fmt::ptr(cond));
|
||||
return NormalizeNpCommonResult(Libraries::Kernel::posix_pthread_cond_destroy(cond));
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCondSignal(Libraries::Kernel::PthreadCondT* cond) {
|
||||
LOG_DEBUG(Lib_NpCommon, "cond={:p}", fmt::ptr(cond));
|
||||
return NormalizeNpCommonResult(Libraries::Kernel::posix_pthread_cond_signal(cond));
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCondTimedwait(Libraries::Kernel::PthreadCondT* cond,
|
||||
Libraries::Kernel::PthreadMutexT* mutex, u32 usec) {
|
||||
LOG_DEBUG(Lib_NpCommon, "cond={:p} mutex={:p} usec={:#x}", fmt::ptr(cond), fmt::ptr(mutex),
|
||||
usec);
|
||||
if (usec == 0) {
|
||||
return NormalizeNpCommonResult(Libraries::Kernel::posix_pthread_cond_wait(cond, mutex));
|
||||
}
|
||||
const s32 rc = NormalizeNpCommonResult(
|
||||
Libraries::Kernel::posix_pthread_cond_reltimedwait_np(cond, mutex, usec));
|
||||
if (rc == ORBIS_KERNEL_ERROR_ETIMEDOUT) {
|
||||
return ORBIS_NP_LW_COND_ERROR_TIMEDOUT;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCreateThread(Libraries::Kernel::PthreadT* thread, NpThreadEntry start_routine,
|
||||
void* arg, s32 priority, u64 stack_size, u64 affinity_mask,
|
||||
const char* name) {
|
||||
LOG_DEBUG(Lib_NpCommon,
|
||||
"thread={:p} start={:#x} arg={:p} priority={} stack={:#x} "
|
||||
"affinity={:#x} name={:p}",
|
||||
fmt::ptr(thread), reinterpret_cast<u64>(start_routine), fmt::ptr(arg), priority,
|
||||
stack_size, affinity_mask, fmt::ptr(name));
|
||||
|
||||
Libraries::Kernel::PthreadAttrT attr = nullptr;
|
||||
int rc = Libraries::Kernel::posix_pthread_attr_init(&attr);
|
||||
if (rc != 0) {
|
||||
return NormalizeNpCommonResult(rc);
|
||||
}
|
||||
|
||||
rc = Libraries::Kernel::posix_pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size));
|
||||
if (rc == 0) {
|
||||
if (priority != 0) {
|
||||
s32 sdk_version = 0;
|
||||
rc = Libraries::Kernel::sceKernelGetCompiledSdkVersion(&sdk_version);
|
||||
if (rc >= 0 && sdk_version >= 0x2500000) {
|
||||
rc = Libraries::Kernel::posix_pthread_attr_setinheritsched(&attr, 0);
|
||||
if (rc == 0) {
|
||||
rc = Libraries::Kernel::posix_pthread_attr_setschedpolicy(
|
||||
&attr, Libraries::Kernel::SchedPolicy::Fifo);
|
||||
}
|
||||
}
|
||||
if (rc >= 0) {
|
||||
Libraries::Kernel::SchedParam param{.sched_priority = priority};
|
||||
rc = Libraries::Kernel::posix_pthread_attr_setschedparam(&attr, ¶m);
|
||||
}
|
||||
}
|
||||
if (rc == 0 && affinity_mask != 0) {
|
||||
rc = Libraries::Kernel::scePthreadAttrSetaffinity(&attr, affinity_mask);
|
||||
}
|
||||
if (rc == 0) {
|
||||
rc = Libraries::Kernel::posix_pthread_create_name_np(thread, &attr, start_routine, arg,
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
Libraries::Kernel::posix_pthread_attr_destroy(&attr);
|
||||
return NormalizeNpCommonResult(rc);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpJoinThread(Libraries::Kernel::PthreadT thread, void** ret) {
|
||||
LOG_DEBUG(Lib_NpCommon, "thread={:p} ret={:p}", fmt::ptr(thread), fmt::ptr(ret));
|
||||
return static_cast<u32>(
|
||||
NormalizeNpCommonResult(Libraries::Kernel::posix_pthread_join(thread, ret)));
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpGetSystemClockUsec(s64* usec) {
|
||||
LOG_DEBUG(Lib_NpCommon, "usec={:p}", fmt::ptr(usec));
|
||||
Libraries::Kernel::OrbisKernelTimespec ts{};
|
||||
const s32 rc =
|
||||
Libraries::Kernel::sceKernelClockGettime(Libraries::Kernel::ORBIS_CLOCK_MONOTONIC, &ts);
|
||||
if (rc == ORBIS_OK) {
|
||||
*usec = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpGetPlatformType(const OrbisNpId* npid) {
|
||||
LOG_DEBUG(Lib_NpCommon, "np_id={:p}", fmt::ptr(npid));
|
||||
|
||||
if (npid == nullptr) {
|
||||
return ORBIS_NP_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
static constexpr u32 kTagPs3 = 0x00337370; // "ps3"
|
||||
static constexpr u32 kTagVita = 0x32707370; // "psp2(VITA)"
|
||||
static constexpr u32 kTagPs4 = 0x00347370; // "ps4"
|
||||
|
||||
if (npid->opt[4] == 0) {
|
||||
return OrbisNpPlatformType::None;
|
||||
}
|
||||
u32 tag = 0;
|
||||
std::memcpy(&tag, npid->opt + 4, sizeof(tag));
|
||||
switch (tag) {
|
||||
case kTagPs3:
|
||||
return OrbisNpPlatformType::PS3;
|
||||
case kTagVita:
|
||||
return OrbisNpPlatformType::Vita;
|
||||
case kTagPs4:
|
||||
return OrbisNpPlatformType::PS4;
|
||||
default:
|
||||
return ORBIS_NP_ERROR_INVALID_PLATFORM_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpIntIsValidOnlineId(const OrbisNpOnlineId* id) {
|
||||
LOG_DEBUG(Lib_NpCommon, "online_id={:p}", fmt::ptr(id));
|
||||
|
||||
if (id == nullptr || id->term != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size_t len = strnlen(id->data, ORBIS_NP_ONLINEID_MAX_LENGTH + 1);
|
||||
if (len < 3 || len > ORBIS_NP_ONLINEID_MAX_LENGTH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const unsigned char first = static_cast<unsigned char>(id->data[0]);
|
||||
if (!std::isalnum(first)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < len; ++i) {
|
||||
const unsigned char c = static_cast<unsigned char>(id->data[i]);
|
||||
if (std::isalnum(c) || c == '_' || c == '-') {
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCalloutInitCtx(OrbisNpCalloutContext* callout_ctx, const char* name,
|
||||
u64 stack_size, s32 priority, u64 affinity_mask) {
|
||||
LOG_DEBUG(Lib_NpCommon, "ctx={:p} name={:p} stack={:#x} priority={} affinity={:#x}",
|
||||
fmt::ptr(callout_ctx), fmt::ptr(name), stack_size, priority, affinity_mask);
|
||||
|
||||
s32 rc = ORBIS_NP_CALLOUT_ERROR_ALREADY_INITIALIZED;
|
||||
if (callout_ctx->active < 1) {
|
||||
callout_ctx->stop_requested = 0;
|
||||
callout_ctx->head = nullptr;
|
||||
rc = static_cast<s32>(sceNpMutexInit(&callout_ctx->mutex, name, 1));
|
||||
if (rc >= 0) {
|
||||
rc = sceNpCondInit(&callout_ctx->cond, name, 0);
|
||||
if (rc >= 0) {
|
||||
rc = sceNpCreateThread(&callout_ctx->thread, NpCalloutThreadMain, callout_ctx,
|
||||
priority, stack_size, affinity_mask, name);
|
||||
if (rc >= 0) {
|
||||
callout_ctx->active = 1;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
sceNpCondDestroy(&callout_ctx->cond);
|
||||
}
|
||||
sceNpMutexDestroy(&callout_ctx->mutex);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCalloutStartOnCtx(OrbisNpCalloutContext* callout_ctx,
|
||||
OrbisNpCalloutEntry* entry, u64 delay_usec, u64 handler,
|
||||
u64 arg) {
|
||||
LOG_DEBUG(Lib_NpCommon, "ctx={:p} callout={:p} delay={:#x} handler={:p} arg={:#x}",
|
||||
fmt::ptr(callout_ctx), fmt::ptr(entry), delay_usec,
|
||||
fmt::ptr(reinterpret_cast<void*>(static_cast<uintptr_t>(handler))), arg);
|
||||
|
||||
if (callout_ctx->active == 0) {
|
||||
return ORBIS_NP_CALLOUT_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
entry->next = nullptr;
|
||||
entry->handler = reinterpret_cast<OrbisNpCalloutHandler>(handler);
|
||||
entry->arg = arg;
|
||||
sceNpGetSystemClockUsec(&entry->deadline_usec);
|
||||
entry->deadline_usec += static_cast<s64>(static_cast<u32>(delay_usec));
|
||||
|
||||
sceNpMutexLock(&callout_ctx->mutex);
|
||||
|
||||
for (auto* cur = callout_ctx->head; cur != nullptr; cur = cur->next) {
|
||||
if (cur == entry) {
|
||||
sceNpMutexUnlock(&callout_ctx->mutex);
|
||||
return ORBIS_NP_CALLOUT_ERROR_DUPLICATE_ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
OrbisNpCalloutEntry** prev_next = &callout_ctx->head;
|
||||
for (auto* cur = callout_ctx->head; cur != nullptr; cur = cur->next) {
|
||||
if (cur->deadline_usec >= entry->deadline_usec) {
|
||||
break;
|
||||
}
|
||||
prev_next = &cur->next;
|
||||
}
|
||||
|
||||
entry->next = *prev_next;
|
||||
*prev_next = entry;
|
||||
sceNpCondSignal(&callout_ctx->cond);
|
||||
sceNpMutexUnlock(&callout_ctx->mutex);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCalloutStartOnCtx64(OrbisNpCalloutContext* callout_ctx,
|
||||
OrbisNpCalloutEntry* entry, s64 delay_usec, u64 handler,
|
||||
u64 arg) {
|
||||
LOG_DEBUG(Lib_NpCommon, "ctx={:p} callout={:p} delay={} handler={:p} arg={:#x}",
|
||||
fmt::ptr(callout_ctx), fmt::ptr(entry), delay_usec,
|
||||
fmt::ptr(reinterpret_cast<void*>(static_cast<uintptr_t>(handler))), arg);
|
||||
|
||||
if (callout_ctx->active == 0) {
|
||||
return ORBIS_NP_CALLOUT_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
entry->next = nullptr;
|
||||
entry->handler = reinterpret_cast<OrbisNpCalloutHandler>(handler);
|
||||
entry->arg = arg;
|
||||
sceNpGetSystemClockUsec(&entry->deadline_usec);
|
||||
entry->deadline_usec += delay_usec;
|
||||
|
||||
sceNpMutexLock(&callout_ctx->mutex);
|
||||
|
||||
for (auto* cur = callout_ctx->head; cur != nullptr; cur = cur->next) {
|
||||
if (cur == entry) {
|
||||
sceNpMutexUnlock(&callout_ctx->mutex);
|
||||
return ORBIS_NP_CALLOUT_ERROR_DUPLICATE_ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
OrbisNpCalloutEntry** prev_next = &callout_ctx->head;
|
||||
for (auto* cur = callout_ctx->head; cur != nullptr; cur = cur->next) {
|
||||
if (cur->deadline_usec >= entry->deadline_usec) {
|
||||
break;
|
||||
}
|
||||
prev_next = &cur->next;
|
||||
}
|
||||
|
||||
entry->next = *prev_next;
|
||||
*prev_next = entry;
|
||||
sceNpCondSignal(&callout_ctx->cond);
|
||||
sceNpMutexUnlock(&callout_ctx->mutex);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpCalloutStopOnCtx(OrbisNpCalloutContext* callout_ctx,
|
||||
OrbisNpCalloutEntry* entry, u32* removed) {
|
||||
LOG_DEBUG(Lib_NpCommon, "ctx={:p} callout={:p} removed={:p}", fmt::ptr(callout_ctx),
|
||||
fmt::ptr(entry), fmt::ptr(removed));
|
||||
|
||||
if (callout_ctx->active == 0) {
|
||||
return ORBIS_NP_CALLOUT_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
sceNpMutexLock(&callout_ctx->mutex);
|
||||
u32 found = 0;
|
||||
OrbisNpCalloutEntry** prev_next = &callout_ctx->head;
|
||||
for (auto* cur = callout_ctx->head; cur != nullptr; cur = cur->next) {
|
||||
if (cur == entry) {
|
||||
*prev_next = cur->next;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
prev_next = &cur->next;
|
||||
}
|
||||
if (removed != nullptr) {
|
||||
*removed = found;
|
||||
}
|
||||
sceNpMutexUnlock(&callout_ctx->mutex);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI sceNpCalloutTermCtx(OrbisNpCalloutContext* callout_ctx) {
|
||||
LOG_DEBUG(Lib_NpCommon, "ctx={:p}", fmt::ptr(callout_ctx));
|
||||
|
||||
if (callout_ctx->active != 0) {
|
||||
sceNpMutexLock(&callout_ctx->mutex);
|
||||
callout_ctx->stop_requested = 1;
|
||||
sceNpCondSignal(&callout_ctx->cond);
|
||||
sceNpMutexUnlock(&callout_ctx->mutex);
|
||||
sceNpJoinThread(callout_ctx->thread, nullptr);
|
||||
sceNpCondDestroy(&callout_ctx->cond);
|
||||
sceNpMutexDestroy(&callout_ctx->mutex);
|
||||
callout_ctx->active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("i8UmXTSq7N4", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCmpNpId);
|
||||
LIB_FUNCTION("TcwEFnakiSc", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCmpNpIdInOrder);
|
||||
LIB_FUNCTION("dj+O5aD2a0Q", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCmpOnlineId);
|
||||
LIB_FUNCTION("1a+iY5YUJcI", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCondDestroy);
|
||||
LIB_FUNCTION("9+m5nRdJ-wQ", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCalloutInitCtx);
|
||||
LIB_FUNCTION("AqJ4xkWsV+I", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCalloutTermCtx);
|
||||
LIB_FUNCTION("18j+qk6dRwk", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpLwMutexLock);
|
||||
LIB_FUNCTION("1CiXI-MyEKs", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpLwMutexInit);
|
||||
LIB_FUNCTION("4zxevggtYrQ", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpLwMutexDestroy);
|
||||
LIB_FUNCTION("CQG2oyx1-nM", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpLwMutexUnlock);
|
||||
LIB_FUNCTION("DuslmoqQ+nk", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpMutexTryLock);
|
||||
LIB_FUNCTION("EjMsfO3GCIA", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpJoinThread);
|
||||
LIB_FUNCTION("fClnlkZmA6k", "libSceNpCommonCompat", 1, "libSceNpCommon",
|
||||
sceNpCalloutStartOnCtx);
|
||||
LIB_FUNCTION("fhJ5uKzcn0w", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCreateThread);
|
||||
LIB_FUNCTION("hkeX9iuCwlI", "libSceNpCommonCompat", 1, "libSceNpCommon",
|
||||
sceNpIntIsValidOnlineId);
|
||||
LIB_FUNCTION("hp0kVgu5Fxw", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpLwMutexTryLock);
|
||||
LIB_FUNCTION("in19gH7G040", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCalloutStopOnCtx);
|
||||
LIB_FUNCTION("lQ11BpMM4LU", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpMutexDestroy);
|
||||
LIB_FUNCTION("lpr66Gby8dQ", "libSceNpCommonCompat", 1, "libSceNpCommon",
|
||||
sceNpCalloutStartOnCtx64);
|
||||
LIB_FUNCTION("oZyb9ktuCpA", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpMutexUnlock);
|
||||
LIB_FUNCTION("PVVsRmMkO1g", "libSceNpCommonCompat", 1, "libSceNpCommon",
|
||||
sceNpGetSystemClockUsec);
|
||||
LIB_FUNCTION("q2tsVO3lM4A", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCondInit);
|
||||
LIB_FUNCTION("r9Bet+s6fKc", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpMutexLock);
|
||||
LIB_FUNCTION("sXVQUIGmk2U", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpGetPlatformType);
|
||||
LIB_FUNCTION("ss2xO9IJxKQ", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCondTimedwait);
|
||||
LIB_FUNCTION("uEwag-0YZPc", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpMutexInit);
|
||||
LIB_FUNCTION("uMJFOA62mVU", "libSceNpCommonCompat", 1, "libSceNpCommon", sceNpCondSignal);
|
||||
LIB_FUNCTION("i8UmXTSq7N4", "libSceNpCommon", 1, "libSceNpCommon", sceNpCmpNpId);
|
||||
LIB_FUNCTION("TcwEFnakiSc", "libSceNpCommon", 1, "libSceNpCommon", sceNpCmpNpIdInOrder);
|
||||
LIB_FUNCTION("dj+O5aD2a0Q", "libSceNpCommon", 1, "libSceNpCommon", sceNpCmpOnlineId);
|
||||
LIB_FUNCTION("1a+iY5YUJcI", "libSceNpCommon", 1, "libSceNpCommon", sceNpCondDestroy);
|
||||
LIB_FUNCTION("9+m5nRdJ-wQ", "libSceNpCommon", 1, "libSceNpCommon", sceNpCalloutInitCtx);
|
||||
LIB_FUNCTION("AqJ4xkWsV+I", "libSceNpCommon", 1, "libSceNpCommon", sceNpCalloutTermCtx);
|
||||
LIB_FUNCTION("18j+qk6dRwk", "libSceNpCommon", 1, "libSceNpCommon", sceNpLwMutexLock);
|
||||
LIB_FUNCTION("1CiXI-MyEKs", "libSceNpCommon", 1, "libSceNpCommon", sceNpLwMutexInit);
|
||||
LIB_FUNCTION("4zxevggtYrQ", "libSceNpCommon", 1, "libSceNpCommon", sceNpLwMutexDestroy);
|
||||
LIB_FUNCTION("CQG2oyx1-nM", "libSceNpCommon", 1, "libSceNpCommon", sceNpLwMutexUnlock);
|
||||
LIB_FUNCTION("DuslmoqQ+nk", "libSceNpCommon", 1, "libSceNpCommon", sceNpMutexTryLock);
|
||||
LIB_FUNCTION("EjMsfO3GCIA", "libSceNpCommon", 1, "libSceNpCommon", sceNpJoinThread);
|
||||
LIB_FUNCTION("fClnlkZmA6k", "libSceNpCommon", 1, "libSceNpCommon", sceNpCalloutStartOnCtx);
|
||||
LIB_FUNCTION("fhJ5uKzcn0w", "libSceNpCommon", 1, "libSceNpCommon", sceNpCreateThread);
|
||||
LIB_FUNCTION("hkeX9iuCwlI", "libSceNpCommon", 1, "libSceNpCommon", sceNpIntIsValidOnlineId);
|
||||
LIB_FUNCTION("hp0kVgu5Fxw", "libSceNpCommon", 1, "libSceNpCommon", sceNpLwMutexTryLock);
|
||||
LIB_FUNCTION("in19gH7G040", "libSceNpCommon", 1, "libSceNpCommon", sceNpCalloutStopOnCtx);
|
||||
LIB_FUNCTION("lQ11BpMM4LU", "libSceNpCommon", 1, "libSceNpCommon", sceNpMutexDestroy);
|
||||
LIB_FUNCTION("lpr66Gby8dQ", "libSceNpCommon", 1, "libSceNpCommon", sceNpCalloutStartOnCtx64);
|
||||
LIB_FUNCTION("oZyb9ktuCpA", "libSceNpCommon", 1, "libSceNpCommon", sceNpMutexUnlock);
|
||||
LIB_FUNCTION("PVVsRmMkO1g", "libSceNpCommon", 1, "libSceNpCommon", sceNpGetSystemClockUsec);
|
||||
LIB_FUNCTION("q2tsVO3lM4A", "libSceNpCommon", 1, "libSceNpCommon", sceNpCondInit);
|
||||
LIB_FUNCTION("r9Bet+s6fKc", "libSceNpCommon", 1, "libSceNpCommon", sceNpMutexLock);
|
||||
LIB_FUNCTION("sXVQUIGmk2U", "libSceNpCommon", 1, "libSceNpCommon", sceNpGetPlatformType);
|
||||
LIB_FUNCTION("ss2xO9IJxKQ", "libSceNpCommon", 1, "libSceNpCommon", sceNpCondTimedwait);
|
||||
LIB_FUNCTION("uEwag-0YZPc", "libSceNpCommon", 1, "libSceNpCommon", sceNpMutexInit);
|
||||
LIB_FUNCTION("uMJFOA62mVU", "libSceNpCommon", 1, "libSceNpCommon", sceNpCondSignal);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Np::NpCommon
|
||||
} // namespace Libraries::Np::NpCommon
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/threads/pthread.h"
|
||||
#include "core/libraries/np/np_types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
@@ -17,5 +19,58 @@ struct OrbisNpFreeKernelMemoryArgs {
|
||||
void* addr;
|
||||
};
|
||||
|
||||
using NpThreadEntry = void* PS4_SYSV_ABI (*)(void*);
|
||||
using OrbisNpCalloutHandler = void PS4_SYSV_ABI (*)(u64);
|
||||
|
||||
struct OrbisNpCalloutEntry {
|
||||
OrbisNpCalloutEntry* next;
|
||||
OrbisNpCalloutHandler handler;
|
||||
s64 deadline_usec;
|
||||
u64 arg;
|
||||
};
|
||||
|
||||
struct OrbisNpCalloutContext {
|
||||
Libraries::Kernel::PthreadT thread;
|
||||
Libraries::Kernel::PthreadMutexT mutex;
|
||||
Libraries::Kernel::PthreadCondT cond;
|
||||
s32 active;
|
||||
s32 stop_requested;
|
||||
OrbisNpCalloutEntry* head;
|
||||
};
|
||||
|
||||
u32 PS4_SYSV_ABI sceNpMutexLock(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
u32 PS4_SYSV_ABI sceNpMutexUnlock(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
u32 PS4_SYSV_ABI sceNpMutexInit(Libraries::Kernel::PthreadMutexT* mutex, const char* name,
|
||||
u64 flags);
|
||||
s32 PS4_SYSV_ABI sceNpMutexDestroy(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
u32 PS4_SYSV_ABI sceNpMutexTryLock(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexLock(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexUnlock(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexInit(Libraries::Kernel::PthreadMutexT* mutex, const char* name,
|
||||
u64 flags);
|
||||
s32 PS4_SYSV_ABI sceNpLwMutexDestroy(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
u32 PS4_SYSV_ABI sceNpLwMutexTryLock(Libraries::Kernel::PthreadMutexT* mutex);
|
||||
s32 PS4_SYSV_ABI sceNpCondInit(Libraries::Kernel::PthreadCondT* cond, const char* name, u64 flags);
|
||||
s32 PS4_SYSV_ABI sceNpCondDestroy(Libraries::Kernel::PthreadCondT* cond);
|
||||
s32 PS4_SYSV_ABI sceNpCondSignal(Libraries::Kernel::PthreadCondT* cond);
|
||||
s32 PS4_SYSV_ABI sceNpCondTimedwait(Libraries::Kernel::PthreadCondT* cond,
|
||||
Libraries::Kernel::PthreadMutexT* mutex, u32 usec);
|
||||
s32 PS4_SYSV_ABI sceNpCreateThread(Libraries::Kernel::PthreadT* thread, NpThreadEntry start_routine,
|
||||
void* arg, s32 priority, u64 stack_size, u64 affinity_mask,
|
||||
const char* name);
|
||||
u32 PS4_SYSV_ABI sceNpJoinThread(Libraries::Kernel::PthreadT thread, void** ret);
|
||||
s32 PS4_SYSV_ABI sceNpGetSystemClockUsec(s64* usec);
|
||||
s32 PS4_SYSV_ABI sceNpGetPlatformType(const OrbisNpId* np_id);
|
||||
s32 PS4_SYSV_ABI sceNpIntIsValidOnlineId(const OrbisNpOnlineId* id);
|
||||
s32 PS4_SYSV_ABI sceNpCalloutInitCtx(OrbisNpCalloutContext* ctx, const char* name, u64 stack_size,
|
||||
s32 priority, u64 affinity_mask);
|
||||
s32 PS4_SYSV_ABI sceNpCalloutStartOnCtx(OrbisNpCalloutContext* ctx, OrbisNpCalloutEntry* callout,
|
||||
u64 delay_usec, u64 handler, u64 arg);
|
||||
s32 PS4_SYSV_ABI sceNpCalloutStartOnCtx64(OrbisNpCalloutContext* ctx, OrbisNpCalloutEntry* callout,
|
||||
s64 delay_usec, u64 handler, u64 arg);
|
||||
s32 PS4_SYSV_ABI sceNpCalloutStopOnCtx(OrbisNpCalloutContext* ctx, OrbisNpCalloutEntry* callout,
|
||||
u32* removed);
|
||||
void PS4_SYSV_ABI sceNpCalloutTermCtx(OrbisNpCalloutContext* ctx);
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Np::NpCommon
|
||||
} // namespace Libraries::Np::NpCommon
|
||||
|
||||
@@ -10,6 +10,7 @@ constexpr int ORBIS_NP_ERROR_ALREADY_INITIALIZED = 0x80550001;
|
||||
constexpr int ORBIS_NP_ERROR_NOT_INITIALIZED = 0x80550002;
|
||||
constexpr int ORBIS_NP_ERROR_INVALID_ARGUMENT = 0x80550003;
|
||||
constexpr int ORBIS_NP_ERROR_UNKNOWN_PLATFORM_TYPE = 0x80550004;
|
||||
constexpr int ORBIS_NP_ERROR_INVALID_PLATFORM_TYPE = 0x80550004;
|
||||
constexpr int ORBIS_NP_ERROR_OUT_OF_MEMORY = 0x80550005;
|
||||
constexpr int ORBIS_NP_ERROR_SIGNED_OUT = 0x80550006;
|
||||
constexpr int ORBIS_NP_ERROR_USER_NOT_FOUND = 0x80550007;
|
||||
@@ -37,6 +38,9 @@ constexpr int ORBIS_NP_ERROR_TITLE_ID_IN_PARAM_SFO_NOT_EXIST = 0x8055001C;
|
||||
constexpr int ORBIS_NP_ERROR_CALLBACK_MAX = 0x8055001D;
|
||||
constexpr int ORBIS_NP_ERROR_INVALID_NP_TITLE_ID = 0x8055001E;
|
||||
constexpr int ORBIS_NP_ERROR_ONLINE_ID_CHANGED = 0x8055001F;
|
||||
constexpr int ORBIS_NP_INT_ERROR_INVALID_ARGUMENT = 0x8055A283;
|
||||
constexpr int ORBIS_NP_SCORE_INVALID_ARGUMENT = 0x80550704;
|
||||
constexpr int ORBIS_NP_WEB_API_INVALID_ARGUMENT = 0x80552902;
|
||||
|
||||
// NP Util (0x80550601 - 0x8055060e)
|
||||
constexpr int ORBIS_NP_UTIL_ERROR_INVALID_ARGUMENT = 0x80550601;
|
||||
@@ -674,3 +678,107 @@ constexpr int ORBIS_NP_GAME_INTENT_ERROR_VALUE_NOT_FOUND = 0x80553807;
|
||||
// NP ASM Client (0x8055a287 - 0x8055a289)
|
||||
constexpr int ORBIS_NP_ASM_CLIENT_ERROR_ABORTED = 0x8055A287;
|
||||
constexpr int ORBIS_NP_ASM_CLIENT_ERROR_NP_SERVICE_LAVEL_NOT_MATCH = 0x8055A289;
|
||||
|
||||
// NP Callout / LW Mutex (0x80558001 - 0x8055800F)
|
||||
constexpr int ORBIS_NP_CALLOUT_ERROR_NOT_INITIALIZED = 0x80558001;
|
||||
constexpr int ORBIS_NP_CALLOUT_ERROR_ALREADY_INITIALIZED = 0x80558002;
|
||||
constexpr int ORBIS_NP_CALLOUT_ERROR_DUPLICATE_ENTRY = 0x80558006;
|
||||
constexpr int ORBIS_NP_LW_COND_ERROR_TIMEDOUT = 0x8055800B;
|
||||
constexpr int ORBIS_NP_LW_MUTEX_ERROR_BUSY = 0x8055800F;
|
||||
|
||||
// NP Signaling internal errors (0x80559601 - 0x8055960F)
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_INVALID_ARGUMENT = 0x80559601;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_DATA_TOO_BIG = 0x80559602;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_INVALID_ACTION = 0x80559603;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_CONN_NOT_ACTIVATED = 0x80559604;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_OUT_OF_MEMORY = 0x80559605;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_PARSER_FAILED = 0x80559606;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_INVALID_NAMESPACE = 0x80559607;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_ALLOCATOR = 0x80559608;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_IPC_CONTEXT_NOT_FOUND = 0x80559609;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_ALREADY_INITIALIZED = 0x8055960A;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_NOT_INITIALIZED = 0x8055960B;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_XMPP_IPC_INVALID_MSG_TYPE = 0x8055960C;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_XMPP_IPC_INVALID_ID = 0x8055960D;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_INVALID_DATA_TYPE = 0x8055960E;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_ERROR_CALLBACK_QUEUE_OVERFLOW = 0x8055960F;
|
||||
|
||||
// NP Signaling internal socket / core errors
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_CORE_ERROR_80550E81 = 0x80550E81;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_CORE_ERROR_80550E82 = 0x80550E82;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_CORE_ERROR_80550E83 = 0x80550E83;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SERVICE_ERROR_TRANSIENT_SOCKET_ALLOC = 0x80559611;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SERVICE_ERROR_POLL_PENDING = 0x80559D1B;
|
||||
|
||||
// NP Signaling internal socket errors
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SOCKET_ERROR_BASE = 0x80410100;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SOCKET_ERROR_SHORT_IO = 0x80410104;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SOCKET_ERROR_ECHO_RECV_REBUILD = 0x80410123;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SOCKET_ERROR_80410124 = 0x80410124;
|
||||
|
||||
// NP Signaling internal STUN errors
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_ALREADY_INITIALIZED = 0x80412401;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_NOT_INITIALIZED = 0x80412402;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_TIMEOUT = 0x80412403;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_BAD_RESPONSE_HEADER = 0x80412404;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_BAD_ATTRIBUTE_LENGTH = 0x80412405;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_PARSE_FAILED = 0x80412406;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_UNSUPPORTED_ADDRESS_FAMILY = 0x80412407;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_NO_SLOT = 0x80412409;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_BAD_QUEUE_INDEX = 0x8041240A;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_MESSAGE_INTEGRITY = 0x8041240B;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_BAD_XOR_MAPPED_ADDRESS = 0x8041240C;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_ALLOC_FAILED = 0x8041240D;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_CANCELLED = 0x8041240E;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_NO_RESULT = 0x8041240F;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_QUEUE_SEND_FAILED = 0x80412410;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_BAD_SERVICE_FLAGS = 0x80412411;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_STUN_ERROR_SERVICE_UNAVAILABLE = 0x80412412;
|
||||
|
||||
// NP Signaling internal UPNP errors
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_INITIALIZATION_FAILED = 0x80414101;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_NET_UNAVAILABLE = 0x80414102;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_INVALID_ARGUMENT = 0x80414105;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_DISCOVERY_PENDING = 0x80414108;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_HTTP_SOCKET_FAILED = 0x8041410A;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SERVICE_NOT_FOUND = 0x8041410B;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_INVALID_ACTION = 0x80414171;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_INVALID_ARGS = 0x80414172;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_INVALID_VAR = 0x80414173;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_ACTION_FAILED = 0x80414174;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_WILDCARD_NOT_PERMITTED = 0x80414175;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_EXTERNAL_PORT_WILDCARD_ONLY =
|
||||
0x80414176;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_CONFLICT_MAPPING_ENTRY = 0x80414177;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_SAME_PORT_VALUES_REQUIRED =
|
||||
0x80414178;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_ONLY_PERMANENT_LEASE_SUPPORTED =
|
||||
0x80414179;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_REMOTE_HOST_WILDCARD_ONLY =
|
||||
0x8041417A;
|
||||
constexpr int
|
||||
ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_EXTERNAL_PORT_WILDCARD_NOT_PERMITTED =
|
||||
0x8041417B;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_NO_PORT_MAPS_AVAILABLE = 0x8041417C;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SOAP_FAULT_GENERIC = 0x8041417D;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_8041417E = 0x8041417E;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_80414181 = 0x80414181;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_80414184 = 0x80414184;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_FORMAT_OR_BUFFER = 0x80414185;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SSDP_ADDR = 0x80414186;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SSDP_TIMEOUT = 0x80414187;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_80414188 = 0x80414188;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_HTTP_URL_INVALID = 0x80414189;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_SSDP_IGNORED = 0x8041418A;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_8041418B = 0x8041418B;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_CONTENT_LENGTH_MISMATCH = 0x8041418D;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_UNSUPPORTED_ACTION = 0x8041418F;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_80414190 = 0x80414190;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_XML_ARGUMENT = 0x804141A0;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_XML_INPUT = 0x804141A1;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_UPNP_ERROR_XML_SPACE = 0x804141A2;
|
||||
|
||||
// NP Signaling internal misc errors
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SHA1_ERROR_INVALID_ARGUMENT = 0x80480300;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_SHA1_ERROR_INACTIVE_CONTEXT = 0x80480302;
|
||||
constexpr int ORBIS_NP_SIGNALING_INTERNAL_HMAC_ERROR_INVALID_ARGUMENT = 0x80481000;
|
||||
|
||||
@@ -0,0 +1,886 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
#include "core/libraries/network/net_util.h"
|
||||
#include "core/libraries/network/netctl.h"
|
||||
#include "core/libraries/np/np_common.h"
|
||||
#include "core/libraries/np/np_handler.h"
|
||||
#include "core/libraries/np/np_manager.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling_helpers.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling_state.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling_stubs.h"
|
||||
|
||||
namespace Libraries::Np::NpSignaling {
|
||||
|
||||
using Libraries::Net::sceNetNtohs;
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingInitialize(s64 memorySize, s32 threadPriority, s32 cpuAffinityMask,
|
||||
s64 threadStackSize) {
|
||||
if (g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
InitSignalingMutex();
|
||||
SignalingMutexGuard lock;
|
||||
|
||||
u32 app_type_4 = 0;
|
||||
const s32 app_type_rc = Helpers::CheckInitializeAppType(&app_type_4);
|
||||
if (app_type_rc < 0) {
|
||||
return app_type_rc;
|
||||
}
|
||||
if (app_type_4 != 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_PROHIBITED_TO_USE;
|
||||
}
|
||||
|
||||
if (memorySize == 0) {
|
||||
memorySize = 0x20000;
|
||||
}
|
||||
if (threadPriority == 0) {
|
||||
threadPriority = 700;
|
||||
}
|
||||
if (threadStackSize == 0) {
|
||||
threadStackSize = 0x4000;
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_NpSignaling,
|
||||
"memorySize={} threadPriority={} cpuAffinityMask={} threadStackSize={}", memorySize,
|
||||
threadPriority, cpuAffinityMask, threadStackSize);
|
||||
|
||||
const s32 heap_rc = Helpers::InitSignalingHeap(memorySize);
|
||||
if (heap_rc < 0) {
|
||||
return heap_rc;
|
||||
}
|
||||
|
||||
RegisterRuntimeHooks();
|
||||
|
||||
const s32 check_app_type_rc = Helpers::CheckAppType();
|
||||
if (check_app_type_rc < 0) {
|
||||
Helpers::ShutdownSignalingHeap();
|
||||
return check_app_type_rc;
|
||||
}
|
||||
|
||||
g_initialized = true;
|
||||
|
||||
const s32 rc = Helpers::StartMainRuntime(threadPriority, cpuAffinityMask, threadStackSize);
|
||||
if (rc < 0) {
|
||||
g_initialized = false;
|
||||
Helpers::ShutdownSignalingHeap();
|
||||
return rc;
|
||||
}
|
||||
|
||||
const s32 echo_rc = Helpers::StartEchoRuntime(threadPriority, cpuAffinityMask);
|
||||
if (echo_rc < 0) {
|
||||
g_initialized = false;
|
||||
Helpers::ShutdownRuntime();
|
||||
Helpers::ShutdownSignalingHeap();
|
||||
return echo_rc;
|
||||
}
|
||||
|
||||
const s32 callout_rc = NpCommon::sceNpCalloutInitCtx(
|
||||
&g_callout_ctx, "SceNpSignalingCallout", static_cast<u64>(threadStackSize), threadPriority,
|
||||
static_cast<u64>(cpuAffinityMask));
|
||||
if (callout_rc < 0) {
|
||||
g_initialized = false;
|
||||
Helpers::ShutdownRuntime();
|
||||
Helpers::ShutdownSignalingHeap();
|
||||
return callout_rc;
|
||||
}
|
||||
g_callout_ctx_active = true;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingTerminate() {
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
g_initialized = false;
|
||||
}
|
||||
|
||||
Helpers::ShutdownRuntime();
|
||||
|
||||
if (g_callout_ctx_active) {
|
||||
NpCommon::sceNpCalloutTermCtx(&g_callout_ctx);
|
||||
g_callout_ctx_active = false;
|
||||
}
|
||||
|
||||
Helpers::ShutdownSignalingHeap();
|
||||
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
g_contexts.clear();
|
||||
g_connections.clear();
|
||||
g_npid_to_conn.clear();
|
||||
g_peer_netinfo_results.clear();
|
||||
}
|
||||
|
||||
DestroySignalingMutex();
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "cleared all state");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingCreateContext(const void* npId, void* callback, void* callbackArg,
|
||||
OrbisNpSignalingContextId* outContextId) {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
if (!npId || !outContextId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
OrbisNpId owner_npid{};
|
||||
OrbisNpOnlineId owner_online_id{};
|
||||
if (NormalizeNpId(npId, &owner_npid, &owner_online_id) != ORBIS_OK) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
s32 ctx_id = 0;
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
ctx_id = AllocateContextIdLocked();
|
||||
if (ctx_id < 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTXID_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NpSignalingContext& ctx = g_contexts[ctx_id];
|
||||
ctx.callback = reinterpret_cast<OrbisNpSignalingHandler>(callback);
|
||||
ctx.callback_arg = callbackArg;
|
||||
ctx.active = true;
|
||||
ctx.owner_npid = owner_npid;
|
||||
ctx.owner_online_id = owner_online_id;
|
||||
ctx.flags = 0x2;
|
||||
ctx.compiled_sdk_version = CaptureCompiledSdkVersion();
|
||||
ctx.activate_budget_us = kActivateBudgetMaxUs;
|
||||
ctx.activate_last_update_us = NowUs();
|
||||
ctx.bound_port = Stubs::ConfiguredPort();
|
||||
*outContextId = ctx_id;
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} owner='{}' callback={} arg={} sdk={:#x} p2p_port={}",
|
||||
ctx_id, OnlineIdToString(owner_online_id), fmt::ptr(callback),
|
||||
fmt::ptr(callbackArg), ctx.compiled_sdk_version, ctx.bound_port);
|
||||
}
|
||||
|
||||
if (Stubs::TransportIsReady()) {
|
||||
SendStunPing(ctx_id);
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingCreateContextA(s32 userId, void* callback, void* callbackArg,
|
||||
OrbisNpSignalingContextId* outContextId) {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
if (userId == -1 || !outContextId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
OrbisNpId owner_npid{};
|
||||
const s32 npid_rc = NpManager::sceNpGetNpId(userId, &owner_npid);
|
||||
if (npid_rc < 0) {
|
||||
return npid_rc;
|
||||
}
|
||||
// Account id isn't needed without matchmaking wired up; leave it 0 for now.
|
||||
const OrbisNpAccountId account_id = 0;
|
||||
|
||||
s32 ctx_id = 0;
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
ctx_id = AllocateContextIdLocked();
|
||||
if (ctx_id < 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTXID_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NpSignalingContext& ctx = g_contexts[ctx_id];
|
||||
ctx.callback = reinterpret_cast<OrbisNpSignalingHandler>(callback);
|
||||
ctx.callback_arg = callbackArg;
|
||||
ctx.active = true;
|
||||
ctx.owner_npid = owner_npid;
|
||||
ctx.owner_online_id = owner_npid.handle;
|
||||
ctx.flags = 0x4 | 0x2;
|
||||
ctx.account_id = account_id;
|
||||
ctx.platform_type = 0;
|
||||
ctx.compiled_sdk_version = CaptureCompiledSdkVersion();
|
||||
ctx.activate_budget_us = kActivateBudgetMaxUs;
|
||||
ctx.activate_last_update_us = NowUs();
|
||||
ctx.bound_port = Stubs::ConfiguredPort();
|
||||
*outContextId = ctx_id;
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} userId={} owner='{}' accountId={:#x}", ctx_id, userId,
|
||||
OnlineIdToString(ctx.owner_online_id), account_id);
|
||||
}
|
||||
|
||||
if (Stubs::TransportIsReady()) {
|
||||
SendStunPing(ctx_id);
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingDeleteContext(OrbisNpSignalingContextId ctxId) {
|
||||
std::vector<s32> active_conns;
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={}", ctxId);
|
||||
|
||||
for (const auto& [cid, ci] : g_connections) {
|
||||
if (ci.ctx_id == ctxId && ci.status != ORBIS_NP_SIGNALING_CONN_STATUS_INACTIVE) {
|
||||
active_conns.push_back(cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const s32 cid : active_conns) {
|
||||
CloseConnectionAndDispatchDead(cid, ORBIS_NP_SIGNALING_ERROR_TERMINATED_BY_PEER);
|
||||
}
|
||||
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
RemoveContextConnectionsLocked(ctxId);
|
||||
for (auto it = g_peer_netinfo_results.begin(); it != g_peer_netinfo_results.end();) {
|
||||
it = (it->second.ctx_id == ctxId) ? g_peer_netinfo_results.erase(it) : std::next(it);
|
||||
}
|
||||
g_contexts.erase(ctxId);
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingActivateConnection(OrbisNpSignalingContextId ctxId,
|
||||
const void* peerNpId,
|
||||
OrbisNpSignalingConnectionId* outConnId) {
|
||||
LOG_INFO(Lib_NpSignaling, "t={} ctxId={} peerNpId={:p} connId={:p}", NowMs(), ctxId, peerNpId,
|
||||
fmt::ptr(outConnId));
|
||||
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
if (!peerNpId || !outConnId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
OrbisNpId peer_npid{};
|
||||
OrbisNpOnlineId peer_online_id{};
|
||||
if (NormalizeNpId(peerNpId, &peer_npid, &peer_online_id) != ORBIS_OK) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
const std::string peer_online_id_str = OnlineIdToString(peer_online_id);
|
||||
|
||||
s32 cid = 0;
|
||||
bool reused_established = false;
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
const auto ctx_it = g_contexts.find(ctxId);
|
||||
if (ctx_it == g_contexts.end() || !ctx_it->second.active) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if (std::memcmp(&ctx_it->second.owner_npid, &peer_npid, sizeof(peer_npid)) == 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_OWN_NP_ID;
|
||||
}
|
||||
if (!ConsumeActivationBudgetGatedLocked(ctx_it->second)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_EXCEED_RATE_LIMIT;
|
||||
}
|
||||
|
||||
const CtxNpIdKey lookup_key = MakeCtxNpIdKey(ctxId, peer_npid);
|
||||
const auto existing_it = g_npid_to_conn.find(lookup_key);
|
||||
if (existing_it != g_npid_to_conn.end()) {
|
||||
const auto conn_it = g_connections.find(existing_it->second);
|
||||
if (conn_it != g_connections.end() && conn_it->second.state == ConnState::Inactive) {
|
||||
RemoveConnectionLocked(existing_it->second);
|
||||
} else if (conn_it != g_connections.end()) {
|
||||
cid = existing_it->second;
|
||||
ConnectionInfo& ci = conn_it->second;
|
||||
ci.locally_activated = true;
|
||||
if (ci.state == ConnState::Established) {
|
||||
ClearLingerAndTimeoutLocked(cid);
|
||||
reused_established = true;
|
||||
} else {
|
||||
ClearLingerAndTimeoutLocked(cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool created_new = false;
|
||||
if (cid == 0) {
|
||||
cid = AllocateConnectionIdLocked();
|
||||
if (cid < 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ConnectionInfo ci{};
|
||||
ci.conn_id = cid;
|
||||
ci.ctx_id = ctxId;
|
||||
ci.state = ConnState::SendingOffer;
|
||||
ci.status = ORBIS_NP_SIGNALING_CONN_STATUS_PENDING;
|
||||
ci.is_initiator = true;
|
||||
ci.locally_activated = true;
|
||||
ci.npid = peer_npid;
|
||||
ci.online_id = peer_online_id;
|
||||
g_connections[cid] = std::move(ci);
|
||||
g_npid_to_conn[lookup_key] = cid;
|
||||
created_new = true;
|
||||
}
|
||||
if (created_new) {
|
||||
ArmConnectTimeoutLocked(cid);
|
||||
QueueActivationLocked(cid, peer_online_id_str);
|
||||
}
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} peer='{}' connId={} Status: {}", ctxId,
|
||||
peer_online_id_str, cid,
|
||||
created_new ? "queued, async"
|
||||
: reused_established ? "reused established"
|
||||
: "reused transient");
|
||||
}
|
||||
|
||||
*outConnId = cid;
|
||||
|
||||
if (reused_established) {
|
||||
EstablishConnection(cid, false);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
g_dispatch_cv.notify_all();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingActivateConnectionA(
|
||||
OrbisNpSignalingContextId ctxId, const OrbisNpSignalingAccountPlatformPair* peerAddr,
|
||||
OrbisNpSignalingConnectionId* outConnId) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!peerAddr || peerAddr->accountId == 0 || !outConnId || peerAddr->platformType == 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const auto ctx_it = g_contexts.find(ctxId);
|
||||
if (ctx_it == g_contexts.end() || !ctx_it->second.active) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if ((ctx_it->second.flags & 0x4) != 0 && ctx_it->second.account_id == peerAddr->accountId &&
|
||||
ctx_it->second.platform_type == peerAddr->platformType) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_OWN_PEER_ADDRESS;
|
||||
}
|
||||
|
||||
if (!ConsumeActivationBudgetGatedLocked(ctx_it->second)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_EXCEED_RATE_LIMIT;
|
||||
}
|
||||
const s32 cid = AllocateConnectionIdLocked();
|
||||
if (cid < 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ConnectionInfo ci{};
|
||||
ci.conn_id = cid;
|
||||
ci.ctx_id = ctxId;
|
||||
ci.status = ORBIS_NP_SIGNALING_CONN_STATUS_PENDING;
|
||||
g_connections[cid] = std::move(ci);
|
||||
*outConnId = cid;
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} accountId={:#x} platform={} connId={}", ctxId,
|
||||
peerAddr->accountId, peerAddr->platformType, cid);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingDeactivateConnection(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId) {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
|
||||
const auto it = g_connections.find(connId);
|
||||
if (it == g_connections.end() || it->second.ctx_id != ctxId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "t={} ctxId={} connId={} peer='{}' status={}", NowMs(), ctxId,
|
||||
connId, OnlineIdToString(it->second.online_id), it->second.status);
|
||||
}
|
||||
DeactivateConnectionFaithful(connId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingTerminateConnection(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId) {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
const auto it = g_connections.find(connId);
|
||||
if (it == g_connections.end() || it->second.ctx_id != ctxId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
|
||||
}
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} connId={}", ctxId, connId);
|
||||
}
|
||||
TerminateConnectionFaithful(connId);
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
RemoveConnectionLocked(connId);
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionStatus(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId,
|
||||
u32* outStatus, u32* outPeerAddr,
|
||||
u16* outPeerPort) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!outStatus) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
|
||||
const auto it = g_connections.find(connId);
|
||||
if (it == g_connections.end() || it->second.ctx_id != ctxId) {
|
||||
*outStatus = ORBIS_NP_SIGNALING_CONN_STATUS_INACTIVE;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
const s32 state = ConnectionStateFromStatus(it->second.status);
|
||||
if (state == 10) {
|
||||
*outStatus = ORBIS_NP_SIGNALING_CONN_STATUS_ACTIVE;
|
||||
if (outPeerAddr) {
|
||||
*outPeerAddr = it->second.addr;
|
||||
}
|
||||
if (outPeerPort) {
|
||||
*outPeerPort = it->second.port;
|
||||
}
|
||||
} else if (state != 0) {
|
||||
*outStatus = ORBIS_NP_SIGNALING_CONN_STATUS_PENDING;
|
||||
} else {
|
||||
*outStatus = ORBIS_NP_SIGNALING_CONN_STATUS_INACTIVE;
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "t={} ctxId={} connId={} peer='{}' status={}", NowMs(), ctxId, connId,
|
||||
OnlineIdToString(it->second.online_id), *outStatus);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionInfo(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId, s32 infoCode,
|
||||
void* outInfo) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!outInfo) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
const s32 rc = GetConnectionInfoInternal(ctxId, connId, infoCode, outInfo, nullptr);
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} connId={} infoCode={} rc={:#x}", ctxId, connId, infoCode,
|
||||
static_cast<u32>(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionInfoA(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId, s32 infoCode,
|
||||
void* outInfo) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!outInfo) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
const s32 rc = GetConnectionInfoInternal(ctxId, connId, infoCode, nullptr, outInfo);
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} connId={} infoCode={} rc={:#x}", ctxId, connId, infoCode,
|
||||
static_cast<u32>(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionFromNpId(OrbisNpSignalingContextId ctxId,
|
||||
const void* peerNpId,
|
||||
OrbisNpSignalingConnectionId* outConnId) {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
if (!peerNpId || !outConnId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
OrbisNpId peer_npid{};
|
||||
OrbisNpOnlineId peer_online_id{};
|
||||
if (NormalizeNpId(peerNpId, &peer_npid, &peer_online_id) != ORBIS_OK) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
|
||||
const auto it = g_npid_to_conn.find(MakeCtxNpIdKey(ctxId, peer_npid));
|
||||
if (it == g_npid_to_conn.end()) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
|
||||
}
|
||||
const auto conn_it = g_connections.find(it->second);
|
||||
if (conn_it == g_connections.end()) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
|
||||
}
|
||||
|
||||
*outConnId = it->second;
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} npid='{}' connId={}", ctxId,
|
||||
OnlineIdToString(peer_online_id), it->second);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceNpSignalingGetConnectionFromPeerAddress(OrbisNpSignalingContextId ctxId, u32 peerAddr,
|
||||
u16 peerPort, OrbisNpSignalingConnectionId* outConnId) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!outConnId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
|
||||
for (const auto& [id, ci] : g_connections) {
|
||||
if (ci.ctx_id == ctxId && ci.addr == peerAddr && ci.port == peerPort &&
|
||||
ConnectionStateFromStatus(ci.status) == 10) {
|
||||
*outConnId = id;
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} addr={:#x} port={} connId={}", ctxId, peerAddr,
|
||||
sceNetNtohs(peerPort), id);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
}
|
||||
return ORBIS_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionFromPeerAddressA(
|
||||
OrbisNpSignalingContextId ctxId, const OrbisNpSignalingAccountPlatformPair* peerAddr,
|
||||
OrbisNpSignalingConnectionId* outConnId) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!peerAddr || !outConnId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
const auto ctx_it = g_contexts.find(ctxId);
|
||||
if (ctx_it == g_contexts.end() || !ctx_it->second.active) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if ((ctx_it->second.flags & 0x4) == 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} accountId={:#x}", ctxId, peerAddr->accountId);
|
||||
return ORBIS_NP_SIGNALING_ERROR_CONN_NOT_FOUND;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingSetContextOption(OrbisNpSignalingContextId ctxId, s32 optionId,
|
||||
s32 optionValue) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
const auto it = g_contexts.find(ctxId);
|
||||
if (it == g_contexts.end() || !it->second.active) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if (optionId != ORBIS_NP_SIGNALING_CONTEXT_OPTION_FLAG) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (optionValue == 0) {
|
||||
it->second.flags &= ~0x2u;
|
||||
} else if (optionValue == 1) {
|
||||
it->second.flags |= 0x2u;
|
||||
} else {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetContextOption(OrbisNpSignalingContextId ctxId, s32 optionId,
|
||||
s32* outOptionValue) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!outOptionValue) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
const auto it = g_contexts.find(ctxId);
|
||||
if (it == g_contexts.end() || !it->second.active) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if (optionId != ORBIS_NP_SIGNALING_CONTEXT_OPTION_FLAG) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
*outOptionValue = (it->second.flags & 0x2u) != 0 ? 1 : 0;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetLocalNetInfo(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingNetInfo* info) {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
if (!info) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (info->size != sizeof(OrbisNpSignalingNetInfo)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
|
||||
info->localAddr = ParseIpv4Nbo(netinfo->GetIp());
|
||||
|
||||
NetCtl::OrbisNetCtlNatInfo nat_info{};
|
||||
nat_info.size = sizeof(nat_info);
|
||||
info->mappedAddr = 0;
|
||||
info->natStatus = 0;
|
||||
if (NetCtl::sceNetCtlGetNatInfo(&nat_info) >= 0) {
|
||||
info->mappedAddr = nat_info.mapped_addr;
|
||||
info->natStatus = nat_info.nat_type;
|
||||
}
|
||||
if (info->mappedAddr == 0) {
|
||||
const u32 external = netinfo->GetExternalIp();
|
||||
info->mappedAddr = external != 0 ? external : info->localAddr;
|
||||
}
|
||||
info->_pad_14 = 0;
|
||||
|
||||
LOG_INFO(Lib_NpSignaling, "localAddr={:#x} mappedAddr={:#x} natStatus={}", info->localAddr,
|
||||
info->mappedAddr, info->natStatus);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetPeerNetInfo(OrbisNpSignalingContextId ctxId, const void* peerNpId,
|
||||
OrbisNpSignalingRequestId* outReqId) {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
if (!peerNpId || !outReqId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
OrbisNpId peer_npid{};
|
||||
if (NormalizeNpId(peerNpId, &peer_npid, nullptr) != ORBIS_OK) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
s32 req_id = 0;
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
req_id = StagePeerNetInfoResultLocked(ctxId);
|
||||
if (req_id == 0) {
|
||||
return ORBIS_NP_MATCHING2_SIGNALING_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
*outReqId = static_cast<u32>(req_id);
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} reqId={:#x}", ctxId, *outReqId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetPeerNetInfoA(OrbisNpSignalingContextId ctxId,
|
||||
const void* peerAccountPayload,
|
||||
OrbisNpSignalingRequestId* outReqId) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!peerAccountPayload || !outReqId) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
const auto ctx_it = g_contexts.find(ctxId);
|
||||
if (ctx_it == g_contexts.end() || !ctx_it->second.active) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if ((ctx_it->second.flags & 0x4) == 0) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
const s32 req_id = StagePeerNetInfoResultLocked(ctxId);
|
||||
if (req_id == 0) {
|
||||
return ORBIS_NP_MATCHING2_SIGNALING_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
*outReqId = static_cast<u32>(req_id);
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} reqId={:#x}", ctxId, *outReqId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingCancelPeerNetInfo(OrbisNpSignalingContextId ctxId, s32 reqOrConnId) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if (!DropPeerNetInfoResultLocked(ctxId, reqOrConnId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_REQ_NOT_FOUND;
|
||||
}
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} reqOrConnId={:#x}", ctxId, reqOrConnId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetPeerNetInfoResult(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId,
|
||||
OrbisNpSignalingNetInfo* peerNetInfo) {
|
||||
SignalingMutexGuard lock;
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!peerNetInfo) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (!IsContextValidLocked(ctxId)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
|
||||
}
|
||||
if (peerNetInfo->size != sizeof(OrbisNpSignalingNetInfo)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
PeerNetInfoResult result{};
|
||||
if (!TakePeerNetInfoResultLocked(ctxId, connId, &result)) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_RESULT_NOT_FOUND;
|
||||
}
|
||||
peerNetInfo->localAddr = result.local_ipv4;
|
||||
peerNetInfo->mappedAddr = result.external_ipv4;
|
||||
peerNetInfo->natStatus = static_cast<s32>(result.nat_route_kind);
|
||||
peerNetInfo->_pad_14 = 0;
|
||||
LOG_INFO(Lib_NpSignaling, "ctxId={} connId={:#x} ext={:#x}", ctxId, connId,
|
||||
result.external_ipv4);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetMemoryInfo(OrbisNpSignalingMemoryInfo* info) {
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!info) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
info->currentInUse = 0;
|
||||
info->peakInUse = 0;
|
||||
info->maxSystemSize = 0x20000;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceNpSignalingGetConnectionStatistics(OrbisNpSignalingConnectionStatistics* stats) {
|
||||
if (!g_initialized) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!stats) {
|
||||
return ORBIS_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
SignalingMutexGuard lock;
|
||||
SnapshotConnectionStatisticsLocked(&stats->peakConnectionCount, &stats->activeConnectionCount,
|
||||
&stats->transientConnectionCount,
|
||||
&stats->establishedConnectionCount);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("0UvTFeomAUM", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingActivateConnection);
|
||||
LIB_FUNCTION("ZPLavCKqAB0", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingActivateConnectionA);
|
||||
LIB_FUNCTION("X1G4kkN2R-8", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingCancelPeerNetInfo);
|
||||
LIB_FUNCTION("5yYjEdd4t8Y", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingCreateContext);
|
||||
LIB_FUNCTION("dDLNFdY8dws", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingCreateContextA);
|
||||
LIB_FUNCTION("6UEembipgrM", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingDeactivateConnection);
|
||||
LIB_FUNCTION("hx+LIg-1koI", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingDeleteContext);
|
||||
LIB_FUNCTION("GQ0hqmzj0F4", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetConnectionFromNpId);
|
||||
LIB_FUNCTION("CkPxQjSm018", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetConnectionFromPeerAddress);
|
||||
LIB_FUNCTION("B7cT9aVby7A", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetConnectionFromPeerAddressA);
|
||||
LIB_FUNCTION("AN3h0EBSX7A", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetConnectionInfo);
|
||||
LIB_FUNCTION("rcylknsUDwg", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetConnectionInfoA);
|
||||
LIB_FUNCTION("C6ZNCDTj00Y", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetConnectionStatistics);
|
||||
LIB_FUNCTION("bD-JizUb3JM", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetConnectionStatus);
|
||||
LIB_FUNCTION("npU5V56id34", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetContextOption);
|
||||
LIB_FUNCTION("U8AQMlOFBc8", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetLocalNetInfo);
|
||||
LIB_FUNCTION("tOpqyDyMje4", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetMemoryInfo);
|
||||
LIB_FUNCTION("zFgFHId7vAE", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetPeerNetInfo);
|
||||
LIB_FUNCTION("Shr7bZq8QHY", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetPeerNetInfoA);
|
||||
LIB_FUNCTION("2HajCEGgG4s", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingGetPeerNetInfoResult);
|
||||
LIB_FUNCTION("3KOuC4RmZZU", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingInitialize);
|
||||
LIB_FUNCTION("IHRDvZodPYY", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingSetContextOption);
|
||||
LIB_FUNCTION("NPhw0UXaNrk", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingTerminate);
|
||||
LIB_FUNCTION("b4qaXPzMJxo", "libSceNpSignaling", 1, "libSceNpSignaling",
|
||||
sceNpSignalingTerminateConnection);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Np::NpSignaling
|
||||
@@ -0,0 +1,146 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::Np::NpSignaling {
|
||||
|
||||
using OrbisNpSignalingContextId = s32;
|
||||
using OrbisNpSignalingConnectionId = s32;
|
||||
using OrbisNpSignalingRequestId = u32;
|
||||
|
||||
using OrbisNpSignalingHandler = PS4_SYSV_ABI void (*)(u32 ctxId, u32 connId, s32 event,
|
||||
s32 errorCode, void* userArg);
|
||||
|
||||
constexpr s32 ORBIS_NP_SIGNALING_EVENT_DEAD = 0;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_EVENT_ESTABLISHED = 1;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_EVENT_NETINFO_ERROR = 2;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_EVENT_NETINFO_RESULT = 3;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_EVENT_PEER_ACTIVATED = 10;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_EVENT_PEER_DEACTIVATED = 11;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_EVENT_MUTUAL_ACTIVATED = 12;
|
||||
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_STATUS_INACTIVE = 0;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_STATUS_PENDING = 1;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_STATUS_ACTIVE = 2;
|
||||
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_RTT = 1;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_BANDWIDTH = 2;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PEER_NP_ID = 3;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PEER_ADDR = 4;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_MAPPED_ADDR = 5;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PACKET_LOSS = 6;
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONN_INFO_PEER_ADDRESS_A = 7;
|
||||
|
||||
constexpr s32 ORBIS_NP_SIGNALING_CONTEXT_OPTION_FLAG = 1;
|
||||
|
||||
struct OrbisNpSignalingNetInfo {
|
||||
u64 size;
|
||||
u32 localAddr;
|
||||
u32 mappedAddr;
|
||||
s32 natStatus;
|
||||
u32 _pad_14;
|
||||
};
|
||||
static_assert(sizeof(OrbisNpSignalingNetInfo) == 0x18);
|
||||
|
||||
struct OrbisNpSignalingAccountPlatformPair {
|
||||
u64 accountId;
|
||||
u32 platformType;
|
||||
u32 _pad_0c;
|
||||
};
|
||||
static_assert(sizeof(OrbisNpSignalingAccountPlatformPair) == 0x10);
|
||||
|
||||
struct OrbisNpSignalingMemoryInfo {
|
||||
u64 currentInUse;
|
||||
u64 peakInUse;
|
||||
u64 maxSystemSize;
|
||||
};
|
||||
static_assert(sizeof(OrbisNpSignalingMemoryInfo) == 0x18);
|
||||
|
||||
struct OrbisNpSignalingConnectionStatistics {
|
||||
u32 peakConnectionCount;
|
||||
u32 activeConnectionCount;
|
||||
u32 transientConnectionCount;
|
||||
u32 establishedConnectionCount;
|
||||
};
|
||||
static_assert(sizeof(OrbisNpSignalingConnectionStatistics) == 0x10);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingInitialize(s64 memorySize, s32 threadPriority, s32 cpuAffinityMask,
|
||||
s64 threadStackSize);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingTerminate();
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingCreateContext(const void* npId, void* callback, void* callbackArg,
|
||||
OrbisNpSignalingContextId* outContextId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingCreateContextA(s32 userId, void* callback, void* callbackArg,
|
||||
OrbisNpSignalingContextId* outContextId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingDeleteContext(OrbisNpSignalingContextId ctxId);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingActivateConnection(OrbisNpSignalingContextId ctxId,
|
||||
const void* peerNpId,
|
||||
OrbisNpSignalingConnectionId* outConnId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingActivateConnectionA(
|
||||
OrbisNpSignalingContextId ctxId, const OrbisNpSignalingAccountPlatformPair* peerAddr,
|
||||
OrbisNpSignalingConnectionId* outConnId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingDeactivateConnection(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingTerminateConnection(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionStatus(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId,
|
||||
u32* outStatus, u32* outPeerAddr,
|
||||
u16* outPeerPort);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionInfo(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId, s32 infoCode,
|
||||
void* outInfo);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionInfoA(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId, s32 infoCode,
|
||||
void* outInfo);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionFromNpId(OrbisNpSignalingContextId ctxId,
|
||||
const void* peerNpId,
|
||||
OrbisNpSignalingConnectionId* outConnId);
|
||||
s32 PS4_SYSV_ABI
|
||||
sceNpSignalingGetConnectionFromPeerAddress(OrbisNpSignalingContextId ctxId, u32 peerAddr,
|
||||
u16 peerPort, OrbisNpSignalingConnectionId* outConnId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionFromPeerAddressA(
|
||||
OrbisNpSignalingContextId ctxId, const OrbisNpSignalingAccountPlatformPair* peerAddr,
|
||||
OrbisNpSignalingConnectionId* outConnId);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingSetContextOption(OrbisNpSignalingContextId ctxId, s32 optionId,
|
||||
s32 optionValue);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetContextOption(OrbisNpSignalingContextId ctxId, s32 optionId,
|
||||
s32* outOptionValue);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetLocalNetInfo(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingNetInfo* info);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetPeerNetInfo(OrbisNpSignalingContextId ctxId, const void* peerNpId,
|
||||
OrbisNpSignalingRequestId* outReqId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetPeerNetInfoA(OrbisNpSignalingContextId ctxId,
|
||||
const void* peerAccountPayload,
|
||||
OrbisNpSignalingRequestId* outReqId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingCancelPeerNetInfo(OrbisNpSignalingContextId ctxId, s32 reqOrConnId);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetPeerNetInfoResult(OrbisNpSignalingContextId ctxId,
|
||||
OrbisNpSignalingConnectionId connId,
|
||||
OrbisNpSignalingNetInfo* peerNetInfo);
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetMemoryInfo(OrbisNpSignalingMemoryInfo* info);
|
||||
s32 PS4_SYSV_ABI sceNpSignalingGetConnectionStatistics(OrbisNpSignalingConnectionStatistics* stats);
|
||||
|
||||
s32 GetActiveConnectionIdForPeer(std::string_view online_id);
|
||||
|
||||
s32 GetConnectionStatusForPeer(std::string_view online_id, s32* out_conn_id);
|
||||
|
||||
bool GetPeerAddress(std::string_view online_id, u32* out_addr, u16* out_port);
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Np::NpSignaling
|
||||
@@ -0,0 +1,520 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/memory.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
#include "core/libraries/network/net_util.h"
|
||||
#include "core/libraries/np/np_common.h"
|
||||
#include "core/libraries/np/np_error.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling_helpers.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling_state.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling_stubs.h"
|
||||
|
||||
namespace Libraries::Np::NpSignaling::Helpers {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr s32 InferredNpAppType = 0;
|
||||
|
||||
bool g_signaling_heap_initialized = false;
|
||||
void* g_signaling_heap_base = nullptr;
|
||||
s64 g_signaling_heap_size = 0;
|
||||
SignalingRuntimeHooks g_runtime_hooks{};
|
||||
bool g_runtime_hooks_registered = false;
|
||||
u64 g_echo_probe_word2 = 0;
|
||||
u64 g_echo_probe_word3 = 0;
|
||||
u64 g_echo_thread_handle = static_cast<u64>(-1);
|
||||
s32 g_echo_thread_status = -1;
|
||||
|
||||
s32 GetInferredAppType(s32* app_type) {
|
||||
if (app_type == nullptr) {
|
||||
return ORBIS_NP_INT_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*app_type = InferredNpAppType;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s16 GetAppTypeStateGate() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetAppTypeMarker(u16 marker) {
|
||||
LOG_DEBUG(Lib_NpSignaling, "marker={:#x}", marker);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SetRuntimeHooks(const SignalingRuntimeHooks& hooks) {
|
||||
g_runtime_hooks = hooks;
|
||||
g_runtime_hooks_registered = true;
|
||||
}
|
||||
|
||||
s32 CheckInitializeAppType(u32* is_app_type_4) {
|
||||
s32 app_type = -1;
|
||||
const s32 rc = GetInferredAppType(&app_type);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (is_app_type_4 != nullptr) {
|
||||
*is_app_type_4 = app_type == 4 ? 1u : 0u;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 InitSignalingHeap(s64 pool_size) {
|
||||
LOG_DEBUG(Lib_NpSignaling, "pool_size={}", pool_size);
|
||||
|
||||
if (pool_size == 0 || g_signaling_heap_initialized) {
|
||||
return ORBIS_NP_SIGNALING_INTERNAL_ERROR_ALLOCATOR;
|
||||
}
|
||||
|
||||
const u64 aligned_size = Common::AlignUp(static_cast<u64>(pool_size), 0x4000);
|
||||
|
||||
void* heap_base = nullptr;
|
||||
const s32 rc = Libraries::Kernel::sceKernelMapNamedFlexibleMemory(&heap_base, aligned_size, 3,
|
||||
0, "SceNpSignaling");
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
g_signaling_heap_initialized = true;
|
||||
g_signaling_heap_base = heap_base;
|
||||
g_signaling_heap_size = static_cast<s64>(aligned_size);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void ShutdownSignalingHeap() {
|
||||
if (!g_signaling_heap_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_signaling_heap_initialized = false;
|
||||
|
||||
if (g_signaling_heap_base != nullptr) {
|
||||
Libraries::Kernel::sceKernelMunmap(g_signaling_heap_base,
|
||||
static_cast<u64>(g_signaling_heap_size));
|
||||
g_signaling_heap_base = nullptr;
|
||||
g_signaling_heap_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
s32 CheckAppType() {
|
||||
s32 app_type = -1;
|
||||
const s32 rc = GetInferredAppType(&app_type);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (app_type == 5) {
|
||||
const s16 gate = GetAppTypeStateGate();
|
||||
if (gate != 0) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
SetAppTypeMarker(0x245a);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 StartMainRuntime(s32 thread_priority, s32 cpu_affinity_mask, s64 thread_stack_size) {
|
||||
LOG_DEBUG(Lib_NpSignaling,
|
||||
"thread_priority={} cpu_affinity_mask={} "
|
||||
"thread_stack_size={}",
|
||||
thread_priority, cpu_affinity_mask, thread_stack_size);
|
||||
|
||||
if (!g_runtime_hooks_registered) {
|
||||
return ORBIS_NP_SIGNALING_INTERNAL_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
const s32 priority = thread_priority;
|
||||
const u64 affinity = static_cast<u64>(static_cast<u32>(cpu_affinity_mask));
|
||||
const u64 stack_size = static_cast<u64>(thread_stack_size);
|
||||
if (g_runtime_hooks.start_dispatch != nullptr) {
|
||||
g_runtime_hooks.start_dispatch(priority, affinity, stack_size);
|
||||
}
|
||||
if (g_runtime_hooks.start_receive != nullptr) {
|
||||
g_runtime_hooks.start_receive(priority, affinity, stack_size);
|
||||
}
|
||||
if (g_runtime_hooks.start_ping != nullptr) {
|
||||
g_runtime_hooks.start_ping(priority, affinity, stack_size);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 StartEchoRuntime(s32 thread_priority, s32 cpu_affinity_mask) {
|
||||
LOG_DEBUG(Lib_NpSignaling, "thread_priority={} cpu_affinity_mask={}", thread_priority,
|
||||
cpu_affinity_mask);
|
||||
|
||||
auto sock = Libraries::Net::sceNetSocket("SceNpSignalingIoctl", 2, 6, 0);
|
||||
if (sock < 0) {
|
||||
return sock;
|
||||
}
|
||||
|
||||
const s32 ioctl_rc = Libraries::Net::sceNetIoctl();
|
||||
Libraries::Net::sceNetSocketClose(sock);
|
||||
|
||||
g_echo_probe_word2 = 0;
|
||||
g_echo_probe_word3 = 0;
|
||||
g_echo_thread_handle = static_cast<u64>(-1);
|
||||
g_echo_thread_status = -1;
|
||||
return ioctl_rc;
|
||||
}
|
||||
|
||||
void ShutdownRuntime() {
|
||||
if (!g_runtime_hooks_registered) {
|
||||
g_echo_probe_word2 = 0;
|
||||
g_echo_probe_word3 = 0;
|
||||
g_echo_thread_handle = static_cast<u64>(-1);
|
||||
g_echo_thread_status = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_runtime_hooks.stop_ping != nullptr) {
|
||||
g_runtime_hooks.stop_ping();
|
||||
}
|
||||
if (g_runtime_hooks.stop_receive != nullptr) {
|
||||
g_runtime_hooks.stop_receive();
|
||||
}
|
||||
if (g_runtime_hooks.stop_dispatch != nullptr) {
|
||||
g_runtime_hooks.stop_dispatch();
|
||||
}
|
||||
|
||||
g_echo_probe_word2 = 0;
|
||||
g_echo_probe_word3 = 0;
|
||||
g_echo_thread_handle = static_cast<u64>(-1);
|
||||
g_echo_thread_status = -1;
|
||||
}
|
||||
|
||||
} // namespace Libraries::Np::NpSignaling::Helpers
|
||||
|
||||
namespace Libraries::Np::NpSignaling {
|
||||
|
||||
using Libraries::Net::sceNetNtohs;
|
||||
|
||||
static Kernel::PthreadT g_dispatch_thread{};
|
||||
static Kernel::PthreadT g_receive_thread{};
|
||||
static bool g_receive_stop = false;
|
||||
static Kernel::PthreadT g_ping_thread{};
|
||||
static bool g_ping_stop = false;
|
||||
|
||||
static void HandleStunEcho(s32 ctx_id, const StunEcho& echo) {
|
||||
SignalingMutexGuard lock;
|
||||
const auto it = g_contexts.find(ctx_id);
|
||||
if (it == g_contexts.end() || !it->second.active) {
|
||||
return;
|
||||
}
|
||||
NpSignalingContext& ctx = it->second;
|
||||
ctx.ext_addr.store(echo.ext_ip);
|
||||
ctx.ext_port.store(echo.ext_port);
|
||||
|
||||
LOG_DEBUG(Lib_NpSignaling, "STUN echo: ctxId={} ext_addr={:#x} ext_port={}", ctx_id,
|
||||
echo.ext_ip, sceNetNtohs(echo.ext_port));
|
||||
|
||||
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
|
||||
netinfo->SetExternalIp(echo.ext_ip);
|
||||
|
||||
ctx.stun_cv.notify_all();
|
||||
}
|
||||
|
||||
static bool HasSignalingMagic(const u8* buf, size_t nbytes) {
|
||||
return nbytes >= 5 && std::memcmp(buf, kSignalingMagic, sizeof(kSignalingMagic)) == 0;
|
||||
}
|
||||
|
||||
static void DrainControlPackets() {
|
||||
static constexpr u32 kBufSize = 256;
|
||||
u8 buf[kBufSize];
|
||||
for (;;) {
|
||||
u32 from_addr = 0;
|
||||
u16 from_port = 0;
|
||||
const int rc = Stubs::ControlRecvFrom(buf, kBufSize, &from_addr, &from_port);
|
||||
if (rc <= 0) {
|
||||
break;
|
||||
}
|
||||
const auto nbytes = static_cast<size_t>(rc);
|
||||
if (nbytes == sizeof(SignalingControl) && HasSignalingMagic(buf, nbytes) &&
|
||||
buf[4] == static_cast<u8>(SignalingPacketType::Control)) {
|
||||
SignalingControl ctrl{};
|
||||
std::memcpy(&ctrl, buf, sizeof(ctrl));
|
||||
HandleControlPacket(from_addr, from_port, ctrl);
|
||||
} else {
|
||||
LOG_WARNING(Lib_NpSignaling, "ReceiveThread: bad control packet (size={})", nbytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ReceiveThreadMain() {
|
||||
static constexpr u32 kBufSize = 256;
|
||||
u8 buf[kBufSize];
|
||||
|
||||
while (!g_receive_stop) {
|
||||
DrainControlPackets();
|
||||
|
||||
u32 from_addr = 0;
|
||||
u16 from_port = 0;
|
||||
|
||||
const int rc = Stubs::SignalingRecvFrom(buf, kBufSize, &from_addr, &from_port);
|
||||
if (rc <= 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto nbytes = static_cast<size_t>(rc);
|
||||
|
||||
if (nbytes != sizeof(StunEcho)) {
|
||||
LOG_DEBUG(
|
||||
Lib_NpSignaling,
|
||||
"ReceiveThread DATA from {:#x}:{} size={} b0-4={:02x},{:02x},{:02x},{:02x},{:02x}",
|
||||
from_addr, sceNetNtohs(from_port), nbytes, buf[0], buf[1], buf[2], buf[3],
|
||||
nbytes >= 5 ? buf[4] : 0);
|
||||
}
|
||||
|
||||
if (nbytes == sizeof(StunEcho)) {
|
||||
s32 ctx_id = 0;
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
for (const auto& [cid, ctx] : g_contexts) {
|
||||
if (ctx.active) {
|
||||
ctx_id = cid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ctx_id == 0) {
|
||||
continue;
|
||||
}
|
||||
StunEcho echo{};
|
||||
std::memcpy(&echo, buf, sizeof(echo));
|
||||
HandleStunEcho(ctx_id, echo);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!HasSignalingMagic(buf, nbytes)) {
|
||||
LOG_WARNING(Lib_NpSignaling, "ReceiveThread: dropping non-SHAD packet (size={})",
|
||||
nbytes);
|
||||
continue;
|
||||
}
|
||||
const u8 type = buf[4];
|
||||
|
||||
if (nbytes == sizeof(SignalingEchoPing) &&
|
||||
type == static_cast<u8>(SignalingPacketType::EchoPing)) {
|
||||
SignalingEchoPing ping{};
|
||||
std::memcpy(&ping, buf, sizeof(ping));
|
||||
SignalingEchoPong pong{};
|
||||
pong.conn_id = ping.conn_id;
|
||||
pong.orig_ts_us = ping.send_ts_us;
|
||||
Stubs::SignalingSendTo(&pong, sizeof(pong), from_addr, from_port);
|
||||
continue;
|
||||
}
|
||||
if (nbytes == sizeof(SignalingEchoPong) &&
|
||||
type == static_cast<u8>(SignalingPacketType::EchoPong)) {
|
||||
SignalingEchoPong pong{};
|
||||
std::memcpy(&pong, buf, sizeof(pong));
|
||||
const s64 now = NowUs();
|
||||
s32 rtt_us = static_cast<s32>(now - static_cast<s64>(pong.orig_ts_us));
|
||||
if (rtt_us < 0) {
|
||||
rtt_us = 0;
|
||||
}
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
RecordRttSampleLocked(static_cast<s32>(pong.conn_id), rtt_us);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (nbytes == sizeof(SignalingHandshake) &&
|
||||
type == static_cast<u8>(SignalingPacketType::Handshake)) {
|
||||
SignalingHandshake hs{};
|
||||
std::memcpy(&hs, buf, sizeof(hs));
|
||||
HandleHandshakePacket(from_addr, from_port, hs);
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_WARNING(Lib_NpSignaling, "ReceiveThread: unexpected SHAD packet type={} size={}", type,
|
||||
nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
static PS4_SYSV_ABI void* ReceiveThreadFunc(void*) {
|
||||
ReceiveThreadMain();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void StartReceiveThread(s32 priority, u64 affinity_mask, u64 stack_size) {
|
||||
g_receive_stop = false;
|
||||
if (!g_receive_thread) {
|
||||
NpCommon::sceNpCreateThread(&g_receive_thread, ReceiveThreadFunc, nullptr, priority,
|
||||
stack_size, affinity_mask, "SceNpSignalingRecv");
|
||||
}
|
||||
}
|
||||
|
||||
static void StopReceiveThread() {
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
g_receive_stop = true;
|
||||
}
|
||||
if (g_receive_thread) {
|
||||
NpCommon::sceNpJoinThread(g_receive_thread, nullptr);
|
||||
g_receive_thread = {};
|
||||
}
|
||||
}
|
||||
|
||||
static void PingThreadMain() {
|
||||
while (!g_ping_stop) {
|
||||
if (!Stubs::TransportIsReady()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(kSigRetryMs));
|
||||
continue;
|
||||
}
|
||||
|
||||
struct CtxSnapshot {
|
||||
s32 ctx_id;
|
||||
OrbisNpOnlineId online_id{};
|
||||
bool resolved;
|
||||
};
|
||||
std::vector<CtxSnapshot> contexts;
|
||||
{
|
||||
SignalingMutexGuard lock;
|
||||
for (const auto& [ctx_id, ctx] : g_contexts) {
|
||||
if (ctx.active) {
|
||||
contexts.push_back({ctx_id, ctx.owner_online_id, ctx.ext_addr.load() != 0});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const u32 server_addr = Stubs::MmServerAddr();
|
||||
const u16 server_port = Stubs::MmServerUdpPort();
|
||||
|
||||
for (const auto& cs : contexts) {
|
||||
if (server_addr == 0 || server_port == 0) {
|
||||
break;
|
||||
}
|
||||
StunPing ping{};
|
||||
ping.cmd = 0x01;
|
||||
std::memcpy(ping.online_id, cs.online_id.data, ORBIS_NP_ONLINEID_MAX_LENGTH);
|
||||
|
||||
Stubs::SignalingSendTo(&ping, sizeof(ping), server_addr, server_port);
|
||||
}
|
||||
|
||||
SendEchoPings();
|
||||
|
||||
const bool any_unresolved = std::any_of(contexts.begin(), contexts.end(),
|
||||
[](const auto& cs) { return !cs.resolved; });
|
||||
const u32 sleep_ms = any_unresolved ? kSigRetryMs : kSigPingMs;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
|
||||
}
|
||||
}
|
||||
|
||||
static PS4_SYSV_ABI void* PingThreadFunc(void*) {
|
||||
PingThreadMain();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void StartPingThread(s32 priority, u64 affinity_mask, u64 stack_size) {
|
||||
g_ping_stop = false;
|
||||
if (!g_ping_thread) {
|
||||
NpCommon::sceNpCreateThread(&g_ping_thread, PingThreadFunc, nullptr, priority, stack_size,
|
||||
affinity_mask, "SceNpSignalingPing");
|
||||
}
|
||||
}
|
||||
|
||||
static void StopPingThread() {
|
||||
g_ping_stop = true;
|
||||
if (g_ping_thread) {
|
||||
NpCommon::sceNpJoinThread(g_ping_thread, nullptr);
|
||||
g_ping_thread = {};
|
||||
}
|
||||
}
|
||||
|
||||
static void DispatchThreadMain() {
|
||||
for (;;) {
|
||||
ProcessPendingActivations();
|
||||
|
||||
QueuedDispatch dispatch;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(g_dispatch_mutex);
|
||||
for (;;) {
|
||||
if (g_dispatch_stop) {
|
||||
return;
|
||||
}
|
||||
if (g_dispatch_queue.empty()) {
|
||||
g_dispatch_cv.wait_for(lock, std::chrono::seconds(1), [] {
|
||||
return g_dispatch_stop || !g_dispatch_queue.empty();
|
||||
});
|
||||
break;
|
||||
}
|
||||
const auto it = g_dispatch_queue.begin();
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (it->first > now) {
|
||||
g_dispatch_cv.wait_until(lock, it->first);
|
||||
break;
|
||||
}
|
||||
dispatch = std::move(it->second);
|
||||
g_dispatch_queue.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dispatch.callback) {
|
||||
LOG_INFO(Lib_NpSignaling, "t={} ctxId={} connId={} event={}({}) delay={}ms", NowMs(),
|
||||
dispatch.ctx_id, dispatch.conn_id, dispatch.event_type,
|
||||
SignalingEventName(dispatch.event_type), dispatch.delay_ms);
|
||||
LOG_DEBUG(Lib_NpSignaling,
|
||||
"INVOKE signaling_cb={} ctxId={} connId={} event={}({}) errorCode={} arg={}",
|
||||
fmt::ptr(reinterpret_cast<void*>(dispatch.callback)), dispatch.ctx_id,
|
||||
dispatch.conn_id, dispatch.event_type,
|
||||
SignalingEventName(dispatch.event_type), dispatch.error_code,
|
||||
fmt::ptr(dispatch.callback_arg));
|
||||
dispatch.callback(static_cast<u32>(dispatch.ctx_id), static_cast<u32>(dispatch.conn_id),
|
||||
dispatch.event_type, dispatch.error_code, dispatch.callback_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PS4_SYSV_ABI void* DispatchThreadFunc(void*) {
|
||||
DispatchThreadMain();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void StartDispatchThread(s32 priority, u64 affinity_mask, u64 stack_size) {
|
||||
std::lock_guard<std::mutex> lock(g_dispatch_mutex);
|
||||
g_dispatch_stop = false;
|
||||
if (!g_dispatch_thread) {
|
||||
NpCommon::sceNpCreateThread(&g_dispatch_thread, DispatchThreadFunc, nullptr, priority,
|
||||
stack_size, affinity_mask, "SceNpSignalingMain");
|
||||
}
|
||||
}
|
||||
|
||||
static void StopDispatchThread() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_dispatch_mutex);
|
||||
g_dispatch_stop = true;
|
||||
g_dispatch_queue.clear();
|
||||
}
|
||||
g_dispatch_cv.notify_all();
|
||||
if (g_dispatch_thread) {
|
||||
NpCommon::sceNpJoinThread(g_dispatch_thread, nullptr);
|
||||
g_dispatch_thread = {};
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterRuntimeHooks() {
|
||||
Helpers::SetRuntimeHooks({
|
||||
.start_dispatch = StartDispatchThread,
|
||||
.start_receive = StartReceiveThread,
|
||||
.start_ping = StartPingThread,
|
||||
.stop_ping = StopPingThread,
|
||||
.stop_receive = StopReceiveThread,
|
||||
.stop_dispatch = StopDispatchThread,
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Libraries::Np::NpSignaling
|
||||
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Libraries::Np::NpSignaling::Helpers {
|
||||
|
||||
struct SignalingRuntimeHooks {
|
||||
void (*start_dispatch)(s32 priority, u64 affinity_mask, u64 stack_size);
|
||||
void (*start_receive)(s32 priority, u64 affinity_mask, u64 stack_size);
|
||||
void (*start_ping)(s32 priority, u64 affinity_mask, u64 stack_size);
|
||||
void (*stop_ping)();
|
||||
void (*stop_receive)();
|
||||
void (*stop_dispatch)();
|
||||
};
|
||||
|
||||
void SetRuntimeHooks(const SignalingRuntimeHooks& hooks);
|
||||
s32 CheckInitializeAppType(u32* is_app_type_4);
|
||||
s32 InitSignalingHeap(s64 pool_size);
|
||||
void ShutdownSignalingHeap();
|
||||
s32 CheckAppType();
|
||||
s32 StartMainRuntime(s32 thread_priority, s32 cpu_affinity_mask, s64 thread_stack_size);
|
||||
s32 StartEchoRuntime(s32 thread_priority, s32 cpu_affinity_mask);
|
||||
void ShutdownRuntime();
|
||||
|
||||
} // namespace Libraries::Np::NpSignaling::Helpers
|
||||
|
||||
namespace Libraries::Np::NpSignaling {
|
||||
|
||||
void RegisterRuntimeHooks();
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,355 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
#include "core/libraries/np/np_common.h"
|
||||
#include "core/libraries/np/np_signaling/np_signaling.h"
|
||||
#include "core/libraries/np/np_types.h"
|
||||
|
||||
namespace Libraries::Np::NpSignaling {
|
||||
|
||||
extern NpCommon::OrbisNpCalloutContext g_callout_ctx;
|
||||
extern bool g_callout_ctx_active;
|
||||
|
||||
constexpr s64 kActivateCooldownUs = 6'000'000;
|
||||
constexpr s64 kActivateBudgetMaxUs = 600'000'000;
|
||||
constexpr u32 kSigRetryMs = 500;
|
||||
constexpr u32 kSigPingMs = 5'000;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct StunPing {
|
||||
u8 cmd = 0x01;
|
||||
u8 online_id[16]{};
|
||||
u32 local_ip = 0;
|
||||
};
|
||||
static_assert(sizeof(StunPing) == 21, "StunPing must be exactly 21 bytes");
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct StunEcho {
|
||||
u32 ext_ip = 0;
|
||||
u16 ext_port = 0;
|
||||
};
|
||||
static_assert(sizeof(StunEcho) == 6, "StunEcho must be exactly 6 bytes");
|
||||
#pragma pack(pop)
|
||||
|
||||
inline constexpr u8 kSignalingMagic[4] = {'S', 'H', 'A', 'D'};
|
||||
|
||||
enum class SignalingPacketType : u8 {
|
||||
EchoPing = 0x05,
|
||||
EchoPong = 0x06,
|
||||
Handshake = 0x07,
|
||||
Control = 0x10,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SignalingEchoPing {
|
||||
u8 magic[4] = {kSignalingMagic[0], kSignalingMagic[1], kSignalingMagic[2], kSignalingMagic[3]};
|
||||
u8 type = static_cast<u8>(SignalingPacketType::EchoPing);
|
||||
u32 conn_id = 0;
|
||||
u64 send_ts_us = 0;
|
||||
};
|
||||
static_assert(sizeof(SignalingEchoPing) == 17);
|
||||
struct SignalingEchoPong {
|
||||
u8 magic[4] = {kSignalingMagic[0], kSignalingMagic[1], kSignalingMagic[2], kSignalingMagic[3]};
|
||||
u8 type = static_cast<u8>(SignalingPacketType::EchoPong);
|
||||
u32 conn_id = 0;
|
||||
u64 orig_ts_us = 0;
|
||||
};
|
||||
static_assert(sizeof(SignalingEchoPong) == 17);
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SignalingHandshake {
|
||||
u8 magic[4] = {kSignalingMagic[0], kSignalingMagic[1], kSignalingMagic[2], kSignalingMagic[3]};
|
||||
u8 type = static_cast<u8>(SignalingPacketType::Handshake);
|
||||
u8 kind = 0;
|
||||
u8 online_id_from[16]{};
|
||||
u8 online_id_to[16]{};
|
||||
u32 from_conn_id = 0;
|
||||
u32 to_conn_id = 0;
|
||||
u32 mapped_addr = 0;
|
||||
u16 mapped_port = 0;
|
||||
u16 reserved = 0;
|
||||
u64 nonce = 0;
|
||||
};
|
||||
static_assert(sizeof(SignalingHandshake) == 0x3e);
|
||||
#pragma pack(pop)
|
||||
|
||||
enum class HandshakeKind : u8 {
|
||||
Offer = 1,
|
||||
Accept = 2,
|
||||
Check = 3,
|
||||
CheckAck = 4,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SignalingControl {
|
||||
u8 magic[4] = {kSignalingMagic[0], kSignalingMagic[1], kSignalingMagic[2], kSignalingMagic[3]};
|
||||
u8 type = static_cast<u8>(SignalingPacketType::Control);
|
||||
u8 kind = 0;
|
||||
u8 online_id_from[16]{};
|
||||
u8 online_id_to[16]{};
|
||||
u32 from_conn_id = 0;
|
||||
u32 mapped_addr = 0;
|
||||
u16 mapped_port = 0;
|
||||
u16 reason = 0;
|
||||
};
|
||||
static_assert(sizeof(SignalingControl) == 0x32);
|
||||
#pragma pack(pop)
|
||||
|
||||
enum class ControlKind : u8 {
|
||||
ActivationRequest = 1,
|
||||
ActivationAck = 2,
|
||||
Close = 3,
|
||||
Established = 4,
|
||||
};
|
||||
|
||||
enum class ControlReason : u16 {
|
||||
Terminate = 0,
|
||||
Deactivate = 1,
|
||||
};
|
||||
|
||||
enum class ConnState : s32 {
|
||||
Inactive = 0,
|
||||
SendingOffer = 5,
|
||||
WaitOffer = 6,
|
||||
ConnCheck = 7,
|
||||
SendingAccept = 8,
|
||||
WaitAccept = 9,
|
||||
Established = 10,
|
||||
};
|
||||
|
||||
struct ConnectionInfo {
|
||||
OrbisNpSignalingConnectionId conn_id = 0;
|
||||
OrbisNpSignalingContextId ctx_id = 0;
|
||||
|
||||
u32 addr = 0;
|
||||
u16 port = 0;
|
||||
|
||||
u32 local_addr = 0;
|
||||
u16 local_port = 0;
|
||||
|
||||
s32 status = ORBIS_NP_SIGNALING_CONN_STATUS_INACTIVE;
|
||||
|
||||
OrbisNpId npid{};
|
||||
OrbisNpOnlineId online_id{};
|
||||
|
||||
s32 activation_mode = 0;
|
||||
|
||||
static constexpr u32 kProbeSampleCount = 6;
|
||||
s32 probe_rtt_samples[kProbeSampleCount] = {-1, -1, -1, -1, -1, -1};
|
||||
u32 probe_sample_write_index = 0;
|
||||
|
||||
s64 last_echo_ping_us = 0;
|
||||
|
||||
s64 last_peer_rx_us = 0;
|
||||
|
||||
ConnState state = ConnState::Inactive;
|
||||
bool established_fired = false;
|
||||
bool established_event_fired = false;
|
||||
bool peer_activated = false;
|
||||
bool locally_activated = false;
|
||||
bool peer_activated_fired = false;
|
||||
bool peer_established = false;
|
||||
bool mutual_fired = false;
|
||||
bool dead_fired = false;
|
||||
bool is_initiator = false;
|
||||
s64 last_handshake_send_us = 0;
|
||||
|
||||
NpCommon::OrbisNpCalloutEntry timeout_callout{};
|
||||
bool timeout_callout_armed = false;
|
||||
NpCommon::OrbisNpCalloutEntry step_callout{};
|
||||
bool step_callout_armed = false;
|
||||
bool deactivate_lingering = false;
|
||||
|
||||
u32 echo_derived_value = 0;
|
||||
};
|
||||
|
||||
struct NpSignalingContext {
|
||||
OrbisNpSignalingHandler callback{nullptr};
|
||||
void* callback_arg{nullptr};
|
||||
bool active{false};
|
||||
|
||||
u32 flags{0};
|
||||
|
||||
u32 compiled_sdk_version{0};
|
||||
|
||||
u64 account_id{0};
|
||||
u32 platform_type{0};
|
||||
|
||||
OrbisNpId owner_npid{};
|
||||
OrbisNpOnlineId owner_online_id{};
|
||||
|
||||
u16 bound_port{0};
|
||||
|
||||
std::atomic<u32> ext_addr{0};
|
||||
std::atomic<u16> ext_port{0};
|
||||
std::mutex stun_mutex{};
|
||||
std::condition_variable stun_cv{};
|
||||
|
||||
s64 activate_budget_us{0};
|
||||
s64 activate_last_update_us{0};
|
||||
};
|
||||
|
||||
struct CtxNpIdKey {
|
||||
OrbisNpSignalingContextId ctx_id = 0;
|
||||
OrbisNpId npid{};
|
||||
};
|
||||
|
||||
struct CtxNpIdKeyHash {
|
||||
size_t operator()(const CtxNpIdKey& key) const noexcept {
|
||||
size_t hash = static_cast<size_t>(key.ctx_id);
|
||||
const auto* bytes = reinterpret_cast<const u8*>(&key.npid);
|
||||
for (size_t i = 0; i < sizeof(key.npid); ++i) {
|
||||
hash ^= static_cast<size_t>(bytes[i]) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const CtxNpIdKey& lhs, const CtxNpIdKey& rhs) {
|
||||
return lhs.ctx_id == rhs.ctx_id && std::memcmp(&lhs.npid, &rhs.npid, sizeof(lhs.npid)) == 0;
|
||||
}
|
||||
|
||||
struct QueuedDispatch {
|
||||
std::chrono::steady_clock::time_point fire_at{};
|
||||
u32 delay_ms = 0;
|
||||
OrbisNpSignalingContextId ctx_id = 0;
|
||||
OrbisNpSignalingConnectionId conn_id = 0;
|
||||
u32 event_type = 0;
|
||||
u32 error_code = 0;
|
||||
OrbisNpSignalingHandler callback = nullptr;
|
||||
void* callback_arg = nullptr;
|
||||
};
|
||||
|
||||
constexpr u32 kPeerNetInfoRequestIdPrefix = 0x21000000;
|
||||
|
||||
struct PeerNetInfoResult {
|
||||
OrbisNpSignalingContextId ctx_id = 0;
|
||||
OrbisNpSignalingConnectionId conn_id = 0;
|
||||
u32 local_ipv4 = 0;
|
||||
u32 external_ipv4 = 0;
|
||||
u32 nat_route_kind = 0;
|
||||
};
|
||||
|
||||
extern std::unordered_map<s32, NpSignalingContext> g_contexts;
|
||||
extern std::unordered_map<s32, ConnectionInfo> g_connections;
|
||||
extern std::unordered_map<CtxNpIdKey, s32, CtxNpIdKeyHash> g_npid_to_conn;
|
||||
extern std::unordered_map<s32, PeerNetInfoResult> g_peer_netinfo_results;
|
||||
struct PendingActivation {
|
||||
OrbisNpSignalingConnectionId conn_id = 0;
|
||||
std::string peer_online_id;
|
||||
};
|
||||
extern std::vector<PendingActivation> g_pending_activations;
|
||||
extern u32 g_peer_netinfo_next_id;
|
||||
extern u32 g_peak_connection_count;
|
||||
extern u32 g_last_assigned_context_id;
|
||||
extern u32 g_connection_id_seed;
|
||||
extern bool g_initialized;
|
||||
|
||||
extern Libraries::Kernel::PthreadMutexT g_mutex_storage;
|
||||
|
||||
struct SignalingMutexGuard {
|
||||
SignalingMutexGuard();
|
||||
~SignalingMutexGuard();
|
||||
SignalingMutexGuard(const SignalingMutexGuard&) = delete;
|
||||
SignalingMutexGuard& operator=(const SignalingMutexGuard&) = delete;
|
||||
};
|
||||
|
||||
void InitSignalingMutex();
|
||||
void DestroySignalingMutex();
|
||||
|
||||
extern std::multimap<std::chrono::steady_clock::time_point, QueuedDispatch> g_dispatch_queue;
|
||||
extern std::mutex g_dispatch_mutex;
|
||||
extern std::condition_variable g_dispatch_cv;
|
||||
extern bool g_dispatch_stop;
|
||||
|
||||
long long NowMs();
|
||||
s64 NowUs();
|
||||
std::string OnlineIdToString(const OrbisNpOnlineId& online_id_in);
|
||||
std::string OnlineIdFromNpId(const OrbisNpId& np_id);
|
||||
OrbisNpId NpIdFromOnlineId(const OrbisNpOnlineId& online_id);
|
||||
bool OnlineIdEqualsString(const OrbisNpOnlineId& online_id, std::string_view value);
|
||||
bool IsValidNpId(const OrbisNpId& np_id);
|
||||
s32 NormalizeNpId(const void* np_id, OrbisNpId* out_npid, OrbisNpOnlineId* out_online_id = nullptr);
|
||||
CtxNpIdKey MakeCtxNpIdKey(OrbisNpSignalingContextId ctx_id, const OrbisNpId& npid);
|
||||
|
||||
bool IsContextValidLocked(OrbisNpSignalingContextId ctx_id);
|
||||
OrbisNpSignalingContextId AllocateContextIdLocked();
|
||||
OrbisNpSignalingConnectionId AllocateConnectionIdLocked();
|
||||
void RemoveConnectionLocked(OrbisNpSignalingConnectionId conn_id);
|
||||
void RemoveContextConnectionsLocked(OrbisNpSignalingContextId ctx_id);
|
||||
|
||||
s32 ConnectionStateFromStatus(s32 status);
|
||||
|
||||
u32 CaptureCompiledSdkVersion();
|
||||
|
||||
u32 ParseIpv4Nbo(const std::string& dotted);
|
||||
|
||||
s32 GetConnectionInfoInternal(OrbisNpSignalingContextId ctx_id,
|
||||
OrbisNpSignalingConnectionId conn_id, s32 info_code, void* out_a,
|
||||
void* out_b);
|
||||
|
||||
bool ConsumeActivationBudgetGatedLocked(NpSignalingContext& ctx);
|
||||
|
||||
void SnapshotConnectionStatisticsLocked(u32* out_peak, u32* out_active, u32* out_transient,
|
||||
u32* out_established);
|
||||
|
||||
OrbisNpSignalingRequestId StagePeerNetInfoResultLocked(OrbisNpSignalingContextId ctx_id);
|
||||
bool TakePeerNetInfoResultLocked(OrbisNpSignalingContextId ctx_id, s32 req_or_conn_id,
|
||||
PeerNetInfoResult* out);
|
||||
bool DropPeerNetInfoResultLocked(OrbisNpSignalingContextId ctx_id, s32 req_or_conn_id);
|
||||
|
||||
void RecordRttSampleLocked(OrbisNpSignalingConnectionId conn_id, s32 rtt_us);
|
||||
void SendEchoPings();
|
||||
|
||||
void DispatchConnectionEvent(OrbisNpSignalingConnectionId conn_id, s32 event_type, s32 event_data);
|
||||
|
||||
void DispatchPeerActivatedEvent(OrbisNpSignalingConnectionId conn_id);
|
||||
|
||||
void CloseConnectionAndDispatchDead(OrbisNpSignalingConnectionId conn_id, s32 error_code);
|
||||
|
||||
void EstablishConnection(OrbisNpSignalingConnectionId conn_id, bool peer_activated_hint);
|
||||
|
||||
void DeactivateConnectionFaithful(OrbisNpSignalingConnectionId conn_id);
|
||||
|
||||
void TerminateConnectionFaithful(OrbisNpSignalingConnectionId conn_id);
|
||||
|
||||
void StartHandshakeInitiator(OrbisNpSignalingConnectionId conn_id);
|
||||
|
||||
void QueueActivationLocked(OrbisNpSignalingConnectionId conn_id, std::string_view peer_online_id);
|
||||
void ProcessPendingActivations();
|
||||
|
||||
void HandleHandshakePacket(u32 from_addr, u16 from_port, const SignalingHandshake& pkt);
|
||||
|
||||
void ArmConnectTimeoutLocked(OrbisNpSignalingConnectionId conn_id);
|
||||
void ClearLingerAndTimeoutLocked(OrbisNpSignalingConnectionId conn_id);
|
||||
|
||||
void SendActivationRequestLocked(const ConnectionInfo& ci);
|
||||
|
||||
void SendControlCloseLocked(const ConnectionInfo& ci, ControlReason reason);
|
||||
|
||||
void HandleControlPacket(u32 from_addr, u16 from_port, const SignalingControl& pkt);
|
||||
|
||||
const char* SignalingEventName(u32 event_type);
|
||||
bool ConsumeActivationBudgetLocked(NpSignalingContext& ctx);
|
||||
void SendStunPing(OrbisNpSignalingContextId ctx_id);
|
||||
void ClearActiveDeadlines();
|
||||
void ClearConnectionDeadlineForPeer(std::string_view npid);
|
||||
void SetRoomLeft();
|
||||
|
||||
} // namespace Libraries::Np::NpSignaling
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/libraries/np/np_signaling/np_signaling_stubs.h"
|
||||
|
||||
namespace Libraries::Np::NpSignaling::Stubs {
|
||||
|
||||
namespace {
|
||||
TransportHooks g_transport{};
|
||||
PeerResolver g_peer_resolver = nullptr;
|
||||
u32 g_mm_server_addr = 0;
|
||||
u16 g_mm_server_udp_port = 0;
|
||||
} // namespace
|
||||
|
||||
void SetTransportHooks(const TransportHooks& hooks) {
|
||||
g_transport = hooks;
|
||||
}
|
||||
|
||||
int SignalingSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port) {
|
||||
return g_transport.signaling_send ? g_transport.signaling_send(data, len, dest_addr, dest_port)
|
||||
: -1;
|
||||
}
|
||||
|
||||
int SignalingRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port) {
|
||||
return g_transport.signaling_recv ? g_transport.signaling_recv(buf, len, from_addr, from_port)
|
||||
: -1;
|
||||
}
|
||||
|
||||
int ControlSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port) {
|
||||
return g_transport.control_send ? g_transport.control_send(data, len, dest_addr, dest_port)
|
||||
: -1;
|
||||
}
|
||||
|
||||
int ControlRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port) {
|
||||
return g_transport.control_recv ? g_transport.control_recv(buf, len, from_addr, from_port) : -1;
|
||||
}
|
||||
|
||||
bool TransportIsReady() {
|
||||
return g_transport.transport_ready ? g_transport.transport_ready() : false;
|
||||
}
|
||||
|
||||
u16 ConfiguredPort() {
|
||||
return g_transport.configured_port ? g_transport.configured_port() : 0;
|
||||
}
|
||||
|
||||
void SetPeerResolver(PeerResolver fn) {
|
||||
g_peer_resolver = fn;
|
||||
}
|
||||
|
||||
void SetMmServerEndpoint(u32 addr, u16 udp_port) {
|
||||
g_mm_server_addr = addr;
|
||||
g_mm_server_udp_port = udp_port;
|
||||
}
|
||||
|
||||
bool ResolvePeer(std::string_view online_id, u32* out_addr, u16* out_port) {
|
||||
return g_peer_resolver ? g_peer_resolver(online_id, out_addr, out_port) : false;
|
||||
}
|
||||
|
||||
u32 MmServerAddr() {
|
||||
return g_mm_server_addr;
|
||||
}
|
||||
|
||||
u16 MmServerUdpPort() {
|
||||
return g_mm_server_udp_port;
|
||||
}
|
||||
|
||||
} // namespace Libraries::Np::NpSignaling::Stubs
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Libraries::Np::NpSignaling::Stubs {
|
||||
|
||||
struct TransportHooks {
|
||||
int (*signaling_send)(const void* data, u32 len, u32 dest_addr, u16 dest_port) = nullptr;
|
||||
int (*signaling_recv)(void* buf, u32 len, u32* from_addr, u16* from_port) = nullptr;
|
||||
int (*control_send)(const void* data, u32 len, u32 dest_addr, u16 dest_port) = nullptr;
|
||||
int (*control_recv)(void* buf, u32 len, u32* from_addr, u16* from_port) = nullptr;
|
||||
bool (*transport_ready)() = nullptr;
|
||||
u16 (*configured_port)() = nullptr;
|
||||
};
|
||||
void SetTransportHooks(const TransportHooks& hooks);
|
||||
|
||||
int SignalingSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port);
|
||||
int SignalingRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port);
|
||||
int ControlSendTo(const void* data, u32 len, u32 dest_addr, u16 dest_port);
|
||||
int ControlRecvFrom(void* buf, u32 len, u32* from_addr, u16* from_port);
|
||||
bool TransportIsReady();
|
||||
u16 ConfiguredPort();
|
||||
|
||||
using PeerResolver = bool (*)(std::string_view online_id, u32* out_addr, u16* out_port);
|
||||
void SetPeerResolver(PeerResolver fn);
|
||||
void SetMmServerEndpoint(u32 addr, u16 udp_port);
|
||||
|
||||
bool ResolvePeer(std::string_view online_id, u32* out_addr, u16* out_port);
|
||||
u32 MmServerAddr();
|
||||
u16 MmServerUdpPort();
|
||||
|
||||
} // namespace Libraries::Np::NpSignaling::Stubs
|
||||
Reference in New Issue
Block a user