feat(libSceNetCtlApDialog): run the offline access-point dialog lifecycle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d53960612f
commit
dbecde00e0
|
|
@ -206,6 +206,16 @@ if(BUILD_TESTING)
|
|||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSigninDialog>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_netctl_ap_dialog_tests tests/GuestNetCtlApDialog.cpp)
|
||||
target_include_directories(guest_netctl_ap_dialog_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_netctl_ap_dialog_tests PRIVATE libSceNetCtlApDialog libc)
|
||||
configure_windows_unwind(guest_netctl_ap_dialog_tests)
|
||||
add_test(NAME guest_netctl_ap_dialog COMMAND guest_netctl_ap_dialog_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_netctl_ap_dialog PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNetCtlApDialog>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_rudp_status_tests tests/GuestRudpStatus.cpp)
|
||||
target_include_directories(guest_rudp_status_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_rudp_status_tests PRIVATE libSceRudp libc)
|
||||
|
|
|
|||
|
|
@ -1,38 +1,78 @@
|
|||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int COMMON_DIALOG_STATUS_NONE = 0;
|
||||
constexpr int COMMON_DIALOG_STATUS_INITIALIZED = 1;
|
||||
constexpr int COMMON_DIALOG_STATUS_RUNNING = 2;
|
||||
constexpr int COMMON_DIALOG_STATUS_FINISHED = 3;
|
||||
constexpr int COMMON_DIALOG_ERROR_NOT_INITIALIZED = static_cast<int>(0x80B80003u);
|
||||
constexpr int COMMON_DIALOG_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x80B80004u);
|
||||
constexpr int COMMON_DIALOG_ERROR_NOT_FINISHED = static_cast<int>(0x80B80005u);
|
||||
constexpr int COMMON_DIALOG_ERROR_BUSY = static_cast<int>(0x80B80007u);
|
||||
constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);
|
||||
constexpr int COMMON_DIALOG_RESULT_USER_CANCELED = 1;
|
||||
|
||||
struct SceNetCtlApDialogResult {
|
||||
std::int32_t result = COMMON_DIALOG_RESULT_USER_CANCELED;
|
||||
std::uint8_t reserved[36] = {};
|
||||
};
|
||||
|
||||
static_assert(sizeof(SceNetCtlApDialogResult) == 40);
|
||||
|
||||
std::atomic<int> g_status{COMMON_DIALOG_STATUS_NONE};
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceNetCtlApDialogInitialize(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int expected = COMMON_DIALOG_STATUS_NONE;
|
||||
if (!g_status.compare_exchange_strong(expected, COMMON_DIALOG_STATUS_INITIALIZED)) return COMMON_DIALOG_ERROR_ALREADY_INITIALIZED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetCtlApDialogTerminate(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (g_status.exchange(COMMON_DIALOG_STATUS_NONE) == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetCtlApDialogOpen(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNetCtlApDialogOpen(const void* param) {
|
||||
const int status = g_status.load();
|
||||
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
|
||||
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
|
||||
if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
|
||||
g_status = COMMON_DIALOG_STATUS_FINISHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetCtlApDialogClose(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (g_status.load() == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
|
||||
g_status = COMMON_DIALOG_STATUS_FINISHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetCtlApDialogUpdateStatus(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return g_status.load();
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetCtlApDialogGetResult(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNetCtlApDialogGetStatus(void) {
|
||||
return g_status.load();
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetCtlApDialogGetResult(void* result) {
|
||||
const int status = g_status.load();
|
||||
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
|
||||
if (status != COMMON_DIALOG_STATUS_FINISHED) return COMMON_DIALOG_ERROR_NOT_FINISHED;
|
||||
if (result == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
|
||||
const SceNetCtlApDialogResult dialogResult{};
|
||||
std::memcpy(result, &dialogResult, sizeof(dialogResult));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceNetCtlApDialogInitialize(void);
|
||||
int APS5_VABI sceNetCtlApDialogTerminate(void);
|
||||
int APS5_VABI sceNetCtlApDialogOpen(const void* param);
|
||||
int APS5_VABI sceNetCtlApDialogClose(void);
|
||||
int APS5_VABI sceNetCtlApDialogUpdateStatus(void);
|
||||
int APS5_VABI sceNetCtlApDialogGetStatus(void);
|
||||
int APS5_VABI sceNetCtlApDialogGetResult(void* result);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void Require(bool value) { if (!value) std::abort(); }
|
||||
|
||||
constexpr int kStatusNone = 0;
|
||||
constexpr int kStatusInitialized = 1;
|
||||
constexpr int kStatusFinished = 3;
|
||||
constexpr int kErrNotInitialized = static_cast<int>(0x80B80003);
|
||||
constexpr int kErrAlreadyInitialized = static_cast<int>(0x80B80004);
|
||||
constexpr int kErrNotFinished = static_cast<int>(0x80B80005);
|
||||
constexpr int kErrArgNull = static_cast<int>(0x80B8000D);
|
||||
constexpr int kResultUserCanceled = 1;
|
||||
|
||||
void RequireCanceled(const std::uint8_t (&result)[44]) {
|
||||
std::int32_t code = 0;
|
||||
std::memcpy(&code, result, sizeof(code));
|
||||
Require(code == kResultUserCanceled);
|
||||
for (int i = 4; i < 40; ++i) Require(result[i] == 0);
|
||||
for (int i = 40; i < 44; ++i) Require(result[i] == 0x5a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::uint8_t param[104] = {};
|
||||
std::uint8_t result[44];
|
||||
std::memset(result, 0x5a, sizeof(result));
|
||||
|
||||
Require(sceNetCtlApDialogTerminate() == kErrNotInitialized);
|
||||
Require(sceNetCtlApDialogOpen(param) == kErrNotInitialized);
|
||||
Require(sceNetCtlApDialogClose() == kErrNotInitialized);
|
||||
Require(sceNetCtlApDialogGetResult(result) == kErrNotInitialized);
|
||||
Require(sceNetCtlApDialogGetStatus() == kStatusNone);
|
||||
Require(sceNetCtlApDialogUpdateStatus() == kStatusNone);
|
||||
|
||||
Require(sceNetCtlApDialogInitialize() == 0);
|
||||
Require(sceNetCtlApDialogInitialize() == kErrAlreadyInitialized);
|
||||
Require(sceNetCtlApDialogGetStatus() == kStatusInitialized);
|
||||
Require(sceNetCtlApDialogUpdateStatus() == kStatusInitialized);
|
||||
|
||||
Require(sceNetCtlApDialogOpen(nullptr) == kErrArgNull);
|
||||
Require(sceNetCtlApDialogGetStatus() == kStatusInitialized);
|
||||
Require(sceNetCtlApDialogGetResult(result) == kErrNotFinished);
|
||||
|
||||
Require(sceNetCtlApDialogOpen(param) == 0);
|
||||
Require(sceNetCtlApDialogGetStatus() == kStatusFinished);
|
||||
Require(sceNetCtlApDialogUpdateStatus() == kStatusFinished);
|
||||
|
||||
Require(sceNetCtlApDialogGetResult(nullptr) == kErrArgNull);
|
||||
Require(sceNetCtlApDialogGetResult(result) == 0);
|
||||
RequireCanceled(result);
|
||||
|
||||
Require(sceNetCtlApDialogOpen(param) == 0);
|
||||
Require(sceNetCtlApDialogClose() == 0);
|
||||
Require(sceNetCtlApDialogTerminate() == 0);
|
||||
Require(sceNetCtlApDialogTerminate() == kErrNotInitialized);
|
||||
Require(sceNetCtlApDialogGetStatus() == kStatusNone);
|
||||
|
||||
Require(sceNetCtlApDialogInitialize() == 0);
|
||||
Require(sceNetCtlApDialogClose() == 0);
|
||||
Require(sceNetCtlApDialogGetStatus() == kStatusFinished);
|
||||
std::memset(result, 0x5a, sizeof(result));
|
||||
Require(sceNetCtlApDialogGetResult(result) == 0);
|
||||
RequireCanceled(result);
|
||||
Require(sceNetCtlApDialogTerminate() == 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# libSceNetCtlApDialog technical debt
|
||||
|
||||
### Silent stubs
|
||||
|
||||
- [libSceNetCtlApDialog](../../../core/libs/prx/libSceNetCtlApDialog/Export.cpp) - the access-point dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled, as no access-point connection is brought up. `Open` takes the 104-byte parameter block and `GetResult` writes a 40-byte result (int32 result and 36 zeroed reserved bytes), following [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/60977b29103452b9681ae10c7a9011d44965bf16/src/SharpProspero/Interop/Net/NetCtlApDialog.cs); the parameter block is not validated and the 0x80B8xxxx error codes follow the other common dialogs, neither verified on hardware. Deathloop imports it
|
||||
Loading…
Reference in New Issue