feat(libSceNet): implement sceNetResolverAbort and sceNetResolverStartNtoaMultipleRecords
UFC 6 (PPSA23566) imports sceNetResolverAbort (#992, #1502); Palworld (PPSA23126) and LEGO Horizon Adventures (PPSA14632) import sceNetResolverStartNtoaMultipleRecords. Signatures and behaviour follow shadPS4 811bfcd7d17e (src/core/libraries/net/net.cpp, net_resolver.cpp); the abort signature also matches SharpProspero Interop/Net/Socket.cs. sceNetResolverStartNtoaMultipleRecords shares the lookup of the Ex form and, like it, throws for any flag. sceNetResolverAbort returns EBADF for an unknown resolver and throws for flag bits other than NTOA (1) and ATON (2) preservation. Host lookups cannot be interrupted, so an abort during a running lookup makes it fail with EINTR when the host call returns, without writing its output; with nothing running, the preservation flags make the next lookup of that kind fail with EINTR. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit bcc8be8a58aa6a9e6b7c288d8a90af6ed63837aa)
This commit is contained in:
parent
9742ec12c8
commit
3d64981643
|
|
@ -30,6 +30,7 @@
|
|||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/GuestArena.hpp"
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
namespace {
|
||||
// FreeBSD errno numbers as reported through sceNetErrnoLoc (SCE_NET_ERROR_* is 0x80410100 + errno).
|
||||
constexpr int NET_ENOENT = 2;
|
||||
constexpr int NET_EINTR = 4;
|
||||
constexpr int NET_EBADF = 9;
|
||||
constexpr int NET_EACCES = 13;
|
||||
constexpr int NET_EFAULT = 14;
|
||||
|
|
@ -66,6 +68,8 @@ constexpr int NET_ECONNREFUSED = 61;
|
|||
constexpr int NET_EHOSTUNREACH = 65;
|
||||
constexpr int NET_ERROR_BASE = static_cast<int>(0x80410100u);
|
||||
constexpr int NET_ERROR_RESOLVER_ENODNS = static_cast<int>(0x804101E1u);
|
||||
constexpr int NET_RESOLVER_ABORT_FLAG_NTOA_PRESERVATION = 0x1;
|
||||
constexpr int NET_RESOLVER_ABORT_FLAG_ATON_PRESERVATION = 0x2;
|
||||
|
||||
constexpr int NET_AF_INET = 2;
|
||||
constexpr int NET_AF_INET6 = 28;
|
||||
|
|
@ -302,7 +306,14 @@ struct NetMemoryPoolStats {
|
|||
std::size_t max_inuse_size;
|
||||
std::size_t current_inuse_size;
|
||||
};
|
||||
std::map<int, int> g_resolvers;
|
||||
struct Resolver {
|
||||
int error = 0;
|
||||
int running = 0;
|
||||
std::uint64_t aborts = 0;
|
||||
bool abort_ntoa = false;
|
||||
bool abort_aton = false;
|
||||
};
|
||||
std::map<int, Resolver> g_resolvers;
|
||||
int g_next_sock = 32;
|
||||
int g_next_epoll = 0x4000;
|
||||
int g_next_pool = 1;
|
||||
|
|
@ -365,10 +376,27 @@ int set_kernel_timeout(int descriptor, int optname, const void* value, std::uint
|
|||
return 0;
|
||||
}
|
||||
|
||||
void set_resolver_error(int rid, int error) {
|
||||
int begin_lookup(int rid, bool Resolver::*preservedAbort, std::uint64_t& generation) {
|
||||
std::lock_guard lk(g_mutex);
|
||||
const auto resolver = g_resolvers.find(rid);
|
||||
if (resolver != g_resolvers.end()) resolver->second = error;
|
||||
if (resolver == g_resolvers.end()) return fail(NET_EBADF);
|
||||
if (std::exchange(resolver->second.*preservedAbort, false)) {
|
||||
resolver->second.error = NET_ERROR_BASE | NET_EINTR;
|
||||
return fail(NET_EINTR);
|
||||
}
|
||||
++resolver->second.running;
|
||||
generation = resolver->second.aborts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_lookup(int rid, std::uint64_t generation, int error) {
|
||||
std::lock_guard lk(g_mutex);
|
||||
const auto resolver = g_resolvers.find(rid);
|
||||
if (resolver == g_resolvers.end()) return error;
|
||||
--resolver->second.running;
|
||||
if (resolver->second.aborts != generation) error = fail(NET_EINTR);
|
||||
resolver->second.error = error;
|
||||
return error;
|
||||
}
|
||||
|
||||
void log_soft(const char* func, const char* what) {
|
||||
|
|
@ -1244,7 +1272,7 @@ int APS5_VABI sceNetResolverCreate(const char* name, int memid, int flags) {
|
|||
(void)flags;
|
||||
std::lock_guard lk(g_mutex);
|
||||
const int id = g_next_resolver++;
|
||||
g_resolvers[id] = 0;
|
||||
g_resolvers[id] = {};
|
||||
return id;
|
||||
}
|
||||
|
||||
|
|
@ -1254,11 +1282,9 @@ int APS5_VABI sceNetResolverDestroy(int rid) {
|
|||
}
|
||||
|
||||
int lookup_ipv4(int rid, const char* hostname, const char* func, std::vector<std::uint32_t>& addresses) {
|
||||
{
|
||||
std::lock_guard lk(g_mutex);
|
||||
if (g_resolvers.count(rid) == 0) return fail(NET_EBADF);
|
||||
}
|
||||
if (!initialize_sockets()) return fail(5);
|
||||
std::uint64_t generation = 0;
|
||||
if (const int error = begin_lookup(rid, &Resolver::abort_ntoa, generation)) return error;
|
||||
addrinfo hints{};
|
||||
hints.ai_family = AF_INET;
|
||||
addrinfo* results = nullptr;
|
||||
|
|
@ -1266,16 +1292,14 @@ int lookup_ipv4(int rid, const char* hostname, const char* func, std::vector<std
|
|||
if (result != 0) {
|
||||
set_errno(result == EAI_AGAIN ? NET_ETIMEDOUT : NET_ENOENT);
|
||||
log_soft(func, "host DNS lookup failed");
|
||||
set_resolver_error(rid, NET_ERROR_RESOLVER_ENODNS);
|
||||
return NET_ERROR_RESOLVER_ENODNS;
|
||||
return end_lookup(rid, generation, NET_ERROR_RESOLVER_ENODNS);
|
||||
}
|
||||
for (const addrinfo* entry = results; entry != nullptr; entry = entry->ai_next) {
|
||||
const auto address = reinterpret_cast<const sockaddr_in*>(entry->ai_addr)->sin_addr.s_addr;
|
||||
if (std::find(addresses.begin(), addresses.end(), address) == addresses.end()) addresses.push_back(address);
|
||||
}
|
||||
::freeaddrinfo(results);
|
||||
set_resolver_error(rid, 0);
|
||||
return 0;
|
||||
return end_lookup(rid, generation, 0);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetResolverStartNtoa(int rid, const char* hostname, void* addr, int timeout, int retry, int flags) {
|
||||
|
|
@ -1305,14 +1329,11 @@ struct NetResolverInfo {
|
|||
static_assert(sizeof(NetResolverRecord) == 32 && offsetof(NetResolverRecord, family) == 16);
|
||||
static_assert(sizeof(NetResolverInfo) == 384 && offsetof(NetResolverInfo, count) == 320 && offsetof(NetResolverInfo, count4) == 324);
|
||||
|
||||
int APS5_VABI sceNetResolverStartNtoaMultipleRecordsEx(int rid, const char* hostname, NetResolverInfo* info, int timeout,
|
||||
int retry, int flags) {
|
||||
(void)timeout;
|
||||
(void)retry;
|
||||
if (flags != 0) throw std::runtime_error("sceNetResolverStartNtoaMultipleRecordsEx: flags " + std::to_string(flags) + " are not supported");
|
||||
int lookup_records(int rid, const char* hostname, NetResolverInfo* info, int flags, const char* func) {
|
||||
if (flags != 0) throw std::runtime_error(std::string(func) + ": flags " + std::to_string(flags) + " are not supported");
|
||||
if (!hostname || !info) return fail(NET_EINVAL);
|
||||
std::vector<std::uint32_t> addresses;
|
||||
if (const int error = lookup_ipv4(rid, hostname, __func__, addresses)) return error;
|
||||
if (const int error = lookup_ipv4(rid, hostname, func, addresses)) return error;
|
||||
*info = {};
|
||||
info->count = static_cast<std::int32_t>(std::min<std::size_t>(addresses.size(), std::size(info->records)));
|
||||
info->count4 = info->count;
|
||||
|
|
@ -1323,28 +1344,41 @@ int APS5_VABI sceNetResolverStartNtoaMultipleRecordsEx(int rid, const char* host
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetResolverStartNtoaMultipleRecords(int rid, const char* hostname, NetResolverInfo* info, int timeout,
|
||||
int retry, int flags) {
|
||||
(void)timeout;
|
||||
(void)retry;
|
||||
return lookup_records(rid, hostname, info, flags, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetResolverStartNtoaMultipleRecordsEx(int rid, const char* hostname, NetResolverInfo* info, int timeout,
|
||||
int retry, int flags) {
|
||||
(void)timeout;
|
||||
(void)retry;
|
||||
return lookup_records(rid, hostname, info, flags, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetResolverStartAton(int rid, const void* addr, char* hostname, int len, int timeout, int retry, int flags) {
|
||||
(void)timeout;
|
||||
(void)retry;
|
||||
(void)flags;
|
||||
if (!addr || !hostname || len <= 0) return fail(NET_EINVAL);
|
||||
{
|
||||
std::lock_guard lk(g_mutex);
|
||||
if (g_resolvers.count(rid) == 0) return fail(NET_EBADF);
|
||||
}
|
||||
if (!initialize_sockets()) return fail(5);
|
||||
std::uint64_t generation = 0;
|
||||
if (const int error = begin_lookup(rid, &Resolver::abort_aton, generation)) return error;
|
||||
sockaddr_in address{};
|
||||
address.sin_family = AF_INET;
|
||||
std::memcpy(&address.sin_addr, addr, sizeof(address.sin_addr));
|
||||
const int result = ::getnameinfo(reinterpret_cast<const sockaddr*>(&address), sizeof(address), hostname,
|
||||
std::vector<char> name(static_cast<std::size_t>(len));
|
||||
const int result = ::getnameinfo(reinterpret_cast<const sockaddr*>(&address), sizeof(address), name.data(),
|
||||
static_cast<NativeLength>(len), nullptr, 0, NI_NAMEREQD);
|
||||
if (result != 0) {
|
||||
set_errno(result == EAI_AGAIN ? NET_ETIMEDOUT : NET_ENOENT);
|
||||
log_soft(__func__, "host reverse DNS lookup failed");
|
||||
set_resolver_error(rid, NET_ERROR_RESOLVER_ENODNS);
|
||||
return NET_ERROR_RESOLVER_ENODNS;
|
||||
return end_lookup(rid, generation, NET_ERROR_RESOLVER_ENODNS);
|
||||
}
|
||||
set_resolver_error(rid, 0);
|
||||
if (const int error = end_lookup(rid, generation, 0)) return error;
|
||||
std::memcpy(hostname, name.data(), std::strlen(name.data()) + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1353,17 +1387,23 @@ int APS5_VABI sceNetResolverGetError(int rid, int* status) {
|
|||
std::lock_guard lk(g_mutex);
|
||||
const auto resolver = g_resolvers.find(rid);
|
||||
if (resolver == g_resolvers.end()) return fail(NET_EBADF);
|
||||
*status = resolver->second;
|
||||
*status = resolver->second.error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetResolverAbort(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNetResolverStartNtoaMultipleRecords() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceNetResolverAbort(int rid, int flags) {
|
||||
constexpr int preservation = NET_RESOLVER_ABORT_FLAG_NTOA_PRESERVATION | NET_RESOLVER_ABORT_FLAG_ATON_PRESERVATION;
|
||||
std::lock_guard lk(g_mutex);
|
||||
const auto resolver = g_resolvers.find(rid);
|
||||
if (resolver == g_resolvers.end()) return fail(NET_EBADF);
|
||||
if ((flags & ~preservation) != 0) throw std::runtime_error("sceNetResolverAbort: flags " + std::to_string(flags) + " are not supported");
|
||||
if (resolver->second.running != 0) {
|
||||
++resolver->second.aborts;
|
||||
resolver->second.error = NET_ERROR_BASE | NET_EINTR;
|
||||
return 0;
|
||||
}
|
||||
if ((flags & NET_RESOLVER_ABORT_FLAG_NTOA_PRESERVATION) != 0) resolver->second.abort_ntoa = true;
|
||||
if ((flags & NET_RESOLVER_ABORT_FLAG_ATON_PRESERVATION) != 0) resolver->second.abort_aton = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ extern const std::uint8_t sce_net_in6addr_linklocal_allnodes[16];
|
|||
int APS5_VABI sceNetResolverCreate(const char*, int, int);
|
||||
int APS5_VABI sceNetResolverStartNtoa(int, const char*, void*, int, int, int);
|
||||
int APS5_VABI sceNetResolverStartNtoaMultipleRecordsEx(int, const char*, void*, int, int, int);
|
||||
int APS5_VABI sceNetResolverStartNtoaMultipleRecords(int, const char*, void*, int, int, int);
|
||||
int APS5_VABI sceNetResolverStartAton(int, const void*, char*, int, int, int, int);
|
||||
int APS5_VABI sceNetResolverAbort(int, int);
|
||||
int APS5_VABI sceNetResolverDestroy(int);
|
||||
int APS5_VABI sceNetResolverGetError(int, int*);
|
||||
int APS5_VABI sceNetCtlGetState(int*);
|
||||
|
|
@ -669,6 +672,75 @@ int main() {
|
|||
static_cast<int>(0x80410116) && *sceNetErrnoLoc() == 22);
|
||||
Require(sceNetResolverStartNtoaMultipleRecordsEx(resolver, "guest-sce-net.invalid.", records.data(), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x804101E1) && records == resolved);
|
||||
|
||||
std::array<std::uint8_t, 512> plain{};
|
||||
plain.fill(0xA5);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, "localhost", plain.data(), 5000000, 1, 0) == 0);
|
||||
Require(plain == resolved);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == 0);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, nullptr, plain.data(), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410116) && *sceNetErrnoLoc() == 22 && plain == resolved);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, "localhost", nullptr, 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410116) && *sceNetErrnoLoc() == 22);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, "guest-sce-net.invalid", plain.data(), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x804101E1) && plain == resolved);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == static_cast<int>(0x804101E1));
|
||||
for (const int flags : {0x1, 0x10000}) {
|
||||
bool threw = false;
|
||||
try { sceNetResolverStartNtoaMultipleRecords(resolver, "localhost", plain.data(), 5000000, 1, flags); }
|
||||
catch (const std::runtime_error&) { threw = true; }
|
||||
Require(threw && plain == resolved);
|
||||
}
|
||||
|
||||
const std::array<std::uint8_t, 4> loopback{127, 0, 0, 1};
|
||||
char reverse[256]{};
|
||||
Require(sceNetResolverAbort(resolver, 0) == 0);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == static_cast<int>(0x804101E1));
|
||||
Require(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, 1, 0) == 0);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == 0);
|
||||
Require(sceNetResolverAbort(resolver, 1) == 0);
|
||||
Require(sceNetResolverAbort(resolver, 1) == 0);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == 0);
|
||||
const int reverse_result = sceNetResolverStartAton(resolver, loopback.data(), reverse, sizeof(reverse), 5000000, 1, 0);
|
||||
Require(reverse_result == 0 || reverse_result == static_cast<int>(0x804101E1));
|
||||
Require(sceNetResolverStartNtoa(resolver, nullptr, ipv4.data(), 5000000, 1, 0) == static_cast<int>(0x80410116));
|
||||
ipv4.fill(0xA5);
|
||||
Require(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, 1, 0) == static_cast<int>(0x80410104) &&
|
||||
*sceNetErrnoLoc() == 4 && ipv4[0] == 0xA5);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == static_cast<int>(0x80410104));
|
||||
Require(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, 1, 0) == 0 && ipv4[0] == 127);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == 0);
|
||||
Require(sceNetResolverAbort(resolver, 1) == 0);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, "localhost", plain.data(), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410104) && *sceNetErrnoLoc() == 4);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, "localhost", plain.data(), 5000000, 1, 0) == 0 && plain == resolved);
|
||||
Require(sceNetResolverAbort(resolver, 2) == 0);
|
||||
Require(sceNetResolverStartNtoaMultipleRecordsEx(resolver, "localhost", records.data(), 5000000, 1, 0) == 0 && records == resolved);
|
||||
std::memset(reverse, 0x5A, sizeof(reverse));
|
||||
Require(sceNetResolverStartAton(resolver, loopback.data(), reverse, sizeof(reverse), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410104) && *sceNetErrnoLoc() == 4 && reverse[0] == 0x5A);
|
||||
Require(sceNetResolverGetError(resolver, &resolver_error) == 0 && resolver_error == static_cast<int>(0x80410104));
|
||||
Require(sceNetResolverStartAton(resolver, loopback.data(), reverse, sizeof(reverse), 5000000, 1, 0) == reverse_result);
|
||||
Require(sceNetResolverAbort(resolver, 3) == 0);
|
||||
Require(sceNetResolverStartAton(resolver, loopback.data(), reverse, sizeof(reverse), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410104) && *sceNetErrnoLoc() == 4);
|
||||
Require(sceNetResolverStartNtoaMultipleRecordsEx(resolver, "localhost", records.data(), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410104) && *sceNetErrnoLoc() == 4 && records == resolved);
|
||||
Require(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, 1, 0) == 0);
|
||||
for (const int flags : {0x4, -1}) {
|
||||
bool threw = false;
|
||||
try { sceNetResolverAbort(resolver, flags); } catch (const std::runtime_error&) { threw = true; }
|
||||
Require(threw);
|
||||
}
|
||||
Require(sceNetResolverStartNtoa(resolver, "localhost", ipv4.data(), 5000000, 1, 0) == 0);
|
||||
|
||||
const int other = sceNetResolverCreate("guest-sce-net-other", 0, 0);
|
||||
Require(other >= 0 && other != resolver);
|
||||
Require(sceNetResolverAbort(other, 3) == 0);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, "localhost", plain.data(), 5000000, 1, 0) == 0);
|
||||
Require(sceNetResolverDestroy(other) == 0);
|
||||
Require(sceNetResolverAbort(other, 0) == static_cast<int>(0x80410109) && *sceNetErrnoLoc() == 9);
|
||||
Require(sceNetResolverAbort(-1, 1) == static_cast<int>(0x80410109) && *sceNetErrnoLoc() == 9);
|
||||
Require(sceNetResolverGetError(resolver, nullptr) == static_cast<int>(0x80410116) && *sceNetErrnoLoc() == 22);
|
||||
Require(sceNetResolverDestroy(resolver) == 0);
|
||||
resolver_error = -1;
|
||||
|
|
@ -676,6 +748,9 @@ int main() {
|
|||
*sceNetErrnoLoc() == 9 && resolver_error == -1);
|
||||
Require(sceNetResolverStartNtoaMultipleRecordsEx(resolver, "localhost", records.data(), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410109) && *sceNetErrnoLoc() == 9 && records == resolved);
|
||||
Require(sceNetResolverStartNtoaMultipleRecords(resolver, "localhost", plain.data(), 5000000, 1, 0) ==
|
||||
static_cast<int>(0x80410109) && *sceNetErrnoLoc() == 9 && plain == resolved);
|
||||
Require(sceNetResolverAbort(resolver, 1) == static_cast<int>(0x80410109) && *sceNetErrnoLoc() == 9);
|
||||
|
||||
std::array<std::uint8_t, 16> ipv6{};
|
||||
Require(sceNetInetPton(28, "::1", ipv6.data()) == 1);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
- [sceAudioOut2PortCreate](../../../core/libs/prx/libSceAudioOut/src/AudioOut2Port.cpp) (libSceAudioOut) - 12 channels are assumed to be L R C LFE Ls Rs Lb Rb Ltf Rtf Ltb Rtb as in KytyPS5's 12-to-8 fold, and 6 and 8 channels to be its first 6 and 8; no title or SDK header confirms the order
|
||||
- [sceAudioOut2PortCreate](../../../core/libs/prx/libSceAudioOut/src/AudioOut2Port.cpp) (libSceAudioOut) - the stereo fold is assumed, not the console's downmix: C at -3 dB into both sides, Ls/Rs, Lb/Rb and Ltf/Rtf at -3 dB and Ltb/Rtb at -6 dB into their own side, LFE dropped
|
||||
- [sceAudioOut2PortSetAttributes](../../../core/libs/prx/libSceAudioOut/src/AudioOut2Port.cpp) (libSceAudioOut) - each PCM buffer set (attribute 0) is taken as one grain: buffers set between two pushes are queued and played one per grain, at most 16 queued. A grain with no new buffer repeats the last one only when the port has always been given that same buffer (rewritten in place); a port whose buffers move on plays silence instead. Inferred from PPSA12544, whose object port (type 6) is given one grain of a 64-grain ring per set, often two or three between pushes and then none for a few; the console behaviour for several sets per push and for a push without a new buffer is not documented
|
||||
- PPSA23566 imports declared without parameters, signatures unknown: [sceAudioOut2UserGetSupportedAttributes](../../../core/libs/prx/libSceAudioOut/src/AudioOut2System.cpp), [sceConvertKeycodeGetCharacterFromKeyboardData](../../../core/libs/prx/libSceConvertKeycode/Export.cpp), [sce::Json::MemAllocator::notifyError](../../../core/libs/prx/libSceJson2/Export.cpp), [sceNpCommerceDialogOpen2](../../../core/libs/prx/libSceNpCommerce/Export.cpp), [sceNpEntitlementAccessGetPftFlag](../../../core/libs/prx/libSceNpEntitlementAccess/Export.cpp), [sceProprietaryVoiceChatHelper{Initialize,Terminate,SetVoiceChatState,GetVoiceChatUsageState}](../../../core/libs/prx/libSceProprietaryVoiceChatHelperPrx/Export.cpp), [sceVoice{GetResourceInfo,ResetPort,EnableChat,DisableChat}](../../../core/libs/prx/libSceVoice/Export.cpp). Names from the shadPS4 aerolib NID list- PPSA28416 imports declared without parameters, signatures unknown: [sceAudioOut2EnableChat](../../../core/libs/prx/libSceAudioOut/src/AudioOut2System.cpp), imported by its bundled `party-ps5-shipping.prx`. Name from the shadPS4 aerolib NID list
|
||||
|
||||
### Functional
|
||||
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@
|
|||
|
||||
- [sceNetSetsockopt](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) sets `SO_RCVTIMEO` and `SO_SNDTIMEO` as the host socket's timeouts. On Windows a receive or send on a stream socket that times out fails with `ETIMEDOUT`, where FreeBSD returns `EAGAIN` or the partial count: Winsock leaves the connection in an indeterminate state after a timeout and reports no partial count ([SOL_SOCKET options](https://learn.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options)), so FreeBSD's behaviour needs the timeout waited for without the host option. A receive on a datagram socket that times out fails with `EAGAIN`
|
||||
- [sceNetSendmsg and sceNetRecvmsg](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) copy the scatter/gather list through one host buffer and accept only the flags `sceNetSend`/`sceNetRecv` accept. Sending control data throws; a receive never returns control data (`msg_controllen` 0), since no socket option that queues it is supported
|
||||
- [sceNetResolverAbort and sceNetResolverStartNtoaMultipleRecords](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) follow shadPS4 ([net.cpp](https://github.com/shadps4-emu/shadPS4/blob/811bfcd7d17ed8ae975c477d9ff28abc744e1ca8/src/core/libraries/net/net.cpp), [net_resolver.cpp](https://github.com/shadps4-emu/shadPS4/blob/811bfcd7d17ed8ae975c477d9ff28abc744e1ca8/src/core/libraries/net/net_resolver.cpp)); the `(int rid, int flags)` signature of the abort also matches [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/5dfdb4b0b166e83dc9ae275001afb695f12c7174/src/SharpProspero/Interop/Net/Socket.cs). Unverified on hardware. Lookups run synchronously over the host resolver, which cannot be interrupted: an abort while a lookup runs on another thread returns at once, and that lookup fails with `EINTR` without writing its output only when the host call returns; the abort flags are then ignored, as shadPS4 does for a running lookup. With nothing running, abort flag 1 (NTOA preservation) or 2 (ATON preservation) makes the next `sceNetResolverStartNtoa*` or `sceNetResolverStartAton` call on that resolver fail with `EINTR`, reported by `sceNetResolverGetError`, after its arguments are checked. Unlike shadPS4, which ignores them, other abort flag bits throw, and `sceNetResolverStartNtoaMultipleRecords` throws for any flag, including async (1) and 0x10000 (IP address literals disabled), as `sceNetResolverStartNtoaMultipleRecordsEx` does
|
||||
|
|
|
|||
Loading…
Reference in New Issue