Skip to content

fix(libkernel): read and write guest sockets - #1727

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
SleglJan:feat/libkernel-socket-read-write
Oct 10, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
SleglJan:feat/libkernel-socket-read-write

Conversation

@SleglJan

@SleglJan SleglJan commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

What

read, write, _read and _write on a guest socket descriptor (0x10000000 and up) went to the host as if the number were a host descriptor, so sceKernelRead and sceKernelWrite threw (sceKernelWrite: write failed, fd=…, errno=9) on the first byte a title moved through a socket that way. On the console both are the socket's recv and send without flags (soo_read/soo_write).

  • GuestSockets::Read and GuestSockets::Write in the socket runtime forward to recv and send with flags 0, so the socket layer's errno applies: EAGAIN (35) on an empty non-blocking socket, EPIPE (32) after the peer closed, EBADF (9) on a closed descriptor. A zero-length read returns 0 without touching the socket, as dofileread does, and a read longer than INT_MAX is clamped.
  • read, write, _read and _write route descriptors at or above GuestSockets::FirstDescriptor to them; sceKernelRead and sceKernelWrite do the same, before their null-buffer check, and return the kernel error (0x80020023 for EAGAIN, 0x80020009 for EBADF) instead of throwing.
  • Recorded in TechnicalDebt: EPIPE raises the host's SIGPIPE on Linux, which the guest can neither ignore nor suppress, and nothing on Windows (the console raises it unless SO_NOSIGPIPE); a write above INT_MAX bytes is EMSGSIZE; readv, writev, pread, pwrite, their sceKernel forms and AIO on a guest socket still go to the host.

The 15 catalog titles whose OpenSSL QUIC notifier creates a socketpair (#1711, open) signal it with write and drain it with read (rio_notifier.c through writesocket/readsocket); the same applies to any TCP socket a title reads with read.

Overlap: #1307 rewrites the four wrappers in Stdio.cpp (the socket branch has to stay first); #1711 and #1708 insert a TechnicalDebt line at the same place; #1091 and #1738 add declarations to SocketRuntime.hpp, and #1091 code to Udp.cpp near the table, where this adds two declarations and two functions at the end. Whichever merges second rebases. The pr-overlap report's __error_nid_postfix rows (#1613, #1616, #1627, #1675) are the shared extern "C" declaration of the errno accessor that Open.cpp now adds, not an export.

Tested

  • Linux (CachyOS, kernel 7.2.9, GCC 16.2.1), full build with BUILD_TESTING=ON and ANYPS5_ENABLE_SPIRV_TOOLS=ON on this branch (based on main b83e849): ctest --repeat until-fail:3 467/467; tools/check_test_registration.py and tools/check_conventions.py --base upstream/main pass.
  • New guest_socket_read_write test over a TCP loopback pair: write/read, _write/_read and sceKernelWrite/sceKernelRead carrying data both ways; EAGAIN and 0x80020023 on an empty non-blocking socket; zero-length reads returning 0; 0 from both forms after the peer closed; (Linux) EPIPE on write after the peer closed, with the host's SIGPIPE ignored by the test since a title cannot; EBADF and 0x80020009 from every entry point on a closed descriptor. Each receive waits with poll first, accepting POLLHUP after the close. Written before the change: on main it aborts with the sceKernelWrite throw above; it passes with the change.
  • Windows: the same Build workflow run on this commit in the fork's Actions (merged onto main 6b56175), run 37822108157: guest_socket_read_write passes its three repeats, full suite 474/474; the test excludes only the EPIPE case there, like guest_tcp.
  • Rebased onto main db06355 (head 9d0b105; git range-diff shows only context lines changed). Local full ctest: 541/542; the failure, agc_driver_dcc_keys_first_write, fails on main too ([bug] agc_driver_dcc_keys_first_write fails on main on a real NVIDIA GPU #2188). The fork's Build workflow on this head merged into main 8b393b6, run 37996682292: the relinker jobs pass and guest_socket_read_write passes on Linux; Linux fails only guest_video_out_resolution_status (a main test that aborts on the runner's offscreen SDL driver), and Windows stops building libSceVideoOut.prx on the duplicate export from Windows build fails on main: duplicate patched export name: LibwuIonIBw in libSceVideoOut (since #1339) #2462, both also on main.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes (Claude Code)

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#1755 core/libs/prx/libkernel/File/src/Open.cpp L6
#1764 core/libs/prx/libkernel/File/src/Open.cpp L6
#2144 core/libs/prx/libkernel/File/src/Open.cpp L135-138, L148-156
#2545 core/libs/tests/GuestSocketReadWrite.cpp

@hikazey

hikazey commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Windows run, since the description lists Linux only: Windows 11 Pro (26200), MinGW-w64 GCC 15.2.0 (WinLibs r7, the CI build), Release, configured like CI, Ryzen 9 5900X. This commit merged onto main b858fdc4; only docs/dev/TechnicalDebt.md needed an auto-merge.

build guest_socket_read_write
this PR 5/5 passed
sceKernelWrite's socket branch removed, test kept 5/5 failed: sceKernelWrite: write failed, fd=268435457, errno=9, the original throw
full suite with this PR 478/478 passed

One Windows difference the test doesn't cover, since the peer-closed write case is #ifndef _WIN32. I added a local probe there for Windows: close(client), then write_nid_postfix(server, …) in a loop. In all 5 runs the second write returns -1 with errno 53 (ECONNABORTED): Winsock's WSAECONNABORTED, mapped by NativeError. On Linux, and in FreeBSD's sosend, the same sequence gives 32 (EPIPE). A title that checks for EPIPE after the peer closed would see a different errno on Windows. That may be worth a line next to the SIGPIPE entry in TechnicalDebt, or a follow-up that maps it for send/write on a connected stream socket. I haven't checked how the console reports a reset (as opposed to an orderly close) there.

AI-assisted: yes (Claude Code).

read, write, _read and _write on a guest socket descriptor went to the
host, which has no such descriptor, so sceKernelRead and sceKernelWrite
threw. They now reach the socket as recv and send without flags, with
the socket layer's errno (EAGAIN 35, EPIPE 32, EBADF 9), a zero-length
read returns 0 as dofileread does, and the two sceKernel forms return
the kernel error for the same cases. The host's SIGPIPE on EPIPE, a
write above INT_MAX bytes, readv, writev and the positioned forms are
recorded in TechnicalDebt.

OpenSSL's QUIC notifier signals its socketpair with write and read.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@SleglJan
SleglJan force-pushed the feat/libkernel-socket-read-write branch from 62aa3af to 9d0b105 Compare October 9, 2026 21:59
oneandonlydean added a commit to oneandonlydean/AnyPS5 that referenced this pull request Oct 10, 2026
oneandonlydean added a commit to oneandonlydean/AnyPS5 that referenced this pull request Oct 10, 2026
@oneandonlydean
oneandonlydean merged commit a8ce7b7 into boykopovar:main Oct 10, 2026
9 checks passed
SleglJan pushed a commit to SleglJan/AnyPS5 that referenced this pull request Oct 10, 2026
…t-read-write

fix(libkernel): read and write guest sockets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants