mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge pull request #9386 from mehmetbayoglu/perf/netctl-host-query-cache
perf(libSceNetCtl): reuse host interface queries until Windows reports a change
This commit is contained in:
2 files changed
+90
-2
No files matched your search
@@ -131,7 +131,7 @@ static bool HasIpv4Callback() {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HostHasAddress(int family) {
|
||||
static bool QueryHostHasAddress(int family) {
|
||||
#ifdef _WIN32
|
||||
static const int socket_status = [] {
|
||||
WSADATA data{};
|
||||
@@ -188,6 +188,74 @@ struct HostIpv4Interface {
|
||||
std::vector<in_addr> dns;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace {
|
||||
|
||||
struct HostAddressCache {
|
||||
std::mutex lock;
|
||||
bool registered = false;
|
||||
bool tried = false;
|
||||
std::atomic<std::uint64_t> generation{1};
|
||||
std::uint64_t seen[3]{};
|
||||
bool value[3]{};
|
||||
std::uint64_t interfaceSeen = 0;
|
||||
bool interfaceFound = false;
|
||||
HostIpv4Interface interfaceValue;
|
||||
};
|
||||
|
||||
HostAddressCache& AddressCache() {
|
||||
static HostAddressCache cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
void CALLBACK HostAddressChanged(PVOID, PMIB_UNICASTIPADDRESS_ROW, MIB_NOTIFICATION_TYPE) {
|
||||
AddressCache().generation.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void CALLBACK HostInterfaceChanged(PVOID, PMIB_IPINTERFACE_ROW, MIB_NOTIFICATION_TYPE) {
|
||||
AddressCache().generation.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void CALLBACK HostRouteChanged(PVOID, PMIB_IPFORWARD_ROW2, MIB_NOTIFICATION_TYPE) {
|
||||
AddressCache().generation.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void WatchHostAddresses(HostAddressCache& cache) {
|
||||
if (cache.tried) return;
|
||||
cache.tried = true;
|
||||
HANDLE addresses = nullptr;
|
||||
HANDLE interfaces = nullptr;
|
||||
HANDLE routes = nullptr;
|
||||
cache.registered = NotifyUnicastIpAddressChange(AF_UNSPEC, HostAddressChanged, nullptr, FALSE, &addresses) == NO_ERROR &&
|
||||
NotifyIpInterfaceChange(AF_UNSPEC, HostInterfaceChanged, nullptr, FALSE, &interfaces) == NO_ERROR &&
|
||||
NotifyRouteChange2(AF_UNSPEC, HostRouteChanged, nullptr, FALSE, &routes) == NO_ERROR;
|
||||
if (!cache.registered) {
|
||||
if (addresses != nullptr) CancelMibChangeNotify2(addresses);
|
||||
if (interfaces != nullptr) CancelMibChangeNotify2(interfaces);
|
||||
if (routes != nullptr) CancelMibChangeNotify2(routes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool HostHasAddress(int family) {
|
||||
#ifdef _WIN32
|
||||
auto& cache = AddressCache();
|
||||
const int slot = family == AF_INET ? 0 : family == AF_INET6 ? 1 : 2;
|
||||
std::lock_guard guard(cache.lock);
|
||||
WatchHostAddresses(cache);
|
||||
const auto generation = cache.generation.load(std::memory_order_acquire);
|
||||
if (cache.registered && cache.seen[slot] == generation) return cache.value[slot];
|
||||
const bool value = QueryHostHasAddress(family);
|
||||
cache.value[slot] = value;
|
||||
cache.seen[slot] = generation;
|
||||
return value;
|
||||
#else
|
||||
return QueryHostHasAddress(family);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool UsableIpv4(in_addr address) {
|
||||
const auto host = ntohl(address.s_addr);
|
||||
return host != 0 && (host >> 24) != 127;
|
||||
@@ -310,7 +378,7 @@ static std::vector<in_addr> HostDnsServers() {
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool FindHostIpv4Interface(HostIpv4Interface& found) {
|
||||
static bool QueryHostIpv4Interface(HostIpv4Interface& found) {
|
||||
#ifdef _WIN32
|
||||
ULONG size = 0;
|
||||
const ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_INCLUDE_GATEWAYS;
|
||||
@@ -371,6 +439,25 @@ static bool FindHostIpv4Interface(HostIpv4Interface& found) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool FindHostIpv4Interface(HostIpv4Interface& found) {
|
||||
#ifdef _WIN32
|
||||
auto& cache = AddressCache();
|
||||
std::lock_guard guard(cache.lock);
|
||||
WatchHostAddresses(cache);
|
||||
const auto generation = cache.generation.load(std::memory_order_acquire);
|
||||
if (!cache.registered || cache.interfaceSeen != generation) {
|
||||
HostIpv4Interface value;
|
||||
cache.interfaceFound = QueryHostIpv4Interface(value);
|
||||
cache.interfaceValue = std::move(value);
|
||||
cache.interfaceSeen = generation;
|
||||
}
|
||||
if (cache.interfaceFound) found = cache.interfaceValue;
|
||||
return cache.interfaceFound;
|
||||
#else
|
||||
return QueryHostIpv4Interface(found);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" std::size_t NetCtlHostDnsServers_nid_no_patch(std::uint32_t* servers, std::size_t capacity) {
|
||||
HostIpv4Interface host;
|
||||
if (!FindHostIpv4Interface(host)) return 0;
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
- [libSceNetCtl initialization](../../../core/libs/prx/libSceNetCtl/Export.cpp) (libSceNetCtl) - the library starts initialized, as titles find it: it is the internal sysmodule `0x80000009`, and PPSA11386, PPSA20049, PPSA02530, PPSA14632 and PPSA15878 register and check NetCtl callbacks without importing `sceNetCtlInit`. PPSA11386 executes `int 0x42` at start-up unless `sceNetCtlRegisterCallback` returns 0. So the supplied module's `SCE_NET_CTL_ERROR_NOT_INITIALIZED` answers are unreachable, since Term is a no-op. Whether the console's process start or the module's start sets that state is not measured.
|
||||
- [sceNetCtlGetInfo](../../../core/libs/prx/libSceNetCtl/Export.cpp) (libSceNetCtl) finds the host's default route in `/proc/net/route` on Linux and, on macOS, in the routing table read with `sysctl(NET_RT_FLAGS, RTF_GATEWAY)`, where an interface-scoped default route ranks after the unscoped one
|
||||
- [sceNetCtlGetIfStat](../../../core/libs/prx/libSceNetCtl/Export.cpp) (libSceNetCtl) throws on macOS: an unprivileged process reads the interface byte counters (`getifaddrs` and `sysctl(NET_RT_IFLIST2)` alike) reduced to their low 32 bits, so a total would wrap every 4 GiB
|
||||
- [Host interface cache](../../../core/libs/prx/libSceNetCtl/Export.cpp) (libSceNetCtl) - on Windows, `sceNetCtlGetState`, `sceNetCtlGetStateV6`, `sceNetCtlCheckCallback`, `sceNetCtlGetIfStat` and `sceNetCtlGetInfo` reuse the last host interface query until `NotifyUnicastIpAddressChange`, `NotifyIpInterfaceChange` or `NotifyRouteChange2` reports a change, instead of calling `GetAdaptersAddresses` on every call. A DNS server change with no address, interface or route change is seen only at the next such change. If the notifications cannot be registered, every call queries the host as before.
|
||||
Reference in new issue
Block a user