mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-23 00:53:02 -05:00
read, write, _read and _write on a guest socket descriptor went to the host, which has no such descriptor, so sceKernelRead and sceKernelWrite threw. They now reach the socket as recv and send without flags, with the socket layer's errno (EAGAIN 35, EPIPE 32, EBADF 9), a zero-length read returns 0 as dofileread does, and the two sceKernel forms return the kernel error for the same cases. The host's SIGPIPE on EPIPE, a write above INT_MAX bytes, readv, writev and the positioned forms are recorded in TechnicalDebt. OpenSSL's QUIC notifier signals its socketpair with write and read. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
115 lines
5.1 KiB
C++
115 lines
5.1 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#ifndef _WIN32
|
|
#include <csignal>
|
|
#endif
|
|
|
|
struct PollDescriptor {
|
|
int descriptor;
|
|
short events;
|
|
short revents;
|
|
};
|
|
|
|
extern "C" {
|
|
int APS5_VABI socket_nid_postfix(int, int, int);
|
|
int APS5_VABI bind_nid_postfix(int, const void*, std::uint32_t);
|
|
int APS5_VABI listen_nid_postfix(int, int);
|
|
int APS5_VABI getsockname_nid_postfix(int, void*, std::uint32_t*);
|
|
int APS5_VABI connect_nid_postfix(int, const void*, std::uint32_t);
|
|
int APS5_VABI accept_nid_postfix(int, void*, std::uint32_t*);
|
|
int APS5_VABI fcntl_nid_postfix(int, int, ...);
|
|
int APS5_VABI poll_nid_postfix(PollDescriptor*, std::uint32_t, int);
|
|
int APS5_VABI close_nid_postfix(int);
|
|
std::int64_t APS5_VABI read_nid_postfix(int, void*, std::uint64_t);
|
|
std::int64_t APS5_VABI write_nid_postfix(int, const char*, std::int64_t);
|
|
std::int64_t APS5_VABI _read_nid_postfix(int, void*, std::size_t);
|
|
std::int64_t APS5_VABI _write_nid_postfix(int, const void*, std::size_t);
|
|
std::int64_t APS5_VABI sceKernelRead(int, void*, std::size_t);
|
|
std::int64_t APS5_VABI sceKernelWrite(int, const void*, std::size_t);
|
|
int* APS5_VABI __error_nid_postfix();
|
|
}
|
|
|
|
static void Check(bool value, int line) {
|
|
if (!value) {
|
|
std::fprintf(stderr, "socket read/write check failed at line %d, errno %d\n", line, *__error_nid_postfix());
|
|
std::abort();
|
|
}
|
|
}
|
|
#define Require(value) Check((value), __LINE__)
|
|
|
|
constexpr short In = 0x1;
|
|
constexpr short Hup = 0x10;
|
|
constexpr int KernelAgain = static_cast<int>(0x80020023u);
|
|
constexpr int KernelBadDescriptor = static_cast<int>(0x80020009u);
|
|
|
|
static bool Readable(int descriptor, short accepted = In) {
|
|
PollDescriptor waited{descriptor, In, 0};
|
|
return poll_nid_postfix(&waited, 1, 2000) == 1 && (waited.revents & accepted) != 0;
|
|
}
|
|
|
|
int main() {
|
|
#ifndef _WIN32
|
|
std::signal(SIGPIPE, SIG_IGN);
|
|
#endif
|
|
const int listener = socket_nid_postfix(2, 1, 0);
|
|
Require(listener >= 0);
|
|
std::array<std::uint8_t, 16> address{16, 2, 0, 0, 127, 0, 0, 1};
|
|
Require(bind_nid_postfix(listener, address.data(), address.size()) == 0);
|
|
Require(listen_nid_postfix(listener, 4) == 0);
|
|
std::uint32_t addressSize = address.size();
|
|
Require(getsockname_nid_postfix(listener, address.data(), &addressSize) == 0);
|
|
const int client = socket_nid_postfix(2, 1, 0);
|
|
Require(client >= 0 && connect_nid_postfix(client, address.data(), address.size()) == 0);
|
|
const int server = accept_nid_postfix(listener, nullptr, nullptr);
|
|
Require(server >= 0);
|
|
|
|
const char request[] = "written to a socket";
|
|
char received[32]{};
|
|
Require(write_nid_postfix(client, request, sizeof(request)) == sizeof(request));
|
|
Require(Readable(server) && read_nid_postfix(server, received, sizeof(received)) == sizeof(request));
|
|
Require(std::strcmp(received, request) == 0);
|
|
|
|
const char reply[] = "and back";
|
|
std::memset(received, 0, sizeof(received));
|
|
Require(_write_nid_postfix(server, reply, sizeof(reply)) == sizeof(reply));
|
|
Require(Readable(client) && _read_nid_postfix(client, received, sizeof(received)) == sizeof(reply));
|
|
Require(std::strcmp(received, reply) == 0);
|
|
|
|
const char kernel[] = "through sceKernelWrite";
|
|
std::memset(received, 0, sizeof(received));
|
|
Require(sceKernelWrite(client, kernel, sizeof(kernel)) == sizeof(kernel));
|
|
Require(Readable(server) && sceKernelRead(server, received, sizeof(received)) == sizeof(kernel));
|
|
Require(std::strcmp(received, kernel) == 0);
|
|
|
|
Require(fcntl_nid_postfix(server, 4, 4) == 0);
|
|
*__error_nid_postfix() = 0;
|
|
Require(read_nid_postfix(server, received, sizeof(received)) == -1 && *__error_nid_postfix() == 35);
|
|
Require(sceKernelRead(server, received, sizeof(received)) == KernelAgain);
|
|
|
|
Require(read_nid_postfix(server, received, 0) == 0 && sceKernelRead(server, received, 0) == 0);
|
|
Require(close_nid_postfix(client) == 0);
|
|
Require(Readable(server, In | Hup) && read_nid_postfix(server, received, sizeof(received)) == 0);
|
|
Require(sceKernelRead(server, received, sizeof(received)) == 0);
|
|
#ifndef _WIN32
|
|
std::int64_t written = 0;
|
|
for (int i = 0; i < 100 && written >= 0; ++i) written = write_nid_postfix(server, request, sizeof(request));
|
|
Require(written == -1 && *__error_nid_postfix() == 32);
|
|
#endif
|
|
Require(close_nid_postfix(server) == 0);
|
|
*__error_nid_postfix() = 0;
|
|
Require(read_nid_postfix(server, received, sizeof(received)) == -1 && *__error_nid_postfix() == 9);
|
|
Require(read_nid_postfix(server, received, 0) == -1 && *__error_nid_postfix() == 9);
|
|
Require(write_nid_postfix(server, request, sizeof(request)) == -1 && *__error_nid_postfix() == 9);
|
|
Require(_write_nid_postfix(server, request, sizeof(request)) == -1 && *__error_nid_postfix() == 9);
|
|
Require(_read_nid_postfix(server, received, sizeof(received)) == -1 && *__error_nid_postfix() == 9);
|
|
Require(sceKernelRead(server, received, sizeof(received)) == KernelBadDescriptor);
|
|
Require(sceKernelWrite(server, request, sizeof(request)) == KernelBadDescriptor);
|
|
Require(close_nid_postfix(listener) == 0);
|
|
return 0;
|
|
}
|