diff --git a/core/libs/CMakeLists.txt b/core/libs/CMakeLists.txt index 2e8057fd3..23a160828 100644 --- a/core/libs/CMakeLists.txt +++ b/core/libs/CMakeLists.txt @@ -219,6 +219,16 @@ if(BUILD_TESTING) "PATH=path_list_prepend:$") endif() + add_test_executable(guest_rudp_pump_tests tests/GuestRudpPump.cpp) + target_include_directories(guest_rudp_pump_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(guest_rudp_pump_tests PRIVATE libSceRudp libc) + configure_windows_unwind(guest_rudp_pump_tests) + add_test(NAME guest_rudp_pump COMMAND guest_rudp_pump_tests) + if(WIN32) + set_tests_properties(guest_rudp_pump PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() + add_test_executable(guest_memory_pool_stats_tests tests/GuestMemoryPoolStats.cpp) target_include_directories(guest_memory_pool_stats_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(guest_memory_pool_stats_tests PRIVATE libSceSsl libSceHttp2 libSceNet libkernel libc) diff --git a/core/libs/prx/libSceRudp/Export.cpp b/core/libs/prx/libSceRudp/Export.cpp index 132ea291f..a10f455bd 100644 --- a/core/libs/prx/libSceRudp/Export.cpp +++ b/core/libs/prx/libSceRudp/Export.cpp @@ -242,4 +242,25 @@ int APS5_VABI sceRudpRead(int ctx_id, void* data, uint32_t len, int flags, void* } return valid_ctx(ctx_id) ? RUDP_ERROR_CONN_RESET : RUDP_ERROR_INVALID_CONTEXT_ID; } + +int APS5_VABI sceRudpNetFlush(void) { + std::lock_guard lk(g_mutex); + return g_inited ? 0 : RUDP_ERROR_NOT_INITIALIZED; +} + +int APS5_VABI sceRudpProcessEvents(void) { + std::lock_guard lk(g_mutex); + return g_inited ? 0 : RUDP_ERROR_NOT_INITIALIZED; +} + +int APS5_VABI sceRudpNetReceived(void) { + NotImplemented_nid_no_patch(__func__); + return 0; +} + +int APS5_VABI sceRudpGetMaxSegmentSize(void) { + NotImplemented_nid_no_patch(__func__); + return 0; +} + } diff --git a/core/libs/tests/GuestRudpPump.cpp b/core/libs/tests/GuestRudpPump.cpp new file mode 100644 index 000000000..36cf63cb4 --- /dev/null +++ b/core/libs/tests/GuestRudpPump.cpp @@ -0,0 +1,47 @@ +#include "prx/libc/include/general/VabiMacros.hpp" + +#include +#include +#include +#include +#include + +extern "C" { +int APS5_VABI sceRudpInit_nid_postfix(void*, int); +int APS5_VABI sceRudpTerminate(); +int APS5_VABI sceRudpProcessEvents(); +int APS5_VABI sceRudpNetFlush(); +int APS5_VABI sceRudpGetMaxSegmentSize(); +int APS5_VABI sceRudpNetReceived(); +} + +static void Require(bool value, int line) { + if (!value) { + std::fprintf(stderr, "rudp check failed at line %d\n", line); + std::abort(); + } +} +#define CHECK(value) Require((value), __LINE__) + +int main() { + constexpr int notInitialized = static_cast(0x80770001); + CHECK(sceRudpProcessEvents() == notInitialized); + CHECK(sceRudpNetFlush() == notInitialized); + + alignas(8) static unsigned char pool[0xC58]; + CHECK(sceRudpInit_nid_postfix(pool, sizeof(pool)) == 0); + CHECK(sceRudpProcessEvents() == 0); + CHECK(sceRudpNetFlush() == 0); + CHECK(sceRudpTerminate() == 0); + + for (const auto call : {&sceRudpNetReceived, &sceRudpGetMaxSegmentSize}) { + bool threw = false; + try { + call(); + } catch (const std::runtime_error&) { + threw = true; + } + CHECK(threw); + } + return 0; +} diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index d79ada8f2..778c87b3e 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -40,6 +40,7 @@ Throughout the project, every function at every stage either **does exactly what - [libSceHttp2](../../core/libs/prx/libSceHttp2/Export.cpp) - no request reaches the network, so `sceHttp2SetMinSslVersion` has no TLS connection to restrict and its value is ignored, as for `sceHttp2SslEnableOption` and `sceHttp2SslDisableOption`. The three setters validate `id` against the live handle registry and return `SCE_HTTP2_ERROR_INVALID_ID` (`0x817B1100`) for a handle that was never allocated, was deleted, or belonged to a terminated context, following [prosper](https://github.com/mattias800/prosper). Whether the console restricts the object kind these setters accept, and what it does with an id from a previous init/term cycle, is unverified, so any live handle kind is accepted and ids are never reused. `sceHttp2Term`, `sceHttp2DeleteTemplate`, `sceHttp2DeleteRequest`, `sceHttp2CreateTemplate`, `sceHttp2CreateRequestWithURL`, `sceHttp2CreateCookieBox` and `sceHttp2SendRequestAsync` also return the invalid-id error for a handle of the wrong kind or no longer live, following prosper (not measured on a console) - [libSceNpTrophy2](../../core/libs/prx/libSceNpTrophy2/src/GameInfo.cpp): `sceNpTrophy2RegisterUnlockCallback` accepts a callback that is never called, as no trophy is ever unlocked, `sceNpTrophy2UnregisterUnlockCallback` only returns success, and `sceNpTrophy2ShowTrophyList` returns success without showing a list (there is no system trophy UI; seen on PPSA15552). - [sceAvPlayerSetTrickSpeed](../../core/libs/prx/libSceAvPlayer/src/Source.cpp) (libSceAvPlayer) with a negative speed runs the clock backwards but delivers no frames; when a forward speed is set again, playback resumes from the rewound time. +- [sceRudpProcessEvents and sceRudpNetFlush](../../core/libs/prx/libSceRudp/Export.cpp) (libSceRudp) - there is no reliable-UDP stack on the host, and every `sceRudpWrite`, `sceRudpRead` and `sceRudpGetStatus` call here reports a reset or idle context without queueing data, so no context ever holds pending data to process or send; both calls return success after `sceRudpInit` and `RUDP_ERROR_NOT_INITIALIZED` before it, as [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/rudp/rudp.cpp) returns OK from its stubs. PPSA03490 calls `sceRudpProcessEvents(0)` followed by `sceRudpNetFlush()` from its P2P service thread and ignores the first result; whether the real calls take parameters is unknown - [sceRudpActivate](../../core/libs/prx/libSceRudp/Export.cpp) (libSceRudp) - there is no reliable-UDP stack on the host to activate, so it returns success without doing anything, as [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/rudp/rudp.cpp) does for its own `sceRudpActivate`. PPSA01325 calls it with no arguments during start-up; what the console activates, and whether it reports an error before `sceRudpInit`, is unverified - [ulobjmgr](../../core/libs/prx/ulobjmgr/Export.cpp) registers no object: `_sceUlobjmgrRegisterObject` always hands out id 0 and `_sceUlobjmgrUnregisterObject` releases nothing, as shadPS4 does - [libSceHttp](../../core/libs/prx/libSceHttp/Export.cpp) - no request reaches the network, so `sceHttpSetResponseHeaderMaxSize` has no response header to limit, `sceHttpSetRecvBlockSize` (`(int id, u32 blockSize)` as in [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/network/http.h)) no response body to read in blocks and `sceHttpRedirectCacheFlush` no redirect to forget; `sceHttpsUnloadCert` returns success like `sceHttpsLoadCert`, which keeps no certificate; `sceHttpSetRedirectCallback` and `sceHttpSetCookieRecvCallback` accept callbacks that are never called, `sceHttpsSetSslVersion` has no TLS connection to configure and `sceHttpsGetSslError` reports error 0 with detail 0; `sceHttpSetAuthInfoCallback` accepts a callback that is never called, as no server asks for authentication; `sceHttpsGetCaList` and `sceHttpsFreeCaList` report an empty CA list (`certs` null, `certsNum` 0) and return 0, as no CA store is kept, and a null list returns `ERROR_INVALID_VALUE`; unlike shadPS4 they do not check that `http_ctx_id` is a live context nor that the library is initialised, and `sceHttpsFreeCaList` also nulls `certs`, which shadPS4 leaves untouched. The signatures and the `{ void* certs; int certsNum; }` layout follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/network/http.h) (PS4), not confirmed on a PS5 title