fix(libSceNetCtl): read 64-bit interface byte counters on Linux

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bubblegg 2026-10-12 19:25:54 +00:00 committed by Adrià Franch
parent ec07f5a5ec
commit a2e97d25a6
2 changed files with 30 additions and 5 deletions

View File

@ -8,7 +8,6 @@
#include <net/if.h>
#include <netinet/in.h>
#ifdef __linux__
#include <linux/if_link.h>
#include <netpacket/packet.h>
#endif
#endif
@ -16,8 +15,10 @@
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include <fstream>
#include <mutex>
#include <stdexcept>
#include <string>
#ifdef _WIN32
#include <vector>
#endif
@ -83,6 +84,13 @@ static bool HostHasAddress(int family) {
#endif
}
extern "C" std::uint64_t NetCtlReadByteCounter_nid_no_patch(const char* path) {
std::ifstream file(path);
std::uint64_t value = 0;
if (!(file >> value)) throw std::runtime_error(std::string("sceNetCtlGetIfStat: no byte counter in ") + path);
return value;
}
static void HostTraffic(std::uint64_t& sent, std::uint64_t& received) {
sent = 0;
received = 0;
@ -100,11 +108,11 @@ static void HostTraffic(std::uint64_t& sent, std::uint64_t& received) {
ifaddrs* interfaces = nullptr;
if (getifaddrs(&interfaces) != 0) throw std::runtime_error("sceNetCtlGetIfStat: the host interface list is unavailable");
for (auto* item = interfaces; item; item = item->ifa_next) {
if (!item->ifa_addr || item->ifa_addr->sa_family != AF_PACKET || !item->ifa_data) continue;
if (!item->ifa_addr || item->ifa_addr->sa_family != AF_PACKET) continue;
if (!(item->ifa_flags & IFF_UP) || (item->ifa_flags & IFF_LOOPBACK)) continue;
const auto* stats = static_cast<const rtnl_link_stats*>(item->ifa_data);
sent += stats->tx_bytes;
received += stats->rx_bytes;
const std::string statistics = std::string("/sys/class/net/") + item->ifa_name + "/statistics/";
sent += NetCtlReadByteCounter_nid_no_patch((statistics + "tx_bytes").c_str());
received += NetCtlReadByteCounter_nid_no_patch((statistics + "rx_bytes").c_str());
}
freeifaddrs(interfaces);
#else

View File

@ -58,6 +58,7 @@ int APS5_VABI sceNetResolverDestroy(int);
int APS5_VABI sceNetResolverGetError(int, int*);
int APS5_VABI sceNetCtlGetState(int*);
int APS5_VABI sceNetCtlGetIfStat(NetCtlIfStat*);
std::uint64_t NetCtlReadByteCounter_nid_no_patch(const char*);
int APS5_VABI select_nid_postfix(int, void*, void*, void*, const void*);
int APS5_VABI open_nid_postfix(const char*, int, int);
int APS5_VABI close_nid_postfix(int);
@ -766,6 +767,22 @@ int main() {
Require(sceNetCtlGetState(&state) == 0);
Require(state == 0 || state == 3);
Require(sceNetCtlGetIfStat(nullptr) == static_cast<int>(0x80412107));
{
const char* counterPath = "guest_sce_net_byte_counter.txt";
std::FILE* counter = std::fopen(counterPath, "w");
Require(counter != nullptr);
Require(std::fputs("1099511627776", counter) >= 0);
Require(std::fclose(counter) == 0);
Require(NetCtlReadByteCounter_nid_no_patch(counterPath) == 1099511627776ull);
Require(std::remove(counterPath) == 0);
bool missing = false;
try {
NetCtlReadByteCounter_nid_no_patch(counterPath);
} catch (const std::runtime_error&) {
missing = true;
}
Require(missing);
}
NetCtlIfStat first{};
first.device = 7;
first.reserved[7] = 7;