#include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include #include #ifndef _WIN32 #include #endif struct PollDescriptor { int descriptor; short events; short revents; }; struct Iovec { void* base; std::size_t length; }; 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); std::int64_t APS5_VABI sceKernelReadv(int, const Iovec*, int); std::int64_t APS5_VABI sceKernelWritev(int, const Iovec*, int); std::int64_t APS5_VABI pread_nid_postfix(int, void*, std::size_t, std::int64_t); std::int64_t APS5_VABI pwrite_nid_disambig1_nid_postfix(int, const void*, std::size_t, std::int64_t); std::int64_t APS5_VABI preadv_nid_postfix(int, const Iovec*, int, std::int64_t); std::int64_t APS5_VABI pwritev_nid_postfix(int, const Iovec*, int, std::int64_t); std::int64_t APS5_VABI sceKernelPread(int, void*, std::size_t, std::int64_t); std::int64_t APS5_VABI sceKernelPwrite(int, const void*, std::size_t, std::int64_t); std::int64_t APS5_VABI sceKernelPreadv(int, const Iovec*, int, std::int64_t); std::int64_t APS5_VABI sceKernelPwritev(int, const Iovec*, int, std::int64_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(0x80020023u); constexpr int KernelBadDescriptor = static_cast(0x80020009u); constexpr int KernelIllegalSeek = static_cast(0x8002001du); 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 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); const char vectorFirst[] = "vector "; const char vectorSecond[] = "write"; Iovec vectorWrite[] = {{const_cast(vectorFirst), sizeof(vectorFirst) - 1}, {const_cast(vectorSecond), sizeof(vectorSecond)}}; Require(sceKernelWritev(client, vectorWrite, 2) == sizeof(vectorFirst) + sizeof(vectorSecond) - 1); char vectorReadFirst[sizeof(vectorFirst) - 1]{}; char vectorReadSecond[sizeof(vectorSecond)]{}; Iovec vectorRead[] = {{vectorReadFirst, sizeof(vectorReadFirst)}, {vectorReadSecond, sizeof(vectorReadSecond)}}; Require(Readable(server) && sceKernelReadv(server, vectorRead, 2) == sizeof(vectorFirst) + sizeof(vectorSecond) - 1); Require(std::memcmp(vectorReadFirst, "vector ", sizeof(vectorReadFirst)) == 0 && std::strcmp(vectorReadSecond, "write") == 0); const char sceVectorFirst[] = "sceKernel"; const char sceVectorSecond[] = "Writev"; Iovec sceVectorWrite[] = {{const_cast(sceVectorFirst), sizeof(sceVectorFirst) - 1}, {const_cast(sceVectorSecond), sizeof(sceVectorSecond)}}; Require(sceKernelWritev(client, sceVectorWrite, 2) == sizeof(sceVectorFirst) + sizeof(sceVectorSecond) - 1); char sceVectorReadFirst[sizeof(sceVectorFirst) - 1]{}; char sceVectorReadSecond[sizeof(sceVectorSecond)]{}; Iovec sceVectorRead[] = {{sceVectorReadFirst, sizeof(sceVectorReadFirst)}, {sceVectorReadSecond, sizeof(sceVectorReadSecond)}}; Require(Readable(server) && sceKernelReadv(server, sceVectorRead, 2) == sizeof(sceVectorFirst) + sizeof(sceVectorSecond) - 1); Require(std::memcmp(sceVectorReadFirst, "sceKernel", sizeof(sceVectorReadFirst)) == 0 && std::strcmp(sceVectorReadSecond, "Writev") == 0); const char positionedWrite[] = "positioned"; Iovec positionedIov[] = {{const_cast(positionedWrite), sizeof(positionedWrite)}}; *__error_nid_postfix() = 0; Require(pread_nid_postfix(server, received, 1, 0) == -1 && *__error_nid_postfix() == 29); Require(pwrite_nid_disambig1_nid_postfix(client, positionedWrite, 1, 0) == -1 && *__error_nid_postfix() == 29); Require(preadv_nid_postfix(server, positionedIov, 1, 0) == -1 && *__error_nid_postfix() == 29); Require(pwritev_nid_postfix(client, positionedIov, 1, 0) == -1 && *__error_nid_postfix() == 29); Require(sceKernelPread(server, received, 1, 0) == KernelIllegalSeek); Require(sceKernelPwrite(client, positionedWrite, 1, 0) == KernelIllegalSeek); Require(sceKernelPreadv(server, positionedIov, 1, 0) == KernelIllegalSeek); Require(sceKernelPwritev(client, positionedIov, 1, 0) == KernelIllegalSeek); 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); Iovec emptyRead[] = {{received, sizeof(received)}}; Require(sceKernelReadv(server, emptyRead, 1) == 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(sceKernelPread(server, received, 1, 0) == KernelBadDescriptor); Require(sceKernelPwrite(server, request, 1, 0) == KernelBadDescriptor); Require(pread_nid_postfix(server, received, 1, 0) == -1 && *__error_nid_postfix() == 9); Require(pwrite_nid_disambig1_nid_postfix(server, request, 1, 0) == -1 && *__error_nid_postfix() == 9); Require(preadv_nid_postfix(server, positionedIov, 1, 0) == -1 && *__error_nid_postfix() == 9); Require(pwritev_nid_postfix(server, positionedIov, 1, 0) == -1 && *__error_nid_postfix() == 9); Require(close_nid_postfix(listener) == 0); return 0; }