fix(libkernel): return EDESTADDRREQ for send and sendto on unconnected UDP sockets
This commit is contained in:
parent
325e0a8bdd
commit
8b04156bfd
|
|
@ -60,6 +60,14 @@ int NativeError() {
|
|||
return GuestSockets::GuestErrorFromHost(errno);
|
||||
#endif
|
||||
}
|
||||
int SendError(int type) {
|
||||
#ifdef _WIN32
|
||||
if (type == 2 && WSAGetLastError() == WSAENOTCONN) return 39;
|
||||
#else
|
||||
static_cast<void>(type);
|
||||
#endif
|
||||
return NativeError();
|
||||
}
|
||||
struct Socket {
|
||||
NativeSocket value;
|
||||
int family;
|
||||
|
|
@ -597,7 +605,7 @@ std::int64_t APS5_VABI send_nid_postfix(int descriptor, const void* buffer, std:
|
|||
if (length > INT_MAX) return Fail(40);
|
||||
if (!buffer && length) return Fail(14);
|
||||
const auto result = ::send(socket->value, static_cast<const char*>(buffer), static_cast<int>(length), NativeSendFlags(flags));
|
||||
return result < 0 ? Fail(NativeError()) : result;
|
||||
return result < 0 ? Fail(SendError(socket->type)) : result;
|
||||
}
|
||||
std::int64_t APS5_VABI recv_nid_postfix(int descriptor, void* buffer, std::uint64_t length, int flags) {
|
||||
const auto socket = Lookup(descriptor);
|
||||
|
|
@ -690,7 +698,7 @@ std::int64_t APS5_VABI sendto_nid_postfix(int descriptor, const void* buffer, st
|
|||
result = static_cast<int>(::sendto(socket->value, static_cast<const char*>(buffer), static_cast<int>(length), NativeSendFlags(flags),
|
||||
reinterpret_cast<sockaddr*>(&native), size));
|
||||
}
|
||||
return result < 0 ? Fail(NativeError()) : result;
|
||||
return result < 0 ? Fail(SendError(socket->type)) : result;
|
||||
}
|
||||
std::int64_t APS5_VABI recvfrom_nid_postfix(int descriptor, void* buffer, std::uint64_t length,
|
||||
int flags, void* address, std::uint32_t* addressLength) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ int APS5_VABI bind_nid_postfix(int, const void*, std::uint32_t);
|
|||
int APS5_VABI getsockname_nid_postfix(int, void*, std::uint32_t*);
|
||||
int APS5_VABI ioctl_nid_postfix(int, std::uint64_t, void*);
|
||||
int APS5_VABI _ioctl_nid_postfix(int, std::uint64_t, void*);
|
||||
std::int64_t APS5_VABI send_nid_postfix(int, const void*, std::uint64_t, int);
|
||||
std::int64_t APS5_VABI sendto_nid_postfix(int, const void*, std::uint64_t, int, const void*, std::uint32_t);
|
||||
std::int64_t APS5_VABI recvfrom_nid_postfix(int, void*, std::uint64_t, int, void*, std::uint32_t*);
|
||||
int APS5_VABI close_nid_postfix(int);
|
||||
|
|
@ -68,13 +69,13 @@ int main() {
|
|||
Require(getsockopt_nid_postfix(sender, 0xffff, 0x20, &option, &optionSize) == 0 && option != 0);
|
||||
Require(setsockopt_nid_postfix(sender, 0xffff, 12345, &enabled, sizeof(enabled)) == -1);
|
||||
Require(*__error_nid_postfix() == 42);
|
||||
#ifndef _WIN32
|
||||
const int unconnected = socket_nid_postfix(2, 2, 0);
|
||||
Require(unconnected >= 0);
|
||||
Require(send_nid_postfix(unconnected, "x", 1, 0) == -1);
|
||||
Require(*__error_nid_postfix() == 39);
|
||||
Require(sendto_nid_postfix(unconnected, "x", 1, 0, nullptr, 0) == -1);
|
||||
Require(*__error_nid_postfix() == 39);
|
||||
Require(close_nid_postfix(unconnected) == 0);
|
||||
#endif
|
||||
const int unsized = socket_nid_postfix(2, 2, 0);
|
||||
std::array<unsigned char, 16> unsizedAddress{0, 2, 0, 0, 127, 0, 0, 1};
|
||||
Require(unsized >= 0 && bind_nid_postfix(unsized, unsizedAddress.data(), unsizedAddress.size()) == 0);
|
||||
|
|
|
|||
|
|
@ -607,6 +607,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [The scanf family](../../core/libs/prx/libc/include/WindowsScanning.hpp) (libc) on Windows returns 0, as C17 and FreeBSD do, when input fails after only suppressed conversions have completed (`sscanf("12", "%*d%d", &value)`). Linux hands the format to glibc, which returns `EOF` there. On Windows the host stops a `%x`, `%X`, `%i` or `%p` after the `x` of a `0x` that no hex digit follows (or that the width cuts off), and a float conversion (`%e`, `%f`, `%g`, `%a`) after the `e` of an exponent with no digits (`1e`), where C17 and FreeBSD stop before the `x` or the `e`
|
||||
- [socketpair](../../core/libs/prx/libkernel/Socket/src/Udp.cpp) (libkernel) - the pair is the host's `AF_UNIX` pair on Linux and, on Windows, a loopback TCP connection for `SOCK_STREAM` or two connected UDP sockets for `SOCK_DGRAM`; `SOCK_SEQPACKET` throws on Windows. A datagram sent to a full receiver gets `ENOBUFS` on the console, waits or gets `EAGAIN` on Linux and is dropped on Windows, and on Windows a datagram `recv` after the peer closed reports `ECONNRESET` instead of the console's `ENOTCONN`, and a stream `send` after the peer closed reports `ECONNABORTED` instead of the console's `EPIPE`. `read` and `write` on a pair end go to the host like on every guest socket. `getpeername` on a pair end succeeds after the peer closed, where the console returns `ENOTCONN`, and `connect`, `bind` and `sendto` with an address on a pair end report an address-family error instead of the console's `EISCONN`. On Windows `poll` on a stream end reports `POLLHUP` without `POLLIN` after the peer's `shutdown(SHUT_WR)` or `close`, where the console reports `POLLIN`, with `POLLHUP` only after `close`
|
||||
- [UDP recv/recvfrom](../../core/libs/prx/libkernel/Socket/src/Udp.cpp) and [sceNetRecv/sceNetRecvfrom](../../core/libs/prx/libSceNet/Export.cpp) translate Windows WSAEMSGSIZE into the copied byte count for datagram sockets, including MSG_PEEK, and retain the sender address. This follows FreeBSD 11.4 recv(2) and Winsock's documented truncated-datagram behavior; console behavior and existing title impact are unverified.
|
||||
- [send, sendto](../../core/libs/prx/libkernel/Socket/src/Udp.cpp) (libkernel) - send and sendto without an address on an unconnected datagram socket map Windows `WSAENOTCONN` to FreeBSD's `EDESTADDRREQ` (39).
|
||||
- [read, write and vector I/O](../../core/libs/prx/libkernel/File/src/Stdio.cpp) (libkernel) on a guest socket use `recv` and `send` without flags; `sceKernelReadv` and `sceKernelWritev` gather or scatter through one socket operation, preserving stream short reads and datagram boundaries. The positioned `pread`, `pwrite`, `preadv` and `pwritev` forms, and their `sceKernel` forms, return `ESPIPE` for an open guest socket and `EBADF` for a closed one. Guest socket descriptors start at `0x10000000` and are allocated upward, so the descriptor range selects the guest socket table or the host descriptor table. `EPIPE` from a write raises the host's `SIGPIPE` on Linux, which the guest can neither ignore nor suppress: `signal(SIGPIPE, SIG_IGN)` and `sigaction` record the disposition, as they do for every number from 1 to 128, but only the six signals with host equivalents (2, 4, 6, 8, 11 and 15) take effect on the host or are delivered, so the host `SIGPIPE` is not stopped; `SO_NOSIGPIPE` is not an option here, and raises nothing on Windows; a `write` longer than `INT_MAX` bytes is `EMSGSIZE` where the console sends it. AIO on a guest socket still goes to the host, which has no such descriptor
|
||||
- [poll](../../core/libs/prx/libkernel/Socket/src/Udp.cpp) (libkernel) waits only on guest sockets, through `WSAPoll` on Windows and `poll` on Linux; the `pollfd` layout and flag values are FreeBSD's. A descriptor below the socket range (files, pipes, stdio) throws, as do event bits other than `POLLIN`, `POLLPRI`, `POLLOUT`, `POLLRDNORM`, `POLLRDBAND` and `POLLWRBAND` (the `POLLERR`, `POLLHUP` and `POLLNVAL` bits are ignored in `events`), `POLLPRI` on Windows, which `WSAPoll` rejects, and an infinite timeout with no socket to wait on. A closed socket descriptor reports `POLLNVAL`; the console's limit on the descriptor count is unknown and not checked
|
||||
- [Socket error numbers](../../core/libs/prx/libkernel/Socket/include/SocketError.hpp) (libkernel) - a host socket error becomes the FreeBSD 11 `errno.h` number of the same name; the numbers are not checked on the console. Winsock `WSAESHUTDOWN` becomes `EPIPE`, as a send after `shutdown` does on FreeBSD, and a host error with no FreeBSD socket counterpart becomes `EIO`. A nonblocking `connect` in progress reports `EINPROGRESS` on Linux but `EAGAIN` on Windows (`WSAEWOULDBLOCK`), where FreeBSD reports `EINPROGRESS`. On Windows a refused nonblocking `connect` is never reported (`SO_ERROR` is unsupported), so a repeated one keeps reporting `EALREADY` where FreeBSD reports `ECONNREFUSED`. A receive after `shutdown(SHUT_RD)` reports `EPIPE` on Windows where FreeBSD returns 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue