sosend_generic fails a send on a socket that can send no more with EPIPE
before it looks at so_error. Winsock reports the same send as WSAECONNABORTED
or WSAECONNRESET, which reached the guest as ECONNABORTED or ECONNRESET.
A stream send now maps both to EPIPE. The send-after-close checks of
guest_tcp, guest_socket_read_write and guest_socket_pair run on Windows too.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
On Linux the host keeps data that was buffered before shutdown(SHUT_RD) and
guest_socket_pair expects to read it, so the shortcut that answers 0 for any
receive after SHUT_RD broke that test there. Limit the shortcut to Windows,
where the host cannot answer it, and run the post-shutdown receives of
guest_tcp on Windows only.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
soreceive_generic returns 0 for a socket whose receive side is shut and for a
zero-length receive on a connected stream socket (ENOTCONN when it is not
connected), without waiting. Winsock fails the first with WSAESHUTDOWN, which
reached the guest as EPIPE, and blocks the second until data arrives. recv and
recvfrom now answer both themselves.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The PS5 libkernel exports _accept, _bind, _connect, _getdirentries,
_getpeername, _getsockname, _getsockopt, _listen, _recvfrom, _recvmsg,
_sendmsg, _sendto, _setsockopt, _sigaction and _sigsuspend (PS5 3.20
export list, DNNDHH/PS5-3.20_Libs b2a77c0 libkernel.c), and main
exports none of them, so a title importing one fails at startup. Each
now forwards to the export without the underscore, as _close, _ioctl
and _nanosleep already do.
In FreeBSD 11.4 (8c639945a4) these are libc's plain system call
entries: lib/libc/amd64/SYS.h makes bind, getdirentries, getpeername,
getsockname, getsockopt, listen and setsockopt one stub under both
names, and lib/libc/sys/Makefile.inc gives accept, connect, recvfrom,
recvmsg, sendmsg, sendto, sigaction and sigsuspend a separate public
name that goes through libthr's interposing table, which adds the
cancellation points and the sigaction wrapper. The exports without the
underscore have no libthr layer here, so forwarding gives the system
call. docs/dev/debt/libkernel.md records what stays unverified: the
console is not measured, _sigaction shares the handler table of
sigaction, and a null set throws in _sigsuspend as in sigsuspend,
where FreeBSD's system call returns EFAULT.
guest_underscore_entries calls every new export: a loopback TCP
connection, UDP datagrams with scatter, truncation and sender
addresses, a directory listing compared with getdirentries, a SIGTERM
handler set by _sigaction, and a pending SIGUSR1 that _sigsuspend
delivers before returning EINTR with the mask restored. It checks the
errors they pass on (EBADF, EINVAL, EFAULT, ENOPROTOOPT, EOPNOTSUPP)
and that outputs stay untouched on failure.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
WSAPoll reports POLLHUP alone for a stream socket whose peer has closed, so
poll never returned POLLIN for it and a caller waiting for POLLIN did not see
the end of the stream. sopoll_generic reports a socket that can receive no
more as readable and adds POLLHUP only once it can send no more either.
poll now adds the requested read bit and keeps POLLHUP only after the socket
shut its own sending side. A reset or refused connection keeps WSAPoll's flags.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
FreeBSD 11 sendfile checks the file descriptor first, then looks up the
socket with getsock_cap, which answers ENOTSOCK for an open descriptor
that is not a socket and EBADF for one that is not open
(sys/kern/kern_sendfile.c, sys/kern/uipc_syscalls.c).
sendfile replaced the errno that Lookup had already set with EBADF. It
now reports the errno Lookup chose, so an open non-socket gives ENOTSOCK
and a closed descriptor still gives EBADF. The sentence about this gap
is cut from the sendfile debt entry and guest_sendfile covers both cases.
Linux's udp_sendmsg refuses port 0 with EINVAL, so a send that FreeBSD
accepts (the socket is bound to a specific address and port and the
destination is not INADDR_ANY or INADDR_BROADCAST) failed there. Nothing can
receive on port 0, so the call now returns the length itself on every host.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
udp_output hands the destination to in_pcbconnect_setup unless the socket is
bound to a specific address and port and the destination is neither
INADDR_ANY nor INADDR_BROADCAST, and in_pcbconnect_setup fails port 0 with
EADDRNOTAVAIL. The send went to the host, which accepted it. sendto, and
sendmsg through it, now fails the same way for an AF_INET datagram socket
that is not connected. connect to port 0 already did.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
soreceive_generic keeps a MSG_WAITALL receive on a stream socket waiting until
the buffer is full, the peer closes or an error occurs. The three calls failed
every flag but MSG_PEEK and MSG_DONTWAIT with EOPNOTSUPP. A stream socket now
passes the flag to the host receive; a datagram socket ignores it, as a record
is delivered whole.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
bind, connect and sendto looked the descriptor up before they looked at the
address length, so a descriptor that is not open hid an argument error.
FreeBSD 11.4 sys_bind, sys_connect and sendit run getsockaddr first
(ENAMETOOLONG, EINVAL, EFAULT) and only then look the descriptor up, so
these arguments are now answered first and EBADF only follows for a valid
address.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
GuestSockets::Ready only knew the read end of a pipe, and WaitAny asked the host for POLLIN on every descriptor that is not a socket, so a write interest on a pipe could never be reported or wake a wait. PipeWriteState gives the free space of the host buffer (F_GETPIPE_SZ less FIONREAD on Linux, the write quota on Windows), EOF once the read end is closed, and whether the host takes a write now; Ready reports the write end when it is writable or at EOF, and WaitAny asks for POLLOUT on it. macOS has no call for the capacity of a pipe and throws.
listen on a connected stream socket failed with EISCONN, the Winsock error.
FreeBSD 11.4 solisten_proto_check fails a socket that is connected,
connecting or disconnecting with EINVAL. The guest listen now reports EINVAL
for the host's EISCONN, and the connect-listening test checks it.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
send, sendto, sendmsg, recv, recvfrom and recvmsg failed with EOPNOTSUPP for
MSG_DONTWAIT on Windows, where FreeBSD 11.4 sosend_generic and
soreceive_generic make the one call non-blocking and fail with EWOULDBLOCK
when it would wait. Winsock has no per-call flag, so the call now asks WSAPoll
with a zero timeout whether the socket is ready and fails with EAGAIN when it
is not. The Windows branches of the socket tests that expected EOPNOTSUPP now
run the same checks as the other hosts.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
bind, listen, accept, connect, shutdown, getsockname, getsockopt, setsockopt, send, recv and the other calls that look up a guest socket answered EBADF for a descriptor that is open but not a socket, for example a pipe end. FreeBSD 11.4's getsock_cap fails these with ENOTSOCK and keeps EBADF for a closed or invalid descriptor.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
bind, connect and sendto answered EFAULT for an address length below 2 and EAFNOSUPPORT for an AF_INET address below 16 or an AF_INET6 address below 28 bytes. FreeBSD 11.4's getsockaddr fails a length below 2 with EINVAL and above SOCK_MAXADDRLEN (255) with ENAMETOOLONG, and the protocols compare the length with sizeof(struct sockaddr_in) or sockaddr_in6 and fail with EINVAL.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
socketpair accepted SOCK_CLOEXEC but left both descriptors out of the
close-on-exec set, so F_GETFD read 0 on them. FreeBSD 11's
kern_socketpair opens both files with O_CLOEXEC when the type carries
SOCK_CLOEXEC, as socket already does here.
The guest socket layer relies on a few Linux calls:
- The equeue wait uses poll with the timeout rounded up to a millisecond;
macOS has no ppoll.
- A readable stream socket whose peer closed is reported with POLLHUP by
peeking one byte; macOS has no POLLRDHUP.
- FIONREAD on a datagram socket, and the byte count that fstat and kevent
report for it, is SO_NREAD, the size of the next datagram; macOS adds the
source address to FIONREAD.
- socketpair throws for SOCK_SEQPACKET, which has no AF_UNIX pair on macOS.
- gethostbyname replaces gethostbyname_r, which macOS lacks.
The UDP test sends on its connected socket without an address, as #7475
does, because macOS, like FreeBSD, fails sendto with an address on a
connected socket with EISCONN. The log test uses a datagram pair with
enlarged buffers instead of SOCK_SEQPACKET.
FreeBSD's sys_ioctl rejects a request with no direction bit, an output request with no length, or a void request whose length is not an int before it reads the argument or resolves the descriptor. ioctl threw on such a request for a file, pipe or directory, failed with EBADF for a closed descriptor and with EFAULT for a socket given no argument.
(cherry picked from commit 501518f321ac5d0b45ce1090af39c680927edf49)
(cherry picked from commit 3eb7edd9cf)
kevent threw for EV_CLEAR on a socket or the read end of a pipe; Boost.Asio's kqueue reactor, among others, registers every socket that way. On Linux such a knote now watches its host descriptor through an edge watch. It is armed when added, on every later EV_ADD or EV_ENABLE while enabled, and by each host wakeup; when armed it is checked with the level-triggered readiness test and reported with the current data and EV_EOF, or disarmed if no longer ready, as kqueue_scan re-runs the filter; reporting it disarms it until the next edge. Waits block on the watch's epoll descriptor, so a socket that stays readable does not wake them. Windows and macOS still throw. GuestSockets::NativeDescriptor exposes the host socket behind a guest one for the watch.
Address review: check the msghdr, iovec array, iovec bases and name
are mapped before MessageLength or the receive loop touches them,
pairing the HostWrite guard with committed-range validation. Add
regression tests for forged iovec-array and output pointers.
recvmsg_nid_postfix wrote the msghdr, every iovec base and the sender
address with only null checks, unlike recv_nid_postfix and the
sceNetRecvfrom sender outputs which all gate on GuestArena::HostWrite.
Validate the message, each iovec base and the name buffer the same way
so a forged pointer fails with EFAULT instead of writing received bytes
to an arbitrary host address.