#include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include #include 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*); 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); int APS5_VABI getpeername_nid_postfix(int, void*, std::uint32_t*); int APS5_VABI shutdown_nid_postfix(int, int); 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); int* APS5_VABI __error_nid_postfix(); } static void Require(bool condition) { if (!condition) std::abort(); } static void StreamReceiveReportsNoSender() { 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 && listen_nid_postfix(listener, 4) == 0); std::uint32_t size = address.size(); Require(getsockname_nid_postfix(listener, address.data(), &size) == 0); const int client = socket_nid_postfix(2, 1, 0); Require(connect_nid_postfix(client, address.data(), address.size()) == 0); const int accepted = accept_nid_postfix(listener, nullptr, nullptr); Require(accepted >= 0); const char text[] = "stream"; Require(send_nid_postfix(client, text, sizeof(text), 0) == sizeof(text)); std::array sender; sender.fill(0xaa); char received[sizeof(text)]{}; std::uint32_t senderSize = sender.size(); Require(recvfrom_nid_postfix(accepted, received, sizeof(received), 0, sender.data(), &senderSize) == sizeof(text)); Require(std::strcmp(text, received) == 0); Require(senderSize == 0 && sender[0] == 0xaa && sender[1] == 0xaa); for (const int descriptor : {client, accepted, listener}) Require(close_nid_postfix(descriptor) == 0); } static void ListenersShareAPortAcrossFamilies() { const int inet = socket_nid_postfix(2, 1, 0); Require(inet >= 0); std::array any{16, 2}; Require(bind_nid_postfix(inet, any.data(), any.size()) == 0 && listen_nid_postfix(inet, 4) == 0); std::uint32_t size = any.size(); Require(getsockname_nid_postfix(inet, any.data(), &size) == 0 && size == any.size()); const int inet6 = socket_nid_postfix(28, 1, 0); if (inet6 < 0) { Require(*__error_nid_postfix() == 47); Require(close_nid_postfix(inet) == 0); return; } std::array any6{28, 28, any[2], any[3]}; if (bind_nid_postfix(inet6, any6.data(), any6.size()) != 0) { if (*__error_nid_postfix() != 49) { std::fprintf(stderr, "bind of [::]:%d failed with errno %d while an IPv4 listener holds 0.0.0.0:%d\n", (any[2] << 8) | any[3], *__error_nid_postfix(), (any[2] << 8) | any[3]); std::abort(); } } else { Require(listen_nid_postfix(inet6, 4) == 0); } Require(close_nid_postfix(inet6) == 0); Require(close_nid_postfix(inet) == 0); } int main() { StreamReceiveReportsNoSender(); ListenersShareAPortAcrossFamilies(); const int listener = socket_nid_postfix(2, 1, 6); 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(bind_nid_postfix(listener, address.data(), address.size()) == -1 && *__error_nid_postfix() == 22); Require(listen_nid_postfix(listener, 4) == 0); std::uint32_t address_size = address.size(); Require(getsockname_nid_postfix(listener, address.data(), &address_size) == 0); Require(address_size == 16 && (address[2] != 0 || address[3] != 0)); const int client = socket_nid_postfix(2, 1, 0); Require(client >= 0); Require(accept_nid_postfix(client, nullptr, nullptr) == -1 && *__error_nid_postfix() == 22); Require(connect_nid_postfix(client, address.data(), address.size()) == 0); std::array peer{}; address_size = peer.size(); const int accepted = accept_nid_postfix(listener, peer.data(), &address_size); Require(accepted >= 0 && address_size == 16 && peer[1] == 2); std::array connected_peer{}; address_size = connected_peer.size(); Require(getpeername_nid_postfix(accepted, connected_peer.data(), &address_size) == 0); Require(address_size == 16 && connected_peer[1] == 2); for (auto query : {getsockname_nid_postfix, getpeername_nid_postfix}) { std::array expected{}; address_size = expected.size(); Require(query(accepted, expected.data(), &address_size) == 0 && address_size == expected.size()); for (std::uint32_t capacity : {0u, 1u, 2u, 15u, 16u, 28u, UINT32_MAX}) { std::array actual; actual.fill(0xa5); address_size = capacity; const auto copied = std::min(capacity, std::uint32_t{16}); Require(query(accepted, actual.data(), &address_size) == 0 && address_size == copied); Require(std::memcmp(actual.data(), expected.data(), copied) == 0); Require(std::all_of(actual.begin() + copied, actual.end(), [](auto byte) { return byte == 0xa5; })); } } const int shortClient = socket_nid_postfix(2, 1, 0); Require(shortClient >= 0 && connect_nid_postfix(shortClient, address.data(), address.size()) == 0); peer.fill(0xa5); address_size = 1; const int shortAccepted = accept_nid_postfix(listener, peer.data(), &address_size); Require(shortAccepted >= 0 && address_size == 1 && peer[0] == 16); Require(std::all_of(peer.begin() + 1, peer.end(), [](auto byte) { return byte == 0xa5; })); Require(close_nid_postfix(shortAccepted) == 0 && close_nid_postfix(shortClient) == 0); const char request[] = "guest TCP loopback"; char received[sizeof(request)]{}; Require(send_nid_postfix(client, request, sizeof(request), 0x1) == -1 && *__error_nid_postfix() == 45); Require(send_nid_postfix(client, request, sizeof(request), 0x20000) == sizeof(request)); Require(recv_nid_postfix(accepted, received, sizeof(received), 0) == sizeof(received)); Require(std::strcmp(request, received) == 0); Require(shutdown_nid_postfix(client, 1) == 0); Require(send_nid_postfix(client, request, sizeof(request), 0x20000) == -1 && *__error_nid_postfix() == 32); Require(close_nid_postfix(accepted) == 0); #ifndef _WIN32 std::int64_t sent = 0; for (int i = 0; i < 100 && sent >= 0; ++i) sent = send_nid_postfix(client, request, sizeof(request), 0x20000); Require(sent == -1 && *__error_nid_postfix() == 32); #endif Require(close_nid_postfix(client) == 0); Require(close_nid_postfix(listener) == 0); Require(close_nid_postfix(listener) == -1 && *__error_nid_postfix() == 9); }