mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
fix(libkernel): forward socket calls on sceNetSocket descriptors to libSceNet
A title can create a socket with sceNetSocket and then call bind, getsockname, sendto or recvfrom from libkernel, which does not hold that descriptor, so the call failed with EBADF. PPSA06866's RakNet does this, its local server fails to start and the load after difficulty selection never ends. libSceNet now registers these four calls with libkernel, as it does for setsockopt and getsockopt. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
bc12e15225
commit
91311f1bf4
5 files changed
+154
No files matched your search
@@ -124,6 +124,17 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(guest_sce_net_keepalive PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNet>")
|
||||
endif()
|
||||
add_test_executable(guest_net_kernel_forwards_tests ${LIBS_INCLUDE_DIR}/tests/GuestNetKernelForwards.cpp)
|
||||
target_include_directories(guest_net_kernel_forwards_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_net_kernel_forwards_tests PRIVATE libSceNet libkernel libc)
|
||||
configure_windows_unwind(guest_net_kernel_forwards_tests)
|
||||
add_test(NAME guest_sce_net_kernel_forwards COMMAND guest_net_kernel_forwards_tests)
|
||||
set_tests_properties(guest_sce_net_kernel_forwards PROPERTIES TIMEOUT 20)
|
||||
if(WIN32)
|
||||
target_link_libraries(guest_net_kernel_forwards_tests PRIVATE ws2_32)
|
||||
set_tests_properties(guest_sce_net_kernel_forwards PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNet>")
|
||||
endif()
|
||||
add_test_executable(guest_datagram_receive_tests ${LIBS_INCLUDE_DIR}/tests/GuestDatagramReceive.cpp)
|
||||
target_include_directories(guest_datagram_receive_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_datagram_receive_tests PRIVATE libSceNet libkernel libc)
|
||||
|
||||
@@ -928,6 +928,42 @@ bool GetSocketOptionForKernel(int descriptor, int level, int option, void* value
|
||||
|
||||
const bool g_socketOptionGetterRegistered = (KernelSetSocketOptionGetter_nid_no_patch(&GetSocketOptionForKernel), true);
|
||||
|
||||
bool OwnsSocket(int descriptor) {
|
||||
std::lock_guard lk(g_mutex);
|
||||
return g_socks.count(descriptor) != 0;
|
||||
}
|
||||
|
||||
int ErrorOf(std::int64_t result) {
|
||||
return result < 0 ? *errno_slot() : 0;
|
||||
}
|
||||
|
||||
const KernelSocketPoll::Forwards g_socketForwards{
|
||||
[](int descriptor, const void* address, std::uint32_t length, int* error) {
|
||||
if (!OwnsSocket(descriptor)) return false;
|
||||
*error = ErrorOf(sceNetBind_nid_postfix(descriptor, address, length));
|
||||
return true;
|
||||
},
|
||||
[](int descriptor, void* address, std::uint32_t* length, int* error) {
|
||||
if (!OwnsSocket(descriptor)) return false;
|
||||
*error = ErrorOf(sceNetGetsockname(descriptor, address, length));
|
||||
return true;
|
||||
},
|
||||
[](int descriptor, const void* buffer, std::uint64_t length, int flags, const void* address, std::uint32_t addressLength, std::int64_t* result, int* error) {
|
||||
if (!OwnsSocket(descriptor)) return false;
|
||||
*result = sceNetSendto(descriptor, buffer, static_cast<size_t>(length), flags, address, addressLength);
|
||||
*error = ErrorOf(*result);
|
||||
return true;
|
||||
},
|
||||
[](int descriptor, void* buffer, std::uint64_t length, int flags, void* address, std::uint32_t* addressLength, std::int64_t* result, int* error) {
|
||||
if (!OwnsSocket(descriptor)) return false;
|
||||
*result = sceNetRecvfrom(descriptor, buffer, static_cast<size_t>(length), flags, address, addressLength);
|
||||
*error = ErrorOf(*result);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
const bool g_socketForwardsRegistered = (KernelSetSocketForwards_nid_no_patch(&g_socketForwards), true);
|
||||
|
||||
constexpr int GuestFcntlGetStatus = 3;
|
||||
constexpr int GuestFcntlSetStatus = 4;
|
||||
constexpr int GuestReadWrite = 2;
|
||||
|
||||
@@ -21,6 +21,12 @@ 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 OptionGetter = bool (*)(int descriptor, int level, int option, void* value, std::uint32_t* length, int* error);
|
||||
using StatusControl = bool (*)(int descriptor, int command, int flags, int* result, int* error);
|
||||
struct Forwards {
|
||||
bool (*bind)(int descriptor, const void* address, std::uint32_t length, int* error);
|
||||
bool (*getsockname)(int descriptor, void* address, std::uint32_t* length, int* error);
|
||||
bool (*sendto)(int descriptor, const void* buffer, std::uint64_t length, int flags, const void* address, std::uint32_t addressLength, std::int64_t* result, int* error);
|
||||
bool (*recvfrom)(int descriptor, void* buffer, std::uint64_t length, int flags, void* address, std::uint32_t* addressLength, std::int64_t* result, int* error);
|
||||
};
|
||||
struct NativeOwner {
|
||||
int (*transfer)(NativeOwner* owner, bool send, void* buffer, int length) = nullptr;
|
||||
};
|
||||
@@ -28,6 +34,7 @@ struct NativeOwner {
|
||||
using NativeLookup = bool (*)(int descriptor, std::shared_ptr<void>* owner, std::uintptr_t* native);
|
||||
}
|
||||
|
||||
extern "C" void KernelSetSocketForwards_nid_no_patch(const KernelSocketPoll::Forwards* forwards);
|
||||
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);
|
||||
|
||||
@@ -270,6 +270,10 @@ int Install(std::shared_ptr<Socket> socket) {
|
||||
}
|
||||
return number;
|
||||
}
|
||||
std::atomic<const KernelSocketPoll::Forwards*> socketForwards{nullptr};
|
||||
const KernelSocketPoll::Forwards* ForwardsFor(int descriptor) {
|
||||
return GuestSockets::IsOpen(descriptor) ? nullptr : socketForwards.load(std::memory_order_acquire);
|
||||
}
|
||||
std::shared_ptr<Socket> Lookup(int descriptor) {
|
||||
std::lock_guard lock(socketsMutex);
|
||||
const auto found = sockets.find(descriptor);
|
||||
@@ -652,6 +656,10 @@ extern "C" void KernelReleaseSocketNumber_nid_no_patch(int number) {
|
||||
ReleaseNumber(number);
|
||||
}
|
||||
|
||||
extern "C" void KernelSetSocketForwards_nid_no_patch(const KernelSocketPoll::Forwards* forwards) {
|
||||
socketForwards.store(forwards, std::memory_order_release);
|
||||
}
|
||||
|
||||
namespace {
|
||||
#ifdef _WIN32
|
||||
using NativePollDescriptor = WSAPOLLFD;
|
||||
@@ -1545,6 +1553,8 @@ std::int64_t APS5_VABI recv_nid_postfix(int descriptor, void* buffer, std::uint6
|
||||
return result < 0 ? Fail(NativeError()) : result;
|
||||
}
|
||||
int APS5_VABI bind_nid_postfix(int descriptor, const void* address, std::uint32_t length) {
|
||||
int netError = 0;
|
||||
if (const auto* forwards = ForwardsFor(descriptor); forwards != nullptr && forwards->bind(descriptor, address, length, &netError)) return netError == 0 ? 0 : Fail(netError);
|
||||
if (const int error = AddressLengthError(address, length)) return Fail(error);
|
||||
const auto socket = Lookup(descriptor);
|
||||
if (!socket) return -1;
|
||||
@@ -1608,6 +1618,8 @@ int CopyAddressOut(const sockaddr_storage& native, bool unnamed, void* address,
|
||||
int APS5_VABI getsockname_nid_postfix(int descriptor, void* address, std::uint32_t* length) {
|
||||
std::uint32_t capacity = 0;
|
||||
if (!GuestCopyIn_nid_no_patch(&capacity, length, sizeof(capacity))) return Fail(14);
|
||||
int netError = 0;
|
||||
if (const auto* forwards = ForwardsFor(descriptor); forwards != nullptr && forwards->getsockname(descriptor, address, length, &netError)) return netError == 0 ? 0 : Fail(netError);
|
||||
const auto socket = Lookup(descriptor);
|
||||
if (!socket) return -1;
|
||||
if (socket->family == GuestUnix) return CopyAddressOut({}, true, address, length, capacity);
|
||||
@@ -1674,6 +1686,9 @@ int APS5_VABI _ioctl_nid_postfix(int descriptor, std::uint64_t request, void* ar
|
||||
}
|
||||
std::int64_t APS5_VABI sendto_nid_postfix(int descriptor, const void* buffer, std::uint64_t length,
|
||||
int flags, const void* address, std::uint32_t addressLength) {
|
||||
std::int64_t netResult = 0;
|
||||
int netError = 0;
|
||||
if (const auto* forwards = ForwardsFor(descriptor); forwards != nullptr && forwards->sendto(descriptor, buffer, length, flags, address, addressLength, &netResult, &netError)) return netError == 0 ? netResult : Fail(netError);
|
||||
std::array<unsigned char, 255> destinationCopy;
|
||||
if (address) {
|
||||
if (const int error = AddressLengthError(address, addressLength)) return Fail(error);
|
||||
@@ -1711,6 +1726,9 @@ std::int64_t APS5_VABI sendto_nid_postfix(int descriptor, const void* buffer, st
|
||||
}
|
||||
std::int64_t APS5_VABI recvfrom_nid_postfix(int descriptor, void* buffer, std::uint64_t length,
|
||||
int flags, void* address, std::uint32_t* addressLength) {
|
||||
std::int64_t netResult = 0;
|
||||
int netError = 0;
|
||||
if (const auto* forwards = ForwardsFor(descriptor); forwards != nullptr && forwards->recvfrom(descriptor, buffer, length, flags, address, addressLength, &netResult, &netError)) return netError == 0 ? netResult : Fail(netError);
|
||||
std::uint32_t capacity = 0;
|
||||
if (addressLength && !GuestCopyIn_nid_no_patch(&capacity, addressLength, sizeof(capacity))) return Fail(14);
|
||||
const auto socket = Lookup(descriptor);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "prx/libSceNet/libSceNet.hpp"
|
||||
#include "prx/libkernel/libkernel.hpp"
|
||||
|
||||
static void Require(bool condition) {
|
||||
if (!condition) std::abort();
|
||||
}
|
||||
|
||||
static bool Failed(std::int64_t result, int error) {
|
||||
return result == -1 && *__error_nid_postfix() == error;
|
||||
}
|
||||
|
||||
static void ClearError() {
|
||||
*__error_nid_postfix() = 0;
|
||||
}
|
||||
|
||||
static void CheckForwardedDatagram() {
|
||||
const int receiver = sceNetSocket("forward-receiver", 2, 2, 17);
|
||||
const int sender = sceNetSocket("forward-sender", 2, 2, 17);
|
||||
Require(receiver >= 0 && sender >= 0);
|
||||
std::array<unsigned char, 16> local{16, 2, 0, 0, 127, 0, 0, 1};
|
||||
Require(bind_nid_postfix(receiver, local.data(), local.size()) == 0);
|
||||
Require(bind_nid_postfix(sender, local.data(), local.size()) == 0);
|
||||
std::array<unsigned char, 16> receiverAddress{};
|
||||
std::array<unsigned char, 16> senderAddress{};
|
||||
std::uint32_t size = receiverAddress.size();
|
||||
Require(getsockname_nid_postfix(receiver, receiverAddress.data(), &size) == 0 && size == receiverAddress.size());
|
||||
Require((receiverAddress[2] | receiverAddress[3]) != 0);
|
||||
size = senderAddress.size();
|
||||
Require(getsockname_nid_postfix(sender, senderAddress.data(), &size) == 0 && size == senderAddress.size());
|
||||
const char payload[] = "ping";
|
||||
Require(sendto_nid_postfix(sender, payload, sizeof(payload), 0, receiverAddress.data(), receiverAddress.size()) == sizeof(payload));
|
||||
char received[8]{};
|
||||
std::array<unsigned char, 16> from{};
|
||||
size = from.size();
|
||||
Require(recvfrom_nid_postfix(receiver, received, sizeof(received), 0, from.data(), &size) == sizeof(payload));
|
||||
Require(std::strcmp(received, payload) == 0 && size == from.size());
|
||||
Require(from[2] == senderAddress[2] && from[3] == senderAddress[3]);
|
||||
Require(sceNetSocketClose(receiver) == 0 && sceNetSocketClose(sender) == 0);
|
||||
}
|
||||
|
||||
static void CheckForwardedErrors() {
|
||||
const int socket = sceNetSocket("forward-errors", 2, 2, 17);
|
||||
Require(socket >= 0);
|
||||
std::array<unsigned char, 16> local{16, 2, 0, 0, 127, 0, 0, 1};
|
||||
ClearError();
|
||||
Require(Failed(bind_nid_postfix(socket, local.data(), 1), 22));
|
||||
Require(bind_nid_postfix(socket, local.data(), local.size()) == 0);
|
||||
char received[8]{};
|
||||
ClearError();
|
||||
Require(Failed(recvfrom_nid_postfix(socket, received, sizeof(received), 0x80, nullptr, nullptr), 35));
|
||||
ClearError();
|
||||
Require(Failed(getsockname_nid_postfix(socket, nullptr, nullptr), 22));
|
||||
ClearError();
|
||||
Require(Failed(sendto_nid_postfix(socket, "x", 1, 0, local.data(), 1), 22));
|
||||
Require(sceNetSocketClose(socket) == 0);
|
||||
}
|
||||
|
||||
static void CheckUnknownDescriptor() {
|
||||
constexpr int unknown = 0x7ffffff0;
|
||||
std::array<unsigned char, 16> local{16, 2, 0, 0, 127, 0, 0, 1};
|
||||
std::uint32_t size = local.size();
|
||||
char byte = 0;
|
||||
ClearError();
|
||||
Require(Failed(bind_nid_postfix(unknown, local.data(), local.size()), 9));
|
||||
ClearError();
|
||||
Require(Failed(getsockname_nid_postfix(unknown, local.data(), &size), 9));
|
||||
ClearError();
|
||||
Require(Failed(sendto_nid_postfix(unknown, &byte, 1, 0, local.data(), local.size()), 9));
|
||||
ClearError();
|
||||
Require(Failed(recvfrom_nid_postfix(unknown, &byte, 1, 0, nullptr, nullptr), 9));
|
||||
}
|
||||
|
||||
int main() {
|
||||
CheckForwardedDatagram();
|
||||
CheckForwardedErrors();
|
||||
CheckUnknownDescriptor();
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user