On Windows a pair is a loopback stream or two connected datagram sockets
rather than the console's local pair. After the peer closes, the first
stream send reaches a socket the host still accepts and succeeds, where
the console fails it with EPIPE, and an empty datagram receive waits on a
socket the host never signals, where the console fails it with
ECONNRESET; a datagram queued before the close is still delivered first.
Both answers now come from the pair's lost peer before the host is
waited on. Measured on a PS5 (13.60 and 11.60): send EPIPE (32) and
receive ECONNRESET (54).
The receive side asks the socket whether a datagram is queued rather than
whether bytes are queued, because a datagram sent with no payload still
has to be delivered: ioctlsocket answers 1 for one on this host, and
select answers readable, while a byte count of the socket as a whole
would answer 0 on a host that counts payload only. The Windows case now
sends an empty datagram before the close and expects it, then 54.
Both waits re-checked the held sockets only before each host wait. A
close during the last slice, or one followed by a packet the retained
native socket then received, came back as a timeout or as readiness on
a descriptor that no longer exists. FreeBSD 11.4's pollrescan reports
POLLNVAL alone for such a descriptor.
The held sockets are now re-checked after every successful host wait as
well, select's socket group fails with EBADF, and poll reports POLLNVAL
without ORing in the native socket's readiness.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Both waits held the guest sockets they polled and handed the host one
poll call for the whole wait. A guest close dropped only the table entry,
so the native socket stayed open and the wait ran to its timeout: poll
returned 0 instead of POLLNVAL, and select reported EBADF only after its
next 100 ms re-lookup, or not at all when the timeout was shorter.
FreeBSD 11.4 wakes such a waiter and reports the closed descriptor.
Waits that include sockets now poll the host in slices of at most 10 ms
and, before each slice, check that every descriptor still maps to the
socket it held. A closed one answers POLLNVAL from poll and EBADF from
select.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
send, sendto without an address, sendmsg and write on a stream socket on
which connect was never called, that was not accepted and that was not
received in a message now fail with ENOTCONN without asking the host, as
FreeBSD 11.4's sosend_generic does. Linux answered EPIPE and raised its
own SIGPIPE, which killed the guest.
bind, getsockname, sendto and recvfrom validate as for a libkernel socket
before they reach libSceNet, so a forwarded descriptor reports the same
errors. recvfrom keeps its guest address handling and MSG_WAITALL, and a
zero-length datagram receive does not wait.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A title can create a socket with sceNetSocket and then call bind, getsockname, sendto or recvfrom from libkernel, which does not hold that descriptor, so the call failed with EBADF. PPSA06866's RakNet does this, its local server fails to start and the load after difficulty selection never ends. libSceNet now registers these four calls with libkernel, as it does for setsockopt and getsockopt.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On Windows, closing a pipe while another thread waited for it in select
terminated the process. The close releases the host handle before the C
runtime descriptor, so in between:
- the readiness query of the pipe failed on the dead handle and threw
'querying pipe descriptor ... failed';
- after that, DescriptorIsOpen still saw the descriptor mapped, select
looked it up again, found no known kind and threw 'is neither a
socket, a pipe, ...'.
QueryPipe now reports a descriptor whose handle is no longer a pipe as
not a pipe instead of throwing, DescriptorIsOpen on Windows also checks
that the mapped handle is still valid, and select answers EBADF for such
a descriptor before throwing for an unknown kind, as FreeBSD 11.4's
kern_select does for a descriptor closed during the wait.
Co-Authored-By: Claude Opus 5.5 <[email protected]>