Skip to content

fix(libkernel): accept MSG_NOSIGNAL in send and sendto - #1279

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
TheAggie:fix/libkernel-send-nosignal
Oct 8, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
TheAggie:fix/libkernel-send-nosignal

Conversation

@TheAggie

@TheAggie TheAggie commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

What

send, sendto and sendmsg (which forwards to sendto) failed every call with a nonzero flags with EOPNOTSUPP. FreeBSD code commonly passes MSG_NOSIGNAL (0x20000) to avoid SIGPIPE on a closed connection, so such callers could not send at all.

  • MSG_NOSIGNAL is accepted. Windows sockets never raise SIGPIPE, so nothing is passed there; on Linux it maps to the native MSG_NOSIGNAL.
  • Any other flag still fails with EOPNOTSUPP, as before.
  • guest_tcp: send with MSG_OOB (0x1) still fails with EOPNOTSUPP; send with MSG_NOSIGNAL succeeds and the data arrives. guest_udp: sendto with MSG_NOSIGNAL succeeds. Both tests fail without the change.

Tested

Windows 11 Pro (26200), MinGW-w64 GCC 15.2.0 (WinLibs r7), Release, NVIDIA GeForce RTX 5070 Ti.

Not tested on Linux.

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

🤖 Generated with Claude Code

@hikazey

hikazey commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Linux run, since the description says it wasn't tested there (Ubuntu 24.04, GCC 14.2, this commit applied to current main 6b57386, which it applies to cleanly).

The PR's own tests: guest_tcp and guest_udp pass with the change and fail with Udp.cpp from main.

The Linux-specific part is what MSG_NOSIGNAL is for: sending on a connection the peer has closed. Nothing in the tree ignores SIGPIPE, so on Linux the native flag is what keeps the process alive. I added that case to guest_tcp: close accepted, then send from client with 0x20000 until it fails. That turned up one gap. The Linux branch of NativeError has no EPIPE case, so the failure is reported as 5 (EIO) instead of FreeBSD's EPIPE (32), which is what callers that pass MSG_NOSIGNAL usually check for.

--- a/core/libs/prx/libkernel/Socket/src/Udp.cpp
+++ b/core/libs/prx/libkernel/Socket/src/Udp.cpp
@@ int NativeError() {
         case EINVAL: return 22;
+        case EPIPE: return 32;
         default: return 5;
--- a/core/libs/tests/GuestTcp.cpp
+++ b/core/libs/tests/GuestTcp.cpp
@@
     Require(close_nid_postfix(accepted) == 0);
+#ifndef _WIN32
+    std::int64_t sent = 0;
+    for (int i = 0; i < 100 && sent >= 0; ++i) sent = send_nid_postfix(client, request, sizeof(request), 0x20000);
+    Require(sent == -1 && *__error_nid_postfix() == 32);
+#endif
     Require(close_nid_postfix(client) == 0);
build guest_tcp with the case above
this PR aborted (errno 5, not 32)
this PR + EPIPE mapping passed
this PR + EPIPE mapping, NativeSendFlags returning 0 on Linux killed by SIGPIPE

The last row shows the MSG_NOSIGNAL mapping is needed on Linux. With the mapping, the 8 socket-related tests (-R 'tcp|udp|net|socket|address|poll|epoll') pass. I ran the case without the #ifndef. I guarded it because Winsock reports a reset or aborted connection there, not EPIPE; I haven't checked which one on Windows.

AI-assisted: yes (Claude Code).

TheAggie and others added 2 commits October 8, 2026 12:36
send, sendto and sendmsg rejected every flag with EOPNOTSUPP, so callers
that pass FreeBSD's MSG_NOSIGNAL (0x20000) could not send at all. Accept
it: Windows sockets never raise SIGPIPE, and on Linux it maps to the
native MSG_NOSIGNAL. Other flags still fail with EOPNOTSUPP.

DOOM (PPSA99666) sends its upload server replies with MSG_NOSIGNAL and
closed every connection without an answer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a closed peer

Case and test by hikazey in the PR thread.

Co-authored-by: hikazey <hikazey@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked: build + full ctest (439/439) on current main, guest_tcp/guest_udp fail with the Udp.cpp change reverted, Linux and Windows CI green. MSG_NOSIGNAL = 0x20000 matches FreeBSD; mapping to the native flag on Linux is needed (without it the process dies with SIGPIPE, as hikazey showed).

Added as our own commit, taken from hikazey's comment (Co-authored-by):

  • NativeError (Linux): EPIPE → 32. Sending to a closed peer returned 5 (EIO) instead of EPIPE.
  • guest_tcp: send with MSG_NOSIGNAL after the peer closed must fail with 32 (#ifndef _WIN32; not checked what Winsock reports there).

Merging once CI is green on the new head.

@adriadam10
adriadam10 force-pushed the fix/libkernel-send-nosignal branch from e91e87c to 065280d Compare October 8, 2026 10:48
@adriadam10
adriadam10 merged commit 615262f into boykopovar:main Oct 8, 2026
4 checks passed
@hikazey

hikazey commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

.hikaze for dev role in Discord

danzaio added a commit to danzaio/AnyPS5 that referenced this pull request Oct 9, 2026
sceNetSend and sceNetSendto rejected every flag with EOPNOTSUPP, so a
caller passing FreeBSD's MSG_NOSIGNAL (0x20000) could not send at all.
The guard now accepts that flag and keeps failing every other one.
shadPS4 already passes 0x20000 down to sendto, and the native send
already uses MSG_NOSIGNAL on Linux, so widening the guard is enough.

The libkernel send and sendto got the same fix in boykopovar#1279.
danzaio added a commit to danzaio/AnyPS5 that referenced this pull request Oct 9, 2026
sceNetSend and sceNetSendto rejected every flag with EOPNOTSUPP, so a
caller passing FreeBSD's MSG_NOSIGNAL (0x20000) could not send at all.
The guard now accepts that flag and keeps failing every other one.
shadPS4 already passes 0x20000 down to sendto, and the native send
already uses MSG_NOSIGNAL on Linux, so widening the guard is enough.

The libkernel send and sendto got the same fix in boykopovar#1279.
danzaio added a commit to danzaio/AnyPS5 that referenced this pull request Oct 10, 2026
sceNetSend and sceNetSendto rejected every flag with EOPNOTSUPP, so a
caller passing FreeBSD's MSG_NOSIGNAL (0x20000) could not send at all.
The guard now accepts that flag and keeps failing every other one.
shadPS4 already passes 0x20000 down to sendto, and the native send
already uses MSG_NOSIGNAL on Linux, so widening the guard is enough.

The libkernel send and sendto got the same fix in boykopovar#1279.
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