On Linux, socket() and sceNetSocket() create AF_INET6 sockets in the
host's default dual-stack mode (net.ipv6.bindv6only is 0), so a wildcard
IPv6 bind also claims the IPv4 port. A title that keeps an IPv4 and an
IPv6 socket on the same port fails: with 0.0.0.0:P bound, binding [::]:P
returns EADDRINUSE (48), and an IPv6 socket bound to [::] also receives
IPv4 traffic from v4-mapped peers.
FreeBSD makes every new IPv6 socket IPv6-only. sys/netinet6/in6_proto.c:
VNET_DEFINE(int, ip6_v6only) = 1;
sys/netinet/in_pcb.c, in_pcballoc():
if (INP_SOCKAF(so) == AF_INET6) {
inp->inp_vflag |= INP_IPV6PROTO;
if (V_ip6_v6only)
inp->inp_flags |= IN6P_IPV6_V6ONLY;
}
and sys/netinet6/in6_pcb.c, in6_pcbbind(), looks for an IPv4 owner of
the port only when the flag is clear:
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
socket() and sceNetSocket() now set IPV6_V6ONLY on every IPv6 socket
they create. Windows already defaults to it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libkernel's setsockopt() hands options for a libSceNet socket to
sceNetSetsockopt(), whose SO_RCVTIMEO and SO_SNDTIMEO take an int of
microseconds. The POSIX call takes a struct timeval, so main read the
low half of tv_sec as microseconds: {1, 250000} set a 1 microsecond
receive timeout, {0, 500000} set 0, which disables the timeout, and an
out-of-range tv_usec was accepted.
FreeBSD reads a struct timeval, sys/kern/uipc_socket.c, sosetopt():
case SO_SNDTIMEO:
case SO_RCVTIMEO:
...
error = sooptcopyin(sopt, &tv, sizeof tv,
sizeof tv);
if (error)
goto bad;
if (tv.tv_sec < 0 || tv.tv_usec < 0 ||
tv.tv_usec >= 1000000) {
error = EDOM;
goto bad;
}
and sooptcopyin() fails a shorter value with EINVAL:
if ((valsize = sopt->sopt_valsize) < minlen)
return EINVAL;
setsockopt() on a libSceNet socket now converts the timeval for these
two options, with EINVAL for a short value and EDOM for a negative or
out-of-range one. sceNetSetsockopt() keeps taking microseconds; both
paths share the code that sets the host timeout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A title creating a socket with sceNetSocket sets its options with the BSD
setsockopt, which looked the descriptor up only among libkernel's own
sockets and returned EBADF. libSceNet now registers an option setter with
libkernel, as it does for close and select, and accepts SO_REUSEADDR,
SO_BROADCAST, SO_SNDBUF and SO_RCVBUF like libkernel's own sockets.
PPSA01289 (Sackboy: A Big Adventure) sets SO_BROADCAST on its UDP P2P
socket this way in UIpNetDriver::InitBase. The failure made every listen
fail, and the engine travelled back to its default map with ?closed,
reloading it about every two seconds behind the loading screen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libSceNet stored its errno only in its own slot (sceNetErrnoLoc). Titles
that use the BSD socket model read errno after a libSceNet call, as the
console's libSceNet calls are kernel calls that set it; shadPS4 mirrors its
net errno into the kernel errno the same way (SetKernelErrnoHook).
PPSA01289 (Sackboy: A Big Adventure) reads errno through Unreal's
GetLastErrorCode after sceNetRecvfrom. It never saw EWOULDBLOCK, so
UIpNetDriver::TickDispatch kept receiving and the game thread never left
its first networked frame.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A libSceNet socket is a kernel descriptor on the console, so titles close it
with close(). libSceNet keeps its sockets in its own table, and libkernel's
close passed their numbers to the CRT, which reported an invalid parameter
and left the socket open. libSceNet now registers a closer with libkernel,
as it registers its poller for select. PPSA01289 (Sackboy: A Big Adventure)
closes its P2P socket this way each time it tears its network session down,
leaking one open socket per attempt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceNetEpollControl used Linux's EPOLL_CTL numbering (1 ADD, 2 DEL, 3 MOD).
The SCE values are 1 ADD, 2 MOD, 3 DEL (shadPS4 net_types.h,
ORBIS_NET_EPOLL_CTL_*). A title removing a socket with op 3 and a null
event got EINVAL, and op 2 deleted the registration it meant to modify.
PPSA01289 (Sackboy: A Big Adventure) removes its UDP socket from its epoll
this way before closing it, every time its network session is torn down.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With SO_RCVTIMEO set, Winsock fails a receive that waits that long with
WSAETIMEDOUT, which native_error turned into ETIMEDOUT (60). sceNetRecv,
sceNetRecvfrom and sceNetRecvmsg on a datagram socket therefore failed
with 0x8041013C on Windows, where FreeBSD's sbwait returns EWOULDBLOCK
(35) to soreceive, Linux returns EAGAIN, and POSIX (XSH 2.10.16)
requires EAGAIN or EWOULDBLOCK when no data was received.
A datagram socket has no connection that can time out, so WSAETIMEDOUT
there only means that the receive timeout the guest set has expired:
report EAGAIN. Stream sockets keep ETIMEDOUT, since Winsock leaves a
connection in an indeterminate state after a timeout; TechnicalDebt
records that gap and the one for SO_SNDTIMEO.
Forwards _sceUltWaitingQueueResourcePoolCreate and _sceUltSemaphoreCreate to the existing calls, like the other underscore Ult exports. Declares sceNetShowIfconfig, sceNpWebApi2GetMemoryPoolStats, Json::Value::setNullAccessCallBack, kqueue, kevent and one pad call of unknown name without an implementation.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Measured on a PS5 (firmware 13.60):
- sceSslGetMemoryPoolStats returns 0x8095F007 for a null output, before
the id check, and 0x8095F006 for an unknown or terminated context,
zeroing the 32-byte output.
- sceHttp2GetMemoryPoolStats returns 0x817B1225 for a null output,
before the id check, and 0x817B1100 for an unknown or terminated
context, zeroing the 32-byte output.
- sceNetGetMemoryPoolStats checks the pool before the output, so an
unknown pool with a null output returns EBADF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PPSA11386 imports it; on main it is one of the title's three missing
imports, with sceSslGetCaList and sceSslFreeCaList, and the title does not
call it during its start-up. The signature is unknown, so it is declared
without parameters and throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Winsock fails send, sendto and sendmsg on a socket shut down for writing
with WSAESHUTDOWN, which neither Windows error map handled, so libkernel
and libSceNet reported EIO. FreeBSD reports EPIPE there, and the Linux
maps already translate the host's EPIPE to 32. Map WSAESHUTDOWN to 32
in both.
sceHttp2GetMemoryPoolStats, sceSslGetMemoryPoolStats and
sceNetGetMemoryPoolStats threw. PPSA16064 (Minecraft Dungeons II,
Unreal Engine) queries all three while its HTTP module starts, and
aborted there.
Each library now records the pool size given at sceHttp2Init,
sceSslInit or sceNetPoolCreate and reports it with a peak and current
use of 0: the offline Http2 and Ssl models and the host-socket Net
library allocate nothing from these pools. The layouts follow the PS4
SDK's *MemoryPoolStats structures. Net returns EBADF for an unknown
pool and EINVAL for a null output, like its other pool calls; Http2 and
Ssl throw for both, as their error codes are unknown. Terminating a
context or destroying a pool forgets its size.
sceHttp2SetResolveRetry, which the title calls next, accepts and
ignores its value like the other Http2 settings. The four Http2
WebSocket exports the title imports are added as unimplemented.
guest_http2, guest_ssl and guest_sce_net check the reported sizes;
guest_sce_net also checks the null-output and unknown-pool errors.
The layout offsets the titles read are static_asserts, and guest_sce_net now
checks a canary past byte 384, distinct records, and an untouched buffer on the
EINVAL, RESOLVER_ENODNS and EBADF paths, as #1845's test did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PS5VR (PPSA99177) stops at start-up on the unresolved import sT4nBQKUPqM;
Jelly5, Emby5 and Nuvio import it too. The call fills the 384-byte resolver
info with up to ten IPv4 records (32 bytes each, family at +16) and the record
counts at +320 and +324, from the same host lookup sceNetResolverStartNtoa
uses, now shared. Only flags 0 is implemented; other flags throw.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The host's EHOSTUNREACH was reported as ENETUNREACH (51); FreeBSD's
EHOSTUNREACH is 65, which libkernel's sockets already report. EADDRNOTAVAIL,
ENOBUFS, EISCONN, ENOTCONN and EACCES had no translation and became EIO;
they now map to 49, 55, 56, 57 and 13, as in libkernel/Socket/src/Udp.cpp.
guest_sce_net connects the connected client again and expects EISCONN
(0x80410138); before this change it received EIO.
A non-blocking sceNetConnect that cannot complete at once must fail with
EINPROGRESS (36, 0x80410124), as FreeBSD's connect does, and a repeated call
while it is pending with EALREADY (37). On Windows, Winsock reports the
first case as WSAEWOULDBLOCK, which was translated to EAGAIN (0x80410123); on
Linux, EINPROGRESS and EALREADY had no translation and became EIO
(0x80410105). Code that waits for the connection only when connect reports
EINPROGRESS treated both as a failed connection.
guest_sce_net connects a non-blocking socket to the loopback listener and
accepts 0 or EINPROGRESS; before this change it received EAGAIN on Windows.
libSceNet registers a socket poller with libkernel; select polls the requested descriptors through it until the timeout and rewrites the descriptor sets.
LEGO Horizon Adventures imports 19 functions that no library exports
and no open pull request adds, so it fails eager binding. They are
declared as throwing stubs. The two libSceAjmWVorbis imports have no
known name and are exported by NID from libSceAjm.native.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
20 of the 31 NIDs have names in shadPS4's aerolib list. They are declared
under those names; POSIX sleep is implemented. The NpPartner001 and Psml
MFSR2 exports stay unnamed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every failing sceNet function returned -1 and left the code only in
sceNetErrnoLoc. The functions return the errno combined with
0x80410100 (SCE_NET_ERROR_*), as the resolver paths of this file
already do with RESOLVER_ENODNS and as shadPS4 and fpPS4 do for the
whole library. A title that compares the result with
SCE_NET_ERROR_EWOULDBLOCK saw a non-blocking receive without data as
an unknown failure.
Assisted-by: Claude Opus 5.5