Clans: improved ticket requesting and waiting logic

Using proper atomic synchronisation primitives, instead of a busy loop

Signed-off-by: zeph <zephyrzefa15@gmail.com>
This commit is contained in:
zeph 2025-12-08 15:15:56 +01:00
parent c358deaf9d
commit 198c965f8b
No known key found for this signature in database
5 changed files with 64 additions and 38 deletions

View File

@ -19,9 +19,6 @@ const char* REQ_TYPE_SEC = "sec";
constexpr const char JID_FORMAT[] = "%s@un.br.np.playstation.net";
const char* CLANS_SERVICE_ID = "IV0001-NPXS01001_00";
const char* CLANS_ENTITLEMENT_ID = "NPWR00432_00";
template <>
void fmt_class_string<clan::ClanRequestType>::format(std::string& out, u64 arg)
{
@ -274,39 +271,18 @@ namespace clan
}
std::string clans_client::getClanTicket(np::np_handler& nph)
{
if (nph.get_ticket().size() > 0)
{
std::vector<byte> ticket_bytes(1024);
uint32_t ticket_size = UINT32_MAX;
Base64_Encode_NoNl(nph.get_ticket().data(), nph.get_ticket().size(), ticket_bytes.data(), &ticket_size);
return std::string(reinterpret_cast<char*>(ticket_bytes.data()), ticket_size);
}
{
const auto& npid = nph.get_npid();
const char* service_id = CLANS_SERVICE_ID;
const unsigned char* cookie = nullptr;
const u32 cookie_size = 0;
const char* entitlement_id = CLANS_ENTITLEMENT_ID;
const u32 consumed_count = 0;
const char* service_id = CLANS_SERVICE_ID;
const unsigned char* cookie = nullptr;
const u32 cookie_size = 0;
const char* entitlement_id = CLANS_ENTITLEMENT_ID;
const u32 consumed_count = 0;
nph.req_ticket(0x00020001, &npid, service_id, cookie, cookie_size, entitlement_id, consumed_count);
nph.req_ticket(0x00020001, &npid, service_id, cookie, cookie_size, entitlement_id, consumed_count);
np::ticket ticket;
// TODO: convert this to use events?
int retries = 0;
while (ticket.empty() && retries < 100)
{
ticket = nph.get_ticket();
if (ticket.empty())
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
retries++;
}
}
np::ticket ticket = nph.get_clan_ticket();
if (ticket.empty())
{
@ -314,14 +290,14 @@ namespace clan
return "";
}
std::vector<byte> ticket_bytes(1024);
uint32_t ticket_size = UINT32_MAX;
std::vector<byte> ticket_bytes(1024);
uint32_t ticket_size = UINT32_MAX;
Base64_Encode_NoNl(ticket.data(), ticket.size(), ticket_bytes.data(), &ticket_size);
std::string ticket_str = std::string(reinterpret_cast<char*>(ticket_bytes.data()), ticket_size);
Base64_Encode_NoNl(ticket.data(), ticket.size(), ticket_bytes.data(), &ticket_size);
std::string ticket_str = std::string(reinterpret_cast<char*>(ticket_bytes.data()), ticket_size);
return ticket_str;
}
return ticket_str;
}
#pragma region Outgoing API Requests
SceNpClansError clans_client::getClanList(np::np_handler& nph, s32 reqId, SceNpClansPagingRequest* paging, SceNpClansEntry* clanList, SceNpClansPagingResult* pageResult)

View File

@ -6,6 +6,9 @@
#include <Emu/IdManager.h>
#include <pugixml.hpp>
inline const char* CLANS_ENTITLEMENT_ID = "NPWR00432_00";
inline const char* CLANS_SERVICE_ID = "IV0001-NPXS01001_00";
namespace clan
{
enum class ClanManagerOperationType

View File

@ -239,6 +239,25 @@ namespace np
return true;
}
std::string ticket::get_service_id() const
{
if (!parse_success)
{
return "";
}
const auto& node = nodes[0].data.data_nodes[8];
if (node.len != SCE_NP_SERVICE_ID_SIZE)
{
return "";
}
// Trim null characters
const auto& vec = node.data.data_vec;
auto it = std::find(vec.begin(), vec.end(), 0);
return std::string(vec.begin(), it);
}
std::optional<ticket_data> ticket::parse_node(std::size_t index) const
{
if ((index + MIN_TICKET_DATA_SIZE) > size())
@ -1345,6 +1364,13 @@ namespace np
return history;
}
ticket np_handler::get_clan_ticket()
{
std::unique_lock lock(mutex_clan_ticket);
cv_clan_ticket.wait(lock, [this] { return clan_ticket_ready.load(); });
return clan_ticket;
}
constexpr usz MAX_HISTORY_ENTRIES = 200;
void np_handler::add_player_to_history(const SceNpId* npid, const char* description)

View File

@ -3,6 +3,7 @@
#include <queue>
#include <map>
#include <unordered_map>
#include <condition_variable>
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/Modules/sceNp.h"
@ -69,6 +70,7 @@ namespace np
bool empty() const;
bool get_value(s32 param_id, vm::ptr<SceNpTicketParam> param) const;
std::string get_service_id() const;
private:
std::optional<ticket_data> parse_node(std::size_t index) const;
@ -253,6 +255,7 @@ namespace np
// Misc stuff
void req_ticket(u32 version, const SceNpId* npid, const char* service_id, const u8* cookie, u32 cookie_size, const char* entitlement_id, u32 consumed_count);
const ticket& get_ticket() const;
ticket get_clan_ticket();
void add_player_to_history(const SceNpId* npid, const char* description);
u32 add_players_to_history(const SceNpId* npids, const char* description, u32 count);
u32 get_players_history_count(u32 options);
@ -415,6 +418,12 @@ namespace np
ticket current_ticket;
// Clan ticket
std::mutex mutex_clan_ticket;
std::condition_variable_any cv_clan_ticket;
atomic_t<bool> clan_ticket_ready = false;
ticket clan_ticket;
// IP & DNS info
std::string hostname = "localhost";
std::array<u8, 6> ether_address{};

View File

@ -1,5 +1,6 @@
#include "Emu/Cell/Modules/sceNp.h"
#include "Emu/Cell/Modules/sceNp2.h"
#include "Emu/NP/clans_client.h"
#include "Emu/NP/rpcn_types.h"
#include "Utilities/StrFmt.h"
#include "stdafx.h"
@ -866,6 +867,17 @@ namespace np
current_ticket = ticket(std::move(ticket_raw));
auto ticket_size = static_cast<s32>(current_ticket.size());
// Clans: check if ticket belongs to the clan service. If so, store it.
if (current_ticket.get_service_id() == CLANS_SERVICE_ID)
{
std::lock_guard lock(mutex_clan_ticket);
clan_ticket = current_ticket;
clan_ticket_ready = true;
cv_clan_ticket.notify_all();
return;
}
if (manager_cb)
{
sysutil_register_cb([manager_cb = this->manager_cb, ticket_size, manager_cb_arg = this->manager_cb_arg](ppu_thread& cb_ppu) -> s32