mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
libNet: finish NpCommerce dialogs at open (#1166)
* libNet: finish NpCommerce dialogs at open * libNet: complete NpCommerce dialog cancellation --------- Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
+73
-3
@@ -1497,13 +1497,43 @@ namespace LibNpCommerce {
|
|||||||
|
|
||||||
LIB_VERSION("NpCommerce", 1, "NpCommerce", 1, 1);
|
LIB_VERSION("NpCommerce", 1, "NpCommerce", 1, 1);
|
||||||
|
|
||||||
constexpr int COMMERCE_STATUS_NONE = 0;
|
constexpr int COMMERCE_STATUS_NONE = 0;
|
||||||
constexpr int COMMERCE_STATUS_INITIALIZED = 1;
|
constexpr int COMMERCE_STATUS_INITIALIZED = 1;
|
||||||
|
constexpr int COMMERCE_STATUS_FINISHED = 3;
|
||||||
|
constexpr int COMMERCE_RESULT_USER_CANCELED = 1;
|
||||||
|
|
||||||
constexpr int COMMERCE_ERROR_NOT_INITIALIZED = static_cast<int>(0x80B80003u);
|
constexpr int COMMERCE_ERROR_NOT_INITIALIZED = static_cast<int>(0x80B80003u);
|
||||||
constexpr int COMMERCE_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x80B80004u);
|
constexpr int COMMERCE_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x80B80004u);
|
||||||
|
constexpr int COMMERCE_ERROR_NOT_FINISHED = static_cast<int>(0x80B80005u);
|
||||||
|
constexpr int COMMERCE_ERROR_PARAM_INVALID = static_cast<int>(0x80B8000Au);
|
||||||
|
constexpr int COMMERCE_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);
|
||||||
|
|
||||||
static int g_commerce_status = COMMERCE_STATUS_NONE;
|
struct CommerceDialogParam {
|
||||||
|
uint8_t base_param[48];
|
||||||
|
int32_t size;
|
||||||
|
int32_t user_id;
|
||||||
|
int32_t mode;
|
||||||
|
uint32_t service_label;
|
||||||
|
const char* const* targets;
|
||||||
|
uint32_t num_targets;
|
||||||
|
uint32_t padding;
|
||||||
|
uint64_t features;
|
||||||
|
void* user_data;
|
||||||
|
uint8_t reserved[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommerceDialogResult {
|
||||||
|
int32_t result;
|
||||||
|
bool authorized;
|
||||||
|
void* user_data;
|
||||||
|
uint8_t reserved[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(CommerceDialogParam) == 128 && offsetof(CommerceDialogParam, user_data) == 88);
|
||||||
|
static_assert(sizeof(CommerceDialogResult) == 48 && offsetof(CommerceDialogResult, user_data) == 8);
|
||||||
|
|
||||||
|
static int g_commerce_status = COMMERCE_STATUS_NONE;
|
||||||
|
static CommerceDialogResult g_commerce_result {};
|
||||||
|
|
||||||
static int KYTY_SYSV_ABI NpCommerceDialogInitialize() {
|
static int KYTY_SYSV_ABI NpCommerceDialogInitialize() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
@@ -1520,9 +1550,47 @@ static int KYTY_SYSV_ABI NpCommerceDialogTerminate() {
|
|||||||
return COMMERCE_ERROR_NOT_INITIALIZED;
|
return COMMERCE_ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
g_commerce_status = COMMERCE_STATUS_NONE;
|
g_commerce_status = COMMERCE_STATUS_NONE;
|
||||||
|
g_commerce_result = {};
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int KYTY_SYSV_ABI NpCommerceDialogOpen(const CommerceDialogParam* param) {
|
||||||
|
PRINT_NAME();
|
||||||
|
if (g_commerce_status == COMMERCE_STATUS_NONE) {
|
||||||
|
return COMMERCE_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (param == nullptr) {
|
||||||
|
return COMMERCE_ERROR_ARG_NULL;
|
||||||
|
}
|
||||||
|
g_commerce_result = {};
|
||||||
|
if (param->size == sizeof(CommerceDialogParam)) {
|
||||||
|
g_commerce_result.user_data = param->user_data;
|
||||||
|
}
|
||||||
|
g_commerce_status = COMMERCE_STATUS_FINISHED;
|
||||||
|
if (param->size != sizeof(CommerceDialogParam) || param->mode < 0 || param->mode > 5 ||
|
||||||
|
std::ranges::any_of(param->reserved, [](uint8_t value) { return value != 0; })) {
|
||||||
|
g_commerce_result.result = COMMERCE_ERROR_PARAM_INVALID;
|
||||||
|
return COMMERCE_ERROR_PARAM_INVALID;
|
||||||
|
}
|
||||||
|
g_commerce_result.result = COMMERCE_RESULT_USER_CANCELED;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int KYTY_SYSV_ABI NpCommerceDialogGetResult(CommerceDialogResult* result) {
|
||||||
|
PRINT_NAME();
|
||||||
|
if (g_commerce_status == COMMERCE_STATUS_NONE) {
|
||||||
|
return COMMERCE_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (result == nullptr) {
|
||||||
|
return COMMERCE_ERROR_ARG_NULL;
|
||||||
|
}
|
||||||
|
if (g_commerce_status != COMMERCE_STATUS_FINISHED) {
|
||||||
|
return COMMERCE_ERROR_NOT_FINISHED;
|
||||||
|
}
|
||||||
|
*result = g_commerce_result;
|
||||||
|
return result->result;
|
||||||
|
}
|
||||||
|
|
||||||
static int KYTY_SYSV_ABI NpCommerceDialogUpdateStatus() {
|
static int KYTY_SYSV_ABI NpCommerceDialogUpdateStatus() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
@@ -1532,6 +1600,8 @@ static int KYTY_SYSV_ABI NpCommerceDialogUpdateStatus() {
|
|||||||
LIB_DEFINE(InitNet_1_NpCommerce) {
|
LIB_DEFINE(InitNet_1_NpCommerce) {
|
||||||
LIB_FUNC("0aR2aWmQal4", NpCommerceDialogInitialize);
|
LIB_FUNC("0aR2aWmQal4", NpCommerceDialogInitialize);
|
||||||
LIB_FUNC("m-I92Ab50W8", NpCommerceDialogTerminate);
|
LIB_FUNC("m-I92Ab50W8", NpCommerceDialogTerminate);
|
||||||
|
LIB_FUNC("DfSCDRA3EjY", NpCommerceDialogOpen);
|
||||||
|
LIB_FUNC("r42bWcQbtZY", NpCommerceDialogGetResult);
|
||||||
LIB_FUNC("LR5cwFMMCVE", NpCommerceDialogUpdateStatus);
|
LIB_FUNC("LR5cwFMMCVE", NpCommerceDialogUpdateStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ namespace Libs::LibNpWebApi2 {
|
|||||||
void InitNet_1_NpWebApi2(Loader::SymbolDatabase *symbols);
|
void InitNet_1_NpWebApi2(Loader::SymbolDatabase *symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Libs::LibNpCommerce {
|
||||||
|
void InitNet_1_NpCommerce(Loader::SymbolDatabase *symbols);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
namespace FileSystem = Libs::LibKernel::FileSystem;
|
namespace FileSystem = Libs::LibKernel::FileSystem;
|
||||||
@@ -385,6 +389,91 @@ void TestAioBatches() {
|
|||||||
Check(FileSystem::KernelClose(fd) == OK, "close AIO read fixture");
|
Check(FileSystem::KernelClose(fd) == OK, "close AIO read fixture");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestNpCommerceDialog() {
|
||||||
|
Loader::SymbolDatabase symbols;
|
||||||
|
Libs::LibNpCommerce::InitNet_1_NpCommerce(&symbols);
|
||||||
|
const auto find = [&](const char *nid) {
|
||||||
|
const auto *symbol = symbols.FindByNid(nid, Loader::SymbolType::Func);
|
||||||
|
Check(symbol != nullptr, "NpCommerce dialog exports resolve");
|
||||||
|
return symbol->vaddr;
|
||||||
|
};
|
||||||
|
using Call = int (KYTY_SYSV_ABI *)();
|
||||||
|
using Open = int (KYTY_SYSV_ABI *)(const void *);
|
||||||
|
using GetResult = int (KYTY_SYSV_ABI *)(void *);
|
||||||
|
const auto initialize = reinterpret_cast<Call>(find("0aR2aWmQal4"));
|
||||||
|
const auto terminate = reinterpret_cast<Call>(find("m-I92Ab50W8"));
|
||||||
|
const auto update = reinterpret_cast<Call>(find("LR5cwFMMCVE"));
|
||||||
|
const auto open = reinterpret_cast<Open>(find("DfSCDRA3EjY"));
|
||||||
|
const auto get_result = reinterpret_cast<GetResult>(find("r42bWcQbtZY"));
|
||||||
|
struct BaseParam {
|
||||||
|
uint64_t size;
|
||||||
|
uint8_t reserved[36];
|
||||||
|
uint32_t magic;
|
||||||
|
};
|
||||||
|
struct Param {
|
||||||
|
BaseParam base;
|
||||||
|
int32_t size, user_id, mode;
|
||||||
|
uint32_t service_label;
|
||||||
|
const char *const *targets;
|
||||||
|
uint32_t num_targets, padding;
|
||||||
|
uint64_t features;
|
||||||
|
void *user_data;
|
||||||
|
uint8_t reserved[32];
|
||||||
|
} param {};
|
||||||
|
struct Result {
|
||||||
|
int32_t result;
|
||||||
|
bool authorized;
|
||||||
|
void *user_data;
|
||||||
|
uint8_t reserved[32];
|
||||||
|
} result {};
|
||||||
|
static_assert(sizeof(Param) == 128 && offsetof(Param, user_data) == 88);
|
||||||
|
static_assert(sizeof(Result) == 48 && offsetof(Result, user_data) == 8);
|
||||||
|
param.base.size = sizeof(BaseParam);
|
||||||
|
param.base.magic = static_cast<uint32_t>(0xC0D1A109u + reinterpret_cast<uintptr_t>(¶m.base));
|
||||||
|
param.size = sizeof(param);
|
||||||
|
param.user_id = 1;
|
||||||
|
param.user_data = &symbols;
|
||||||
|
Check(open(¶m) == static_cast<int>(0x80B80003u) &&
|
||||||
|
get_result(&result) == static_cast<int>(0x80B80003u),
|
||||||
|
"NpCommerce dialog calls require initialization");
|
||||||
|
Check(initialize() == OK && update() == 1 &&
|
||||||
|
get_result(&result) == static_cast<int>(0x80B80005u),
|
||||||
|
"NpCommerce dialog result requires completion");
|
||||||
|
Check(open(nullptr) == static_cast<int>(0x80B8000Du) && update() == 1 &&
|
||||||
|
get_result(nullptr) == static_cast<int>(0x80B8000Du),
|
||||||
|
"NpCommerce dialog rejects null arguments");
|
||||||
|
Check(open(¶m) == OK && update() == 3, "NpCommerce dialog finishes without a store");
|
||||||
|
param.user_data = nullptr;
|
||||||
|
result.authorized = true;
|
||||||
|
Check(get_result(&result) == 1 && result.result == 1 && !result.authorized &&
|
||||||
|
result.user_data == &symbols,
|
||||||
|
"NpCommerce cancellation returns the original user data");
|
||||||
|
param.mode = 5;
|
||||||
|
Check(open(¶m) == OK && get_result(&result) == 1 && !result.authorized &&
|
||||||
|
result.user_data == nullptr,
|
||||||
|
"NpCommerce dialog can reopen with fresh result data");
|
||||||
|
const auto invalid_param = [&] {
|
||||||
|
Check(open(¶m) == static_cast<int>(0x80B8000Au) && update() == 3 &&
|
||||||
|
get_result(&result) == static_cast<int>(0x80B8000Au) &&
|
||||||
|
result.result == static_cast<int>(0x80B8000Au) && !result.authorized,
|
||||||
|
"NpCommerce dialog reports invalid parameters in the completion result");
|
||||||
|
};
|
||||||
|
param.mode = 99;
|
||||||
|
invalid_param();
|
||||||
|
param.mode = -1;
|
||||||
|
invalid_param();
|
||||||
|
param.mode = 0;
|
||||||
|
param.size = 64;
|
||||||
|
invalid_param();
|
||||||
|
param.size = sizeof(param);
|
||||||
|
param.reserved[0] = 1;
|
||||||
|
invalid_param();
|
||||||
|
param.reserved[0] = 0;
|
||||||
|
Check(open(¶m) == OK && get_result(&result) == 1 && terminate() == OK && update() == 0 &&
|
||||||
|
get_result(&result) == static_cast<int>(0x80B80003u),
|
||||||
|
"NpCommerce dialog recovers from invalid parameters and terminates");
|
||||||
|
}
|
||||||
|
|
||||||
void TestNpWebApi2Memory() {
|
void TestNpWebApi2Memory() {
|
||||||
Loader::SymbolDatabase symbols;
|
Loader::SymbolDatabase symbols;
|
||||||
Libs::LibNpWebApi2::InitNet_1_NpWebApi2(&symbols);
|
Libs::LibNpWebApi2::InitNet_1_NpWebApi2(&symbols);
|
||||||
@@ -1644,6 +1733,7 @@ int main(int, char**) {
|
|||||||
CheckSocketWakeup();
|
CheckSocketWakeup();
|
||||||
CheckEtherAddressFormatting();
|
CheckEtherAddressFormatting();
|
||||||
TestNpWebApi2Memory();
|
TestNpWebApi2Memory();
|
||||||
|
TestNpCommerceDialog();
|
||||||
graphics.reset();
|
graphics.reset();
|
||||||
subsystems.Destroy();
|
subsystems.Destroy();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user