Files
AnyPS5/docs/dev/debt/libSceRudp.md
T
harisibrar1andClaude Opus 5.5 b934ab8af1 fix(libSceRudp): drain only the cancelled waits and release a wait's registration on every exit
sceRudpPollCancel waited until no wait was registered, so a wait that
started during the drain kept it blocked, forever for an infinite one.
Waits registered when the cancel starts now move to a draining count,
and the cancel returns once those have left. A scope guard releases each
wait's registration on every exit, retaking the lock if the wait had
dropped it, so an exception in the condition wait no longer leaves a
registration that a later cancel can never drain. Reported by
@MarcZX10, @thepoppfish, @adriadam10 and @oneandonlydean; the guard
follows @thepoppfish's repair.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 01:26:57 -04:00

8.2 KiB

libSceRudp technical debt

Silent stubs

  • sceRudpProcessEvents, sceRudpNetFlush and sceRudpNetReceived (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, send or receive; the three calls return success after sceRudpInit and RUDP_ERROR_NOT_INITIALIZED before it, as shadPS4 returns OK from its stubs. What the console's sceRudpNetReceived returns is unverified. PPSA03490 calls sceRudpProcessEvents(0) followed by sceRudpNetFlush() from its P2P service thread and ignores the first result.
  • sceRudpEnableInternalIOThread2 (libSceRudp) takes (uint32_t stack_size, uint32_t priority, uint64_t affinity), taken from the managed SceRudp.Rudp.EnableInternalIOThread(uint stackSize, uint priority, ulong affinity) in PPSA06888's Unity metadata; the first two match sceRudpEnableInternalIOThread. It returns success after sceRudpInit and RUDP_ERROR_NOT_INITIALIZED before it, as sceRudpEnableInternalIOThread does, without starting any thread. Whether the console reports other errors, and whether it applies the affinity, is unverified.
  • sceRudpActivate takes a context ID, socket address and 32-bit address length. Initialization and initial argument checks match the native implementation; transport mode checks, address conversion and connection activation remain unimplemented and throw.

Unknown function info

  • sceRudpGetStatus - PPSA01521 passes an output pointer and byte count 0xF8. Measured on a PS5 (firmware 13.60): the status is 0xF8 bytes; before sceRudpInit every call returns RUDP_ERROR_NOT_INITIALIZED, and after it a null pointer or a byte count of 0 or above 0xF8 returns RUDP_ERROR_INVALID_ARGUMENT. The layout matches SceRudpStatus in Vita3K with currentContexts at 0x64 and allocs, frees, memCurrent and memPeak at 0xC8 to 0xD4. Only currentContexts is reported: the traffic counters stay 0 because nothing is sent, and the allocator counters stay 0 because the library does not allocate from the title's pool (the console reports 6 allocations and 0x1260 bytes right after sceRudpInit, and 4 more allocations and 0x3F0 bytes per context). The console also writes currentContexts and the allocator counters when the byte count is smaller than their offset; only the requested bytes are written here.
  • sceRudpGetMaxSegmentSize (libSceRudp) - measured on a PS5 (firmware 13.60) in #3073: before sceRudpInit it returns RUDP_ERROR_NOT_INITIALIZED and leaves the value untouched, also for a null pointer; after it a null pointer returns RUDP_ERROR_INVALID_ARGUMENT and a valid one gets 1410 with result 0. No source says whether a size stored by sceRudpSetMaxSegmentSize is reported instead, so 1410 is always reported.
  • sceRudpSetMaxSegmentSize (libSceRudp) - unverified on a PS5. (uint16_t mss) and the checks follow Vita3K, with the argument in RPCS3: RUDP_ERROR_NOT_INITIALIZED before sceRudpInit, RUDP_ERROR_NOT_ACCEPTABLE while a context exists, otherwise stored without a range check and kept across sceRudpEnd, as Vita3K keeps it in its library state. Nothing reads the stored size: Vita3K leaves the getter unimplemented, so sceRudpGetMaxSegmentSize keeps the measured 1410
  • sceRudpGetOption, sceRudpSetOption (libSceRudp) - full PS5 option contracts are unverified; defaults and validation follow Vita3K. Options 12 and 13 have unknown meanings; last-error option 14 is not maintained. Their setters store all 32 bits per context and return 0 for valid four-byte buffers, preserving acceptance on main; their getters throw. Static inspection of PPSA06888 v01.001.008's bundled Unity transport shows its context-set constructor configuring IDs 2, 3, 5 and 6; runtime usage and other paths remain unverified. The plugin wrappers pass four-byte values. No context can connect, so stored settings cannot affect traffic. Closes when: PS5 option contracts are verified and the remaining behavior is implemented.
  • sceRudpPollCreate, sceRudpPollControl, sceRudpPollWait, sceRudpPollDestroy - console hardware behavior and removal of the last entry during an existing wait remain unverified. A firmware 13.42 report executes the actual module under emulation with kernel/libc imports stubbed and condition waits scripted, not on console hardware: an empty poll waits for its remaining timeout, including after spurious wakes, and leaves event output untouched. This agrees with the retained wait behavior here and conflicts with the immediate empty return in Vita3K. The argument checks, control operations and 8-byte event layout retain their existing sources; the firmware report has not been independently reproduced here.
  • sceRudpPollCancel (libSceRudp) - unmeasured: a wait that starts while a cancel is draining. Here the drain waits only for the waits registered when it started; a later wait is neither cancelled nor counted. The rest is measured on a retail PS5 (firmware 13.60) through the real libSceRudp.sprx (@HabibUrRehmanBhattii), matching @BunnyFl's 13.42 library run: int sceRudpPollCancel(int pollId) returns 0x80770001 before sceRudpInit, 0x80770004 for a negative id and 0x8077001F for an unknown one. With no waiter, one cancellation is kept per poll and the next sceRudpPollWait, even with a zero timeout, returns 0x80770014 at once. With waiters, all return 0x80770014, the call returns 0 after they leave, and nothing stays pending.
  • sceRudpPollDestroy and sceRudpEnd - draining remains incomplete. The detailed firmware 13.42 report executes the module with emulated/stubbed imports. In the scripted two-waiter Destroy case both waiters return 0x80770014; Destroy drains them before returning, then destroys the condition variable. A later wait on that destroyed ID returns 0x8077001F. End similarly drains its active waiter with 0x80770014; subsequent Wait/Cancel calls return 0x80770001. Here Destroy/End return without draining and wake existing waiters with 0x8077001F/0x80770001. Real-kernel wake/timeout races, simultaneous control calls, End/re-init overlap and extreme timeout boundaries remain untested; the report is not a console hardware measurement or an independent reproduction here.
  • sceRudpAccept, sceRudpFlush, sceRudpGetLocalInfo and sceRudpListen - remain throwing placeholders. Their names and NIDs are present in the PS5 3.20 export inventory; their parameterless declarations solely resolve known imports and do not establish the ABI.