Files
AnyPS5/core/libs/tests/GuestSocketDescriptorFlags.cpp
T
xXPBSXxandClaude Sonnet 5.5 84aa2349f8 fix(libkernel): answer F_GETFD and F_SETFD on a guest socket
fcntl on a guest socket handled F_GETFL and F_SETFL only and failed every other command with EINVAL, so libcurl's fcntl(fd, F_SETFD, FD_CLOEXEC) on a new socket failed (ProsperoRadio PPSA99001, traced by screamm on #4796). Record FD_CLOEXEC per socket descriptor: F_SETFD sets or clears it, F_GETFD reads it, SOCK_CLOEXEC sets it at creation, and dup, dup2 and close start without it, as FreeBSD's kern_fcntl and kern_dup do.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-14 19:28:40 +02:00

51 lines
2.2 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
extern "C" {
int APS5_VABI socket_nid_postfix(int, int, int);
int APS5_VABI close_nid_postfix(int);
int APS5_VABI dup_nid_postfix(int);
int APS5_VABI dup2_nid_postfix(int, int);
int APS5_VABI fcntl_nid_postfix(int, int, ...);
int* APS5_VABI __error_nid_postfix();
}
namespace {
constexpr int GetDescriptorFlags = 1;
constexpr int SetDescriptorFlags = 2;
constexpr int CloseOnExec = 1;
constexpr int Stream = 1;
constexpr int SocketCloseOnExec = 0x10000000;
void Require(bool condition, const char* what) {
if (condition) return;
std::fprintf(stderr, "%s (errno %d)\n", what, *__error_nid_postfix());
std::abort();
}
}
int main() {
const int plain = socket_nid_postfix(2, Stream, 0);
Require(plain >= 0, "socket failed");
Require(fcntl_nid_postfix(plain, GetDescriptorFlags) == 0, "a new socket must not be close-on-exec (F_GETFD 0)");
Require(fcntl_nid_postfix(plain, SetDescriptorFlags, CloseOnExec) == 0, "F_SETFD on a socket must succeed");
Require(fcntl_nid_postfix(plain, GetDescriptorFlags) == CloseOnExec, "F_GETFD must read back FD_CLOEXEC");
const int copy = dup_nid_postfix(plain);
Require(copy >= 0 && fcntl_nid_postfix(copy, GetDescriptorFlags) == 0, "dup must clear FD_CLOEXEC on the copy");
Require(fcntl_nid_postfix(plain, GetDescriptorFlags) == CloseOnExec, "dup must leave the flag of the original");
Require(fcntl_nid_postfix(plain, SetDescriptorFlags, 0) == 0 && fcntl_nid_postfix(plain, GetDescriptorFlags) == 0, "F_SETFD 0 must clear FD_CLOEXEC");
Require(close_nid_postfix(copy) == 0, "close failed");
const int marked = socket_nid_postfix(2, Stream | SocketCloseOnExec, 0);
Require(marked >= 0 && fcntl_nid_postfix(marked, GetDescriptorFlags) == CloseOnExec, "SOCK_CLOEXEC must set FD_CLOEXEC");
Require(close_nid_postfix(marked) == 0, "close failed");
const int reused = socket_nid_postfix(2, Stream, 0);
Require(reused >= 0 && fcntl_nid_postfix(reused, GetDescriptorFlags) == 0, "the flag of a closed socket must not reach the next socket");
Require(close_nid_postfix(reused) == 0 && close_nid_postfix(plain) == 0, "close failed");
return 0;
}