Files
AnyPS5/core/libs/tests/GuestSocketStreamOptions.cpp

181 lines
9.2 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <array>
#include <csignal>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
extern "C" {
int APS5_VABI socket_nid_postfix(int, int, int);
int APS5_VABI socketpair_nid_postfix(int, 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 shutdown_nid_postfix(int, int);
int APS5_VABI setsockopt_nid_postfix(int, int, int, const void*, std::uint32_t);
int APS5_VABI getsockopt_nid_postfix(int, int, int, void*, std::uint32_t*);
int APS5_VABI fcntl_nid_postfix(int, int, ...);
int APS5_VABI close_nid_postfix(int);
std::int64_t APS5_VABI send_nid_postfix(int, const void*, std::uint64_t, int);
std::int64_t APS5_VABI recv_nid_postfix(int, void*, std::uint64_t, int);
std::int64_t APS5_VABI write_nid_postfix(int, const char*, std::int64_t);
int* APS5_VABI __error_nid_postfix();
}
static void Check(bool value, int line) {
if (!value) {
std::fprintf(stderr, "socket stream option check failed at line %d, errno %d\n", line, *__error_nid_postfix());
std::abort();
}
}
#define Require(value) Check((value), __LINE__)
constexpr int SocketLevel = 0xffff;
constexpr int TcpLevel = 6;
constexpr int TcpNoDelay = 1;
constexpr int TcpMaximumSegment = 2;
constexpr int Ipv6Level = 41;
constexpr int Ipv6UnicastHops = 4;
constexpr int Ipv6Only = 27;
constexpr int NoSigpipe = 0x800;
constexpr int NonBlockingOption = 0x1200;
constexpr int NoSignalFlag = 0x20000;
constexpr int GetStatusFlags = 3;
constexpr int NonBlockingFlag = 4;
constexpr int Invalid = 22;
constexpr int BrokenPipe = 32;
constexpr int Again = 35;
constexpr int NoProtocolOption = 42;
#ifndef _WIN32
static volatile std::sig_atomic_t brokenPipes = 0;
static void CountBrokenPipe(int) {
brokenPipes = brokenPipes + 1;
}
#endif
static int BrokenPipes() {
#ifdef _WIN32
return 0;
#else
return brokenPipes;
#endif
}
static bool Fails(std::int64_t result, int error) {
return result == -1 && *__error_nid_postfix() == error;
}
static bool Set(int descriptor, int level, int option, int value) {
return setsockopt_nid_postfix(descriptor, level, option, &value, sizeof(value)) == 0;
}
static int Get(int descriptor, int level, int option) {
int value = -1;
std::uint32_t length = sizeof(value);
Require(getsockopt_nid_postfix(descriptor, level, option, &value, &length) == 0 && length == sizeof(value));
return value;
}
int main() {
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);
Require(Set(listener, SocketLevel, NoSigpipe, 1) && Set(listener, TcpLevel, TcpNoDelay, 1));
const int secondClient = socket_nid_postfix(2, 1, 0);
Require(secondClient >= 0 && connect_nid_postfix(secondClient, address.data(), address.size()) == 0);
const int inheriting = accept_nid_postfix(listener, nullptr, nullptr);
Require(inheriting >= 0);
Require(Get(inheriting, SocketLevel, NoSigpipe) == NoSigpipe && Get(inheriting, TcpLevel, TcpNoDelay) == 4);
Require(Get(server, SocketLevel, NoSigpipe) == 0 && Get(server, TcpLevel, TcpNoDelay) == 0);
Require(close_nid_postfix(inheriting) == 0 && close_nid_postfix(secondClient) == 0);
const int datagram = socket_nid_postfix(2, 2, 0);
std::array<std::uint8_t, 16> datagramAddress{16, 2, 0, 0, 127, 0, 0, 1};
Require(datagram >= 0 && bind_nid_postfix(datagram, datagramAddress.data(), datagramAddress.size()) == 0);
int local[2]{-1, -1};
Require(socketpair_nid_postfix(1, 1, 0, local) == 0);
int one = 1;
Require(Get(client, TcpLevel, TcpNoDelay) == 0);
Require(Set(client, TcpLevel, TcpNoDelay, 7) && Get(client, TcpLevel, TcpNoDelay) == 4);
unsigned char byte = 0x7f;
std::uint32_t length = sizeof(byte);
Require(getsockopt_nid_postfix(client, TcpLevel, TcpNoDelay, &byte, &length) == 0 && length == sizeof(byte) && byte == 4);
int value = 0;
Require(Set(client, TcpLevel, TcpNoDelay, 0) && Get(client, TcpLevel, TcpNoDelay) == 0);
Require(Fails(setsockopt_nid_postfix(client, TcpLevel, TcpNoDelay, &one, sizeof(one) - 1), Invalid));
Require(Fails(setsockopt_nid_postfix(client, TcpLevel, TcpMaximumSegment, &one, sizeof(one)), NoProtocolOption));
length = sizeof(value);
Require(Fails(setsockopt_nid_postfix(datagram, TcpLevel, TcpNoDelay, &one, sizeof(one)), Invalid));
Require(Fails(getsockopt_nid_postfix(datagram, TcpLevel, TcpNoDelay, &value, &length), Invalid));
Require(Fails(setsockopt_nid_postfix(local[0], TcpLevel, TcpNoDelay, &one, sizeof(one)), Invalid));
Require(Fails(getsockopt_nid_postfix(local[0], TcpLevel, TcpNoDelay, &value, &length), Invalid));
char received = 0;
Require(Get(server, SocketLevel, NonBlockingOption) == 0);
Require((fcntl_nid_postfix(server, GetStatusFlags) & NonBlockingFlag) == 0);
Require(Set(server, SocketLevel, NonBlockingOption, 5) && Get(server, SocketLevel, NonBlockingOption) == 1);
Require((fcntl_nid_postfix(server, GetStatusFlags) & NonBlockingFlag) != 0);
Require(Fails(recv_nid_postfix(server, &received, sizeof(received), 0), Again));
Require(Set(server, SocketLevel, NonBlockingOption, 0) && Get(server, SocketLevel, NonBlockingOption) == 0);
Require((fcntl_nid_postfix(server, GetStatusFlags) & NonBlockingFlag) == 0);
Require(Fails(setsockopt_nid_postfix(server, SocketLevel, NonBlockingOption, &one, sizeof(one) - 1), Invalid));
Require(Set(datagram, SocketLevel, NonBlockingOption, 1) && Get(datagram, SocketLevel, NonBlockingOption) == 1);
Require(Fails(recv_nid_postfix(datagram, &received, sizeof(received), 0), Again));
#ifndef _WIN32
std::signal(SIGPIPE, CountBrokenPipe);
#endif
Require(Get(client, SocketLevel, NoSigpipe) == 0);
Require(Set(client, SocketLevel, NoSigpipe, 3) && Get(client, SocketLevel, NoSigpipe) == NoSigpipe);
Require(Fails(setsockopt_nid_postfix(client, SocketLevel, NoSigpipe, &one, sizeof(one) - 1), Invalid));
Require(shutdown_nid_postfix(client, 1) == 0);
Require(Fails(send_nid_postfix(client, "x", 1, 0), BrokenPipe));
Require(Fails(write_nid_postfix(client, "x", 1), BrokenPipe));
Require(BrokenPipes() == 0);
Require(Set(client, SocketLevel, NoSigpipe, 0) && Get(client, SocketLevel, NoSigpipe) == 0);
Require(Fails(send_nid_postfix(client, "x", 1, NoSignalFlag), BrokenPipe));
Require(BrokenPipes() == 0);
#ifndef _WIN32
Require(Fails(send_nid_postfix(client, "x", 1, 0), BrokenPipe));
Require(BrokenPipes() == 1);
#endif
const int dualStack = socket_nid_postfix(28, 1, 0);
Require(dualStack >= 0 && Get(dualStack, Ipv6Level, Ipv6Only) == 1);
Require(Set(dualStack, Ipv6Level, Ipv6Only, 0) && Get(dualStack, Ipv6Level, Ipv6Only) == 0);
std::array<std::uint8_t, 28> mapped{28, 28, address[2], address[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1};
Require(connect_nid_postfix(dualStack, mapped.data(), mapped.size()) == 0);
const int mappedPeer = accept_nid_postfix(listener, nullptr, nullptr);
Require(mappedPeer >= 0 && close_nid_postfix(mappedPeer) == 0);
const int datagram6 = socket_nid_postfix(28, 2, 0);
Require(datagram6 >= 0 && Get(datagram6, Ipv6Level, Ipv6Only) == 1);
Require(Set(datagram6, Ipv6Level, Ipv6Only, 9) && Get(datagram6, Ipv6Level, Ipv6Only) == 1);
Require(Fails(setsockopt_nid_postfix(datagram6, Ipv6Level, Ipv6Only, &one, sizeof(one) - 1), Invalid));
Require(Fails(setsockopt_nid_postfix(datagram6, Ipv6Level, Ipv6UnicastHops, &one, sizeof(one)), NoProtocolOption));
length = sizeof(value);
Require(Fails(getsockopt_nid_postfix(datagram6, Ipv6Level, Ipv6UnicastHops, &value, &length), NoProtocolOption));
std::array<std::uint8_t, 28> unspecified6{28, 28};
Require(bind_nid_postfix(datagram6, unspecified6.data(), unspecified6.size()) == 0);
Require(Fails(setsockopt_nid_postfix(datagram6, Ipv6Level, Ipv6Only, &one, sizeof(one)), Invalid));
Require(Fails(setsockopt_nid_postfix(datagram, Ipv6Level, Ipv6Only, &one, sizeof(one)), Invalid));
Require(Fails(getsockopt_nid_postfix(datagram, Ipv6Level, Ipv6Only, &value, &length), Invalid));
Require(Fails(setsockopt_nid_postfix(local[0], Ipv6Level, Ipv6Only, &one, sizeof(one)), Invalid));
Require(close_nid_postfix(datagram6) == 0 && close_nid_postfix(dualStack) == 0);
Require(close_nid_postfix(local[0]) == 0 && close_nid_postfix(local[1]) == 0);
Require(close_nid_postfix(datagram) == 0 && close_nid_postfix(server) == 0);
Require(close_nid_postfix(client) == 0 && close_nid_postfix(listener) == 0);
return 0;
}