Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions core/libs/prx/libSceNet/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,41 @@ bool SetSocketOptionForKernel(int descriptor, int level, int option, const void*

const bool g_socketOptionSetterRegistered = (KernelSetSocketOptionSetter_nid_no_patch(&SetSocketOptionForKernel), true);

constexpr int GuestFcntlGetStatus = 3;
constexpr int GuestFcntlSetStatus = 4;
constexpr int GuestReadWrite = 2;
constexpr int GuestNonblocking = 4;
constexpr int GuestStatusFlagsMask = 7;

bool ControlSocketStatusForKernel(int descriptor, int command, int flags, int* result, int* error) {
bool nonblock = false;
{
std::lock_guard lk(g_mutex);
const auto it = g_socks.find(descriptor);
if (it == g_socks.end()) return false;
nonblock = it->second.nonblock;
}
*result = 0;
*error = 0;
if (command == GuestFcntlGetStatus) {
*result = GuestReadWrite | (nonblock ? GuestNonblocking : 0);
return true;
}
if (command != GuestFcntlSetStatus) {
*error = NET_EINVAL;
return true;
}
if ((flags & ~GuestStatusFlagsMask) != 0) {
*error = NET_EOPNOTSUPP;
return true;
}
const int enabled = (flags & GuestNonblocking) != 0 ? 1 : 0;
if (sceNetSetsockopt(descriptor, NET_SOL_SOCKET, NET_SO_NBIO, &enabled, sizeof(enabled)) != 0) *error = *errno_slot();
return true;
}

const bool g_socketStatusControlRegistered = (KernelSetSocketStatusControl_nid_no_patch(&ControlSocketStatusForKernel), true);

int APS5_VABI sceNetInit_nid_postfix(void) {
std::lock_guard lk(g_mutex);
g_net_inited = true;
Expand Down
3 changes: 3 additions & 0 deletions core/libs/prx/libkernel/Socket/include/SocketPoll.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ struct Entry {
using Poller = int (*)(Entry* entries, int count, int timeoutMilliseconds);
using Closer = bool (*)(int descriptor, int* error);
using OptionSetter = bool (*)(int descriptor, int level, int option, const void* value, std::uint32_t length, int* error);
using StatusControl = bool (*)(int descriptor, int command, int flags, int* result, int* error);
}

extern "C" void KernelSetSocketPoller_nid_no_patch(KernelSocketPoll::Poller poller);
extern "C" void KernelSetSocketCloser_nid_no_patch(KernelSocketPoll::Closer closer);
extern "C" bool KernelCloseSocket_nid_no_patch(int descriptor, int* error);
extern "C" void KernelSetSocketOptionSetter_nid_no_patch(KernelSocketPoll::OptionSetter setter);
extern "C" bool KernelSetSocketOption_nid_no_patch(int descriptor, int level, int option, const void* value, std::uint32_t length, int* error);
extern "C" void KernelSetSocketStatusControl_nid_no_patch(KernelSocketPoll::StatusControl control);
extern "C" bool KernelControlSocketStatus_nid_no_patch(int descriptor, int command, int flags, int* result, int* error);
extern "C" int KernelReserveSocketNumber_nid_no_patch(std::uintptr_t native);
extern "C" void KernelReleaseSocketNumber_nid_no_patch(int number);
10 changes: 10 additions & 0 deletions core/libs/prx/libkernel/Socket/src/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct GuestTimeval {
std::atomic<KernelSocketPoll::Poller> g_socketPoller{nullptr};
std::atomic<KernelSocketPoll::Closer> g_socketCloser{nullptr};
std::atomic<KernelSocketPoll::OptionSetter> g_socketOptionSetter{nullptr};
std::atomic<KernelSocketPoll::StatusControl> g_socketStatusControl{nullptr};

bool DescriptorSet(const void* set, int descriptor) {
return set != nullptr && ((static_cast<const std::uint64_t*>(set)[descriptor / 64] >> (descriptor % 64)) & 1u) != 0;
Expand Down Expand Up @@ -153,6 +154,15 @@ bool KernelSetSocketOption_nid_no_patch(int descriptor, int level, int option, c
return setter != nullptr && setter(descriptor, level, option, value, length, error);
}

void KernelSetSocketStatusControl_nid_no_patch(KernelSocketPoll::StatusControl control) {
g_socketStatusControl.store(control);
}

bool KernelControlSocketStatus_nid_no_patch(int descriptor, int command, int flags, int* result, int* error) {
const auto control = g_socketStatusControl.load();
return control != nullptr && control(descriptor, command, flags, result, error);
}

int APS5_VABI select_nid_postfix(int nfds, void* readfds, void* writefds, void* exceptfds, const void* timeout) {
const auto* limit = static_cast<const GuestTimeval*>(timeout);
if (nfds < 0 || nfds > SelectDescriptorLimit || (limit != nullptr && (limit->seconds < 0 || limit->microseconds < 0 || limit->microseconds >= 1000000))) {
Expand Down
5 changes: 5 additions & 0 deletions core/libs/prx/libkernel/Socket/src/Udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,11 @@ int APS5_VABI fcntl_nid_postfix(int descriptor, int command, ...) {
va_end(arguments);
#endif
}
int result = 0;
int netError = 0;
if (KernelControlSocketStatus_nid_no_patch(descriptor, command, static_cast<int>(argument), &result, &netError)) {
return netError == 0 ? result : Fail(netError);
}
return File::Fcntl(descriptor, command, argument);
}
const auto socket = Lookup(descriptor);
Expand Down
22 changes: 22 additions & 0 deletions core/libs/tests/GuestSceNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ int APS5_VABI socket_nid_postfix(int, int, int);
int APS5_VABI bind_nid_postfix(int, const void*, std::uint32_t);
int APS5_VABI close_nid_postfix(int);
int APS5_VABI setsockopt_nid_postfix(int, int, int, const void*, std::uint32_t);
int APS5_VABI fcntl_nid_postfix(int, int, ...);
int* APS5_VABI __error_nid_postfix();
int APS5_VABI sceNetInetPton(int, const char*, void*);
const char* APS5_VABI sceNetInetNtop(int, const void*, char*, std::uint32_t);
Expand Down Expand Up @@ -506,6 +507,26 @@ static void CheckKernelTimeouts() {
Require(sceNetSocketClose(descriptor) == 0);
}

static void CheckKernelStatusFlags() {
const int descriptor = sceNetSocket("kernel-status", 2, 1, 6);
Require(descriptor >= 0);
Require(fcntl_nid_postfix(descriptor, 3) == 2);
Require(fcntl_nid_postfix(descriptor, 4, 2 | 4) == 0);
Require(fcntl_nid_postfix(descriptor, 3) == (2 | 4));
int enabled = 0;
std::uint32_t length = sizeof(enabled);
Require(sceNetGetsockopt(descriptor, 0xffff, 0x1200, &enabled, &length) == 0 && enabled == 1);
Require(fcntl_nid_postfix(descriptor, 4, 2) == 0);
Require(fcntl_nid_postfix(descriptor, 3) == 2);
length = sizeof(enabled);
Require(sceNetGetsockopt(descriptor, 0xffff, 0x1200, &enabled, &length) == 0 && enabled == 0);
*__error_nid_postfix() = 0;
Require(fcntl_nid_postfix(descriptor, 4, 0x100) == -1 && *__error_nid_postfix() == 45);
*__error_nid_postfix() = 0;
Require(fcntl_nid_postfix(descriptor, 1) == -1 && *__error_nid_postfix() == 22);
Require(close_nid_postfix(descriptor) == 0);
}

static void CheckAddressText(int family, const char* text) {
std::array<std::uint8_t, 16> address{};
Require(sceNetInetPton(family, text, address.data()) == 1);
Expand Down Expand Up @@ -844,6 +865,7 @@ int main() {
Require(Failed(sceNetSocketClose(closed), 9));
CheckKernelTimeouts();
CheckSocketError();
CheckKernelStatusFlags();

const int listener = sceNetSocket(nullptr, 2, 1, 6);
Require(listener >= 0);
Expand Down
Loading