Files
ports/sysutils/plasma6-ksystemstats/files/patch-network
T
Max Brazhnikov b6754dfb14 sysutils/plasma6-ksystemstats: Fix memory leak
PR:		295310
Submitted by:	avg
2026-06-09 15:06:17 +03:00

244 lines
7.9 KiB
Plaintext

--- plugins/network/CMakeLists.txt
+++ plugins/network/CMakeLists.txt
@@ -21,6 +21,11 @@ target_link_libraries(ksystemstats_plugin_network PRIVATE Qt::Core Qt::Gui Qt::D
if (KF6NetworkManagerQt_FOUND)
target_link_libraries(ksystemstats_plugin_network PRIVATE KF6::NetworkManagerQt)
endif()
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+ target_sources(ksystemstats_plugin_network PRIVATE SysctlBackend.cpp)
+endif()
+
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
target_sources(ksystemstats_plugin_network PRIVATE RtNetlinkBackend.cpp)
target_link_libraries(ksystemstats_plugin_network PRIVATE ${NL_LIBRARIES} Qt::Network)
--- plugins/network/NetworkPlugin.cpp
+++ plugins/network/NetworkPlugin.cpp
@@ -24,7 +24,9 @@
#ifdef Q_OS_LINUX
#include "RtNetlinkBackend.h"
#endif
-
+#ifdef Q_OS_FREEBSD
+#include "SysctlBackend.h"
+#endif
class NetworkPrivate
{
public:
@@ -52,6 +54,9 @@ NetworkPlugin::NetworkPlugin(QObject *parent, const QVariantList &args)
#endif
#ifdef Q_OS_LINUX
backendFunctions.emplace_back([](NetworkPlugin *parent) -> NetworkBackend* {return new RtNetlinkBackend(parent);});
+#endif
+#ifdef Q_OS_FREEBSD
+ backendFunctions.emplace_back([](NetworkPlugin *parent) -> NetworkBackend* {return new SysctlBackend(parent);});
#endif
for (auto func : backendFunctions) {
auto backend = func(this);
--- /dev/null
+++ plugins/network/SysctlBackend.cpp
@@ -0,0 +1,158 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Jesper Schmitz Mouridsen <jesper@schmitz.computer>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+ */
+
+#include "SysctlBackend.h"
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <systemstats/SysFsSensor.h>
+
+SysctlNetDevice::SysctlNetDevice(const QString &id, const QString &name, int ifnumber)
+ : NetworkDevice(id, name)
+{
+ m_sysctlName = {CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, ifnumber, IFDATA_GENERAL};
+ // Even though we have no sensor, we need to have a name for the grouped text on the front page
+ // of plasma-systemmonitor
+ m_networkSensor->setValue(id);
+ std::array<KSysGuard::SensorProperty *, 6> statisticSensors =
+ {m_downloadSensor, m_downloadBitsSensor, m_totalDownloadSensor, m_uploadSensor, m_uploadBitsSensor, m_totalUploadSensor};
+ auto resetStatistics = [this, statisticSensors]() {
+ if (std::none_of(statisticSensors.begin(), statisticSensors.end(), [](auto property) {
+ return property->isSubscribed();
+ })) {
+ m_totalDownloadSensor->setValue(0);
+ m_totalUploadSensor->setValue(0);
+ m_statisticsTimer->stop();
+ } else if (!m_statisticsTimer->isActive()) {
+ m_statisticsTimer->start();
+ }
+ };
+ for (auto property : statisticSensors) {
+ connect(property, &KSysGuard::SensorProperty::subscribedChanged, this, resetStatistics);
+ }
+ m_statisticsTimer = std::make_unique<QTimer>();
+ m_statisticsTimer->setInterval(UpdateRate);
+ connect(m_statisticsTimer.get(), &QTimer::timeout, this, [this]() {
+ ifmibdata ifmd{};
+ size_t len = sizeof(ifmd);
+ if (sysctl(m_sysctlName.data(), 6, &ifmd, &len, NULL, 0) == 0) {
+ const qulonglong newDownload = ifmd.ifmd_data.ifi_ibytes;
+ const qulonglong previousDownload = m_totalDownloadSensor->value().toULongLong();
+ const qulonglong deltaDownload = newDownload - previousDownload;
+ if (previousDownload > 0) {
+ m_downloadSensor->setValue(deltaDownload * 1000 / UpdateRate);
+ m_downloadBitsSensor->setValue((deltaDownload * 1000 / UpdateRate) * 8);
+ }
+ m_totalDownloadSensor->setValue(newDownload);
+
+ const qulonglong newUpload = ifmd.ifmd_data.ifi_obytes;
+ const qulonglong previousUpload = m_totalUploadSensor->value().toULongLong();
+ const qulonglong deltaUpload = newUpload - previousUpload;
+ if (previousUpload > 0) {
+ m_uploadSensor->setValue(deltaUpload * 1000 / UpdateRate);
+ m_uploadBitsSensor->setValue((deltaUpload * 1000 / UpdateRate) * 8);
+ }
+ m_totalUploadSensor->setValue(newUpload);
+ }
+ });
+}
+void SysctlNetDevice::update()
+{
+ char addr_buf[NI_MAXHOST];
+ QStringList ipv4_addrs;
+ QStringList ipv6_addrs;
+ ifaddrs *ifap0 = nullptr;
+ ifaddrs *ifap;
+ struct sockaddr_in *sin;
+
+ getifaddrs(&ifap0);
+ for (ifap = ifap0; ifap != nullptr; ifap = ifap->ifa_next) {
+ if (name() == QString::fromLatin1(ifap->ifa_name)) {
+ sin = reinterpret_cast<struct sockaddr_in *>(ifap->ifa_addr);
+ if (sin == nullptr)
+ return;
+
+ if (getnameinfo(ifap->ifa_addr, sin->sin_len, addr_buf, sizeof(addr_buf),
+ NULL, 0, NI_NUMERICHOST) == 0) {
+ if (sin->sin_family == AF_INET) {
+ ipv4_addrs << QString::fromLatin1(addr_buf);
+ }
+ if (sin->sin_family == AF_INET6) {
+ ipv6_addrs << QString::fromLatin1(addr_buf);
+ }
+ }
+ }
+ }
+ m_ipv4Sensor->setValue(ipv4_addrs.join("\n"));
+ m_ipv6Sensor->setValue(ipv6_addrs.join("\n"));
+ freeifaddrs(ifap0);
+}
+
+SysctlNetDevice::~SysctlNetDevice()
+{
+}
+SysctlBackend::SysctlBackend(QObject *parent)
+ : NetworkBackend(parent)
+{
+}
+
+SysctlBackend::~SysctlBackend()
+{
+ qDeleteAll(m_devices);
+}
+
+bool SysctlBackend::isSupported()
+{
+ return true;
+}
+
+void SysctlBackend::start()
+{
+ int count, i;
+ size_t len;
+ int ifcnt_name[] = {CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT};
+ len = sizeof(int);
+ if (sysctl(ifcnt_name, 5, &count, &len, NULL, 0) < 0) {
+ return;
+ }
+
+ for (i = 1; i <= count; i++) {
+ struct ifmibdata ifmd {
+ };
+ size_t len = sizeof(ifmd);
+ int sname[6] = {CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL};
+
+ if (sysctl(sname, 6, &ifmd, &len, NULL, 0) < 0) {
+ continue;
+ }
+
+ if ((ifmd.ifmd_data.ifi_type == IFT_ETHER) || (ifmd.ifmd_data.ifi_type == IFT_IEEE80211)) {
+ auto device = new SysctlNetDevice(QString::fromLatin1(ifmd.ifmd_name), QString::fromLatin1(ifmd.ifmd_name), i);
+
+ m_devices.insert(QByteArray(ifmd.ifmd_name), device);
+ Q_EMIT deviceAdded(device);
+ }
+ }
+}
+
+void SysctlBackend::stop()
+{
+}
+
+void SysctlBackend::update()
+{
+ QHashIterator<QByteArray, SysctlNetDevice *> iter(m_devices);
+ while (iter.hasNext()) {
+ iter.next();
+ iter.value()->update();
+ }
+}
--- /dev/null
+++ plugins/network/SysctlBackend.h
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Jesper Schmitz Mouridsen <jesper@schmitz.computer>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+ */
+
+#pragma once
+
+#include "NetworkBackend.h"
+#include "NetworkDevice.h"
+#include <array>
+#include <QElapsedTimer>
+#include <QTimer>
+
+static const int UpdateRate = 500;
+class SysctlNetDevice : public NetworkDevice
+{
+ Q_OBJECT
+
+public:
+ SysctlNetDevice(const QString &id, const QString &name,int ifnumber);
+ ~SysctlNetDevice() override;
+ std::array<int,6> m_sysctlName;
+ void update();
+ bool isConnected() const;
+ std::unique_ptr<QTimer> m_statisticsTimer;
+ QList<struct sockaddr *> m_ifaddrs;
+};
+
+class SysctlBackend : public NetworkBackend
+{
+public:
+ SysctlBackend(QObject *parent);
+ ~SysctlBackend() override;
+ bool isSupported() override;
+ void start() override;
+ void stop() override;
+ void update() override;
+
+private:
+ QHash<QByteArray, SysctlNetDevice *> m_devices;
+};