diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index ed7fc4e5a..652d116bc 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -69,6 +69,7 @@
+
@@ -121,6 +122,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index 9e08e5c9c..8db94748a 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -4,6 +4,7 @@
+
@@ -129,6 +130,7 @@
+
diff --git a/Common/NetworkUtil.cpp b/Common/NetworkUtil.cpp
new file mode 100644
index 000000000..e63170984
--- /dev/null
+++ b/Common/NetworkUtil.cpp
@@ -0,0 +1,136 @@
+/* Copyright (C) 2021 Rainmeter Project Developers
+ *
+ * This Source Code Form is subject to the terms of the GNU General Public
+ * License; either version 2 of the License, or (at your option) any later
+ * version. If a copy of the GPL was not distributed with this file, You can
+ * obtain one at . */
+
+#include "StdAfx.h"
+#include "NetworkUtil.h"
+
+ULONG NetworkUtil::s_InterfaceCount = 0UL;
+MIB_IF_TABLE2* NetworkUtil::s_InterfaceTable = nullptr;
+
+void NetworkUtil::Initialize()
+{
+}
+
+void NetworkUtil::Finalize()
+{
+ DisposeInterfaceTable();
+}
+
+bool NetworkUtil::UpdateInterfaceTable()
+{
+ static ULONGLONG s_LastUpdateTickCount = 0ULL;
+ const ULONGLONG updateInterval = 250ULL; // ms
+
+ ULONGLONG tickCount = GetTickCount64();
+ if (tickCount >= (s_LastUpdateTickCount + updateInterval))
+ {
+ s_LastUpdateTickCount = tickCount;
+
+ DisposeInterfaceTable();
+ if (GetIfTable2(&s_InterfaceTable) == NO_ERROR)
+ {
+ s_InterfaceCount = s_InterfaceTable->NumEntries;
+ return true;
+ }
+ }
+ return false;
+}
+
+ULONG NetworkUtil::FindBestInterface(LPCWSTR interfaceName)
+{
+ if (s_InterfaceTable)
+ {
+ if (_wcsicmp(interfaceName, L"BEST") == 0)
+ {
+ DWORD dwBestIndex = 0;
+ if (NO_ERROR == GetBestInterface(INADDR_ANY, &dwBestIndex))
+ {
+ return (ULONG)dwBestIndex;
+ }
+ }
+ else
+ {
+ for (size_t i = 0; i < s_InterfaceCount; ++i)
+ {
+ MIB_IF_ROW2* table = s_InterfaceTable->Table;
+ if (_wcsicmp(interfaceName, table[i].Description) == 0)
+ {
+ return table[i].InterfaceIndex;
+ }
+ }
+ }
+ }
+ return 0UL;
+}
+
+ULONG NetworkUtil::GetIndexFromIfIndex(const ULONG ifIndex)
+{
+ if (s_InterfaceTable)
+ {
+ for (ULONG i = 0; i < s_InterfaceCount; ++i)
+ {
+ MIB_IF_ROW2* table = s_InterfaceTable->Table;
+ if (ifIndex == table[i].InterfaceIndex)
+ {
+ return i;
+ }
+ }
+ }
+ return 0UL;
+}
+
+LPCWSTR NetworkUtil::GetInterfaceTypeString(const ULONG ifIndex)
+{
+ switch (ifIndex)
+ {
+ case IF_TYPE_ETHERNET_CSMACD: return L"Ethernet";
+ case IF_TYPE_FDDI: return L"Fiber";
+ case IF_TYPE_PPP: return L"PPP";
+ case IF_TYPE_SOFTWARE_LOOPBACK: return L"Loopback";
+ case IF_TYPE_IEEE80211: return L"Wireless";
+ case IF_TYPE_TUNNEL: return L"Tunnel";
+ case IF_TYPE_IEEE1394: return L"Firewire";
+ case IF_TYPE_IEEE80216_WMAN: return L"Mobile WiMax";
+ case IF_TYPE_WWANPP: return L"Mobile GSM";
+ case IF_TYPE_WWANPP2: return L"Mobile CDMA";
+ }
+ return L"Other";
+}
+
+LPCWSTR NetworkUtil::GetInterfaceMediaConnectionString(const NET_IF_MEDIA_CONNECT_STATE state)
+{
+ switch (state)
+ {
+ case MediaConnectStateConnected: return L"Connected";
+ case MediaConnectStateDisconnected: return L"Disconnected";
+ }
+ return L"Unknown";
+}
+
+LPCWSTR NetworkUtil::GetInterfaceOperStatusString(const IF_OPER_STATUS status)
+{
+ switch (status)
+ {
+ case IfOperStatusUp: return L"Up";
+ case IfOperStatusDown: return L"Down";
+ case IfOperStatusTesting: return L"Testing";
+ case IfOperStatusDormant: return L"Dormant";
+ case IfOperStatusNotPresent: return L"Not Present";
+ case IfOperStatusLowerLayerDown: return L"Lower Layer Down";
+ }
+ return L"Unknown";
+}
+
+void NetworkUtil::DisposeInterfaceTable()
+{
+ if (s_InterfaceTable)
+ {
+ FreeMibTable(s_InterfaceTable);
+ s_InterfaceTable = nullptr;
+ }
+ s_InterfaceCount = 0UL;
+}
diff --git a/Common/NetworkUtil.h b/Common/NetworkUtil.h
new file mode 100644
index 000000000..6722fff93
--- /dev/null
+++ b/Common/NetworkUtil.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2021 Rainmeter Project Developers
+ *
+ * This Source Code Form is subject to the terms of the GNU General Public
+ * License; either version 2 of the License, or (at your option) any later
+ * version. If a copy of the GPL was not distributed with this file, You can
+ * obtain one at . */
+
+#ifndef RM_COMMON_NETWORKUTIL_H_
+#define RM_COMMON_NETWORKUTIL_H_
+
+#include
+#include
+#include
+
+class __declspec(novtable) NetworkUtil final
+{
+public:
+ static void Initialize();
+ static void Finalize();
+
+ static bool UpdateInterfaceTable();
+
+ static const ULONG GetInterfaceCount() { return s_InterfaceCount; }
+ static MIB_IF_ROW2* GetInterfaceTable() { if (s_InterfaceTable) { return s_InterfaceTable->Table; } return nullptr; }
+
+ static ULONG FindBestInterface(LPCWSTR interfaceName);
+ static ULONG GetIndexFromIfIndex(const ULONG ifIndex);
+
+ static LPCWSTR GetInterfaceTypeString(const ULONG ifIndex);
+ static LPCWSTR GetInterfaceMediaConnectionString(const NET_IF_MEDIA_CONNECT_STATE state);
+ static LPCWSTR GetInterfaceOperStatusString(const IF_OPER_STATUS status);
+
+private:
+ NetworkUtil() = delete;
+ ~NetworkUtil() = delete;
+
+ NetworkUtil(const NetworkUtil& other) = delete;
+ NetworkUtil& operator=(NetworkUtil other) = delete;
+
+ static void DisposeInterfaceTable();
+
+ static ULONG s_InterfaceCount;
+ static MIB_IF_TABLE2* s_InterfaceTable;
+};
+
+#endif
diff --git a/Library/MeasureNet.cpp b/Library/MeasureNet.cpp
index 0a46f979b..aec2bf21f 100644
--- a/Library/MeasureNet.cpp
+++ b/Library/MeasureNet.cpp
@@ -9,16 +9,15 @@
#include "MeasureNet.h"
#include "Rainmeter.h"
#include "System.h"
+#include "../Common/NetworkUtil.h"
-MIB_IF_TABLE2* MeasureNet::c_Table = nullptr;
-UINT MeasureNet::c_NumOfTables = 0;
std::vector MeasureNet::c_StatValues;
std::vector MeasureNet::c_OldStatValues;
MeasureNet::MeasureNet(Skin* skin, const WCHAR* name, NET type) : Measure(skin, name),
m_Net(type),
- m_Interface(),
- m_Octets(),
+ m_Interface(0U),
+ m_Octets(0Ui64),
m_FirstTime(true),
m_Cumulative(false),
m_UseBits(false)
@@ -35,67 +34,42 @@ MeasureNet::~MeasureNet()
*/
void MeasureNet::UpdateIFTable()
{
- bool logging = false;
+ const ULONG oldCount = NetworkUtil::GetInterfaceCount();
- if (c_Table)
- {
- FreeMibTable(c_Table);
- c_Table = nullptr;
- }
+ if (!NetworkUtil::UpdateInterfaceTable()) return;
- if (GetIfTable2(&c_Table) == NO_ERROR)
+ MIB_IF_ROW2* table = NetworkUtil::GetInterfaceTable();
+ const ULONG newCount = NetworkUtil::GetInterfaceCount();
+ if (table && GetRainmeter().GetDebug() && oldCount != newCount)
{
- if (c_NumOfTables != c_Table->NumEntries)
- {
- c_NumOfTables = c_Table->NumEntries;
- logging = true;
- }
+ LogDebug(L"------------------------------");
+ LogDebugF(L"* NETWORK-INTERFACE: Count=%i", newCount);
- if (GetRainmeter().GetDebug() && logging)
+ for (size_t i = 0; i < newCount; ++i)
{
- LogDebug(L"------------------------------");
- LogDebugF(L"* NETWORK-INTERFACE: Count=%i", c_NumOfTables);
+ LPCWSTR type = NetworkUtil::GetInterfaceTypeString(table[i].Type);
+ LPCWSTR state = NetworkUtil::GetInterfaceMediaConnectionString(table[i].MediaConnectState);
+ LPCWSTR status = NetworkUtil::GetInterfaceOperStatusString(table[i].OperStatus);
- for (size_t i = 0; i < c_NumOfTables; ++i)
- {
- const WCHAR* type = L"Other";
- switch (c_Table->Table[i].Type)
- {
- case IF_TYPE_ETHERNET_CSMACD:
- type = L"Ethernet";
- break;
- case IF_TYPE_PPP:
- type = L"PPP";
- break;
- case IF_TYPE_SOFTWARE_LOOPBACK:
- type = L"Loopback";
- break;
- case IF_TYPE_IEEE80211:
- type = L"IEEE802.11";
- break;
- case IF_TYPE_TUNNEL:
- type = L"Tunnel";
- break;
- case IF_TYPE_IEEE1394:
- type = L"IEEE1394";
- break;
- }
+ LogDebugF(L"%3i: Name: %s", (int)i + 1, table[i].Description);
+ LogDebugF(L" Alias: %s", table[i].Alias);
- LogDebugF(L"%i: %s", (int)i + 1, c_Table->Table[i].Description);
- LogDebugF(L" Alias: %s", c_Table->Table[i].Alias);
- LogDebugF(L" Type=%s(%i), Hardware=%s, Filter=%s",
- type, c_Table->Table[i].Type,
- (c_Table->Table[i].InterfaceAndOperStatusFlags.HardwareInterface == 1) ? L"Yes" : L"No",
- (c_Table->Table[i].InterfaceAndOperStatusFlags.FilterInterface == 1) ? L"Yes" : L"No");
+ WCHAR guid[64] = { 0 };
+ if (StringFromGUID2(table[i].InterfaceGuid, guid, 64) > 0)
+ {
+ LogDebugF(L" GUID: %s", guid);
}
- LogDebug(L"------------------------------");
+
+ LogDebugF(L" Type=%s(%i), Hardware=%s, Filter=%s",
+ type, table[i].Type,
+ (table[i].InterfaceAndOperStatusFlags.HardwareInterface == 1) ? L"Yes" : L"No",
+ (table[i].InterfaceAndOperStatusFlags.FilterInterface == 1) ? L"Yes" : L"No");
+ LogDebugF(L" IfIndex=%i, State=%s, Status=%s(%i)",
+ table[i].InterfaceIndex,
+ state,
+ status, table[i].OperStatus);
}
- }
- else
- {
- // Something's wrong. Unable to get the table.
- c_Table = nullptr;
- c_NumOfTables = 0;
+ LogDebug(L"------------------------------");
}
}
@@ -107,11 +81,14 @@ void MeasureNet::UpdateIFTable()
ULONG64 MeasureNet::GetNetOctets(NET net)
{
ULONG64 value = 0;
- MIB_IF_ROW2* table = (MIB_IF_ROW2*)c_Table->Table;
+ MIB_IF_ROW2* table = NetworkUtil::GetInterfaceTable();
+ if (!table) return value;
+
+ const ULONG interfaceCount = NetworkUtil::GetInterfaceCount();
if (m_Interface == 0)
{
// Get all interfaces
- for (UINT i = 0; i < c_NumOfTables; ++i)
+ for (UINT i = 0; i < interfaceCount; ++i)
{
// Ignore the loopback and filter interfaces
if (table[i].Type == IF_TYPE_SOFTWARE_LOOPBACK ||
@@ -136,22 +113,22 @@ ULONG64 MeasureNet::GetNetOctets(NET net)
}
else
{
- // Get the selected interface
- if (m_Interface <= c_NumOfTables)
+ if (m_Interface <= interfaceCount)
{
+ ULONG index = NetworkUtil::GetIndexFromIfIndex(m_Interface);
switch (net)
{
case NET_IN:
- value += table[m_Interface - 1].InOctets;
+ value += table[index].InOctets;
break;
case NET_OUT:
- value += table[m_Interface - 1].OutOctets;
+ value += table[index].OutOctets;
break;
case NET_TOTAL:
- value += table[m_Interface - 1].InOctets;
- value += table[m_Interface - 1].OutOctets;
+ value += table[index].InOctets;
+ value += table[index].OutOctets;
break;
}
}
@@ -169,16 +146,20 @@ ULONG64 MeasureNet::GetNetStatsValue(NET net)
ULONG64 value = 0;
size_t statsSize = c_StatValues.size() / 2;
+ MIB_IF_ROW2* table = NetworkUtil::GetInterfaceTable();
+ if (!table) return value;
+
+ const ULONG interfaceCount = NetworkUtil::GetInterfaceCount();
if (m_Interface == 0)
{
// Get all interfaces
for (size_t i = 0; i < statsSize; ++i)
{
// Ignore the loopback and filter interfaces
- if (c_NumOfTables == statsSize)
+ if (interfaceCount == statsSize)
{
- if (c_Table->Table[i].Type == IF_TYPE_SOFTWARE_LOOPBACK ||
- c_Table->Table[i].InterfaceAndOperStatusFlags.FilterInterface == 1) continue;
+ if (table[i].Type == IF_TYPE_SOFTWARE_LOOPBACK ||
+ table[i].InterfaceAndOperStatusFlags.FilterInterface == 1) continue;
}
switch (net)
@@ -203,19 +184,20 @@ ULONG64 MeasureNet::GetNetStatsValue(NET net)
// Get the selected interface
if (m_Interface <= statsSize)
{
+ ULONG index = NetworkUtil::GetIndexFromIfIndex(m_Interface);
switch (net)
{
case NET_IN:
- value += c_StatValues[(m_Interface - 1) * 2 + 0];
+ value += c_StatValues[index * 2 + 0];
break;
case NET_OUT:
- value += c_StatValues[(m_Interface - 1) * 2 + 1];
+ value += c_StatValues[index * 2 + 1];
break;
case NET_TOTAL:
- value += c_StatValues[(m_Interface - 1) * 2 + 0];
- value += c_StatValues[(m_Interface - 1) * 2 + 1];
+ value += c_StatValues[index * 2 + 0];
+ value += c_StatValues[index * 2 + 1];
break;
}
}
@@ -226,9 +208,9 @@ ULONG64 MeasureNet::GetNetStatsValue(NET net)
void MeasureNet::UpdateValue()
{
- if (c_Table == nullptr) return;
+ if (!NetworkUtil::GetInterfaceTable()) return;
- const ULONG64 bits = m_UseBits ? 8Ui64 : 1Ui64;
+ const ULONG64 bits = m_UseBits ? 8ULL : 1ULL;
if (m_Cumulative)
{
@@ -302,11 +284,23 @@ void MeasureNet::ReadOptions(ConfigParser& parser, const WCHAR* section)
std::wstring iface = parser.ReadString(section, L"Interface", L"");
if (!iface.empty() && !std::all_of(iface.begin(), iface.end(), iswdigit))
{
- m_Interface = GetBestInterfaceOrByName(iface.c_str());
+ m_Interface = NetworkUtil::FindBestInterface(iface.c_str());
+ if (GetRainmeter().GetDebug())
+ {
+ MIB_IF_ROW2* table = NetworkUtil::GetInterfaceTable();
+ for (size_t i = 0; i < NetworkUtil::GetInterfaceCount(); ++i)
+ {
+ if (table[i].InterfaceIndex == m_Interface)
+ {
+ LogDebugF(this, L"Using network interface: %s (IfIndex=%i)", table[i].Description, m_Interface);
+ break;
+ }
+ }
+ }
}
else
{
- m_Interface = parser.ReadInt(section, L"Interface", 0);
+ m_Interface = parser.ReadUInt(section, L"Interface", 0U);
}
m_Cumulative = parser.ReadBool(section, L"Cumulative", false);
@@ -333,86 +327,47 @@ void MeasureNet::ReadOptions(ConfigParser& parser, const WCHAR* section)
}
}
-UINT MeasureNet::GetBestInterfaceOrByName(const WCHAR* iface)
+void MeasureNet::UpdateStats()
{
- if (c_Table == nullptr) return 0;
+ MIB_IF_ROW2* table = NetworkUtil::GetInterfaceTable();
+ if (!table) return;
- if (_wcsicmp(iface, L"BEST") == 0)
- {
- DWORD dwBestIndex;
- if (NO_ERROR == GetBestInterface(INADDR_ANY, &dwBestIndex))
- {
- MIB_IF_ROW2* table = (MIB_IF_ROW2*)c_Table->Table;
- for (size_t i = 0; i < c_NumOfTables; ++i)
- {
- if (table[i].InterfaceIndex == (NET_IFINDEX)dwBestIndex)
- {
- if (GetRainmeter().GetDebug())
- {
- LogDebugF(this, L"Using network interface: Number=(%i), Name=\"%s\"", i + 1, table[i].Description);
- }
+ const ULONG interfaceCount = NetworkUtil::GetInterfaceCount();
+ size_t statsSize = interfaceCount * 2;
- return (UINT)(i + 1);
- }
- }
- }
- }
- else
+ // Fill the vectors
+ if (c_StatValues.size() < statsSize)
{
- MIB_IF_ROW2* table = (MIB_IF_ROW2*)c_Table->Table;
- for (size_t i = 0; i < c_NumOfTables; ++i)
- {
- if (_wcsicmp(iface, table[i].Description) == 0)
- {
- return (UINT)(i + 1);
- }
- }
+ c_StatValues.resize(statsSize, 0);
}
- LogErrorF(this, L"Cannot find interface: \"%s\"", iface);
- return 0;
-}
-
-void MeasureNet::UpdateStats()
-{
- if (c_Table)
+ if (c_OldStatValues.size() < statsSize)
{
- size_t statsSize = c_NumOfTables * 2;
-
- // Fill the vectors
- if (c_StatValues.size() < statsSize)
- {
- c_StatValues.resize(statsSize, 0);
- }
-
- if (c_OldStatValues.size() < statsSize)
- {
- c_OldStatValues.resize(statsSize, 0);
- }
+ c_OldStatValues.resize(statsSize, 0);
+ }
- for (UINT i = 0; i < c_NumOfTables; ++i)
+ for (size_t i = 0; i < interfaceCount; ++i)
+ {
+ ULONG64 in = table[i].InOctets;
+ ULONG64 out = table[i].OutOctets;
+ if (c_OldStatValues[i * 2 + 0] != 0)
{
- ULONG64 in = c_Table->Table[i].InOctets;
- ULONG64 out = c_Table->Table[i].OutOctets;
- if (c_OldStatValues[i * 2 + 0] != 0)
+ if (in > c_OldStatValues[i * 2 + 0])
{
- if (in > c_OldStatValues[i * 2 + 0])
- {
- c_StatValues[i * 2 + 0] += in - c_OldStatValues[i * 2 + 0];
- }
+ c_StatValues[i * 2 + 0] += in - c_OldStatValues[i * 2 + 0];
}
+ }
- if (c_OldStatValues[i * 2 + 1] != 0)
+ if (c_OldStatValues[i * 2 + 1] != 0)
+ {
+ if (out > c_OldStatValues[i * 2 + 1])
{
- if (out > c_OldStatValues[i * 2 + 1])
- {
- c_StatValues[i * 2 + 1] += out - c_OldStatValues[i * 2 + 1];
- }
+ c_StatValues[i * 2 + 1] += out - c_OldStatValues[i * 2 + 1];
}
-
- c_OldStatValues[i * 2 + 0] = in;
- c_OldStatValues[i * 2 + 1] = out;
}
+
+ c_OldStatValues[i * 2 + 0] = in;
+ c_OldStatValues[i * 2 + 1] = out;
}
}
@@ -529,10 +484,5 @@ void MeasureNet::InitializeStatic()
void MeasureNet::FinalizeStatic()
{
- if (c_Table)
- {
- FreeMibTable(c_Table);
- }
- c_Table = nullptr;
- c_NumOfTables = 0;
+ NetworkUtil::Finalize();
}
diff --git a/Library/MeasureNet.h b/Library/MeasureNet.h
index b648bf9d5..a5078dd15 100644
--- a/Library/MeasureNet.h
+++ b/Library/MeasureNet.h
@@ -48,10 +48,9 @@ class MeasureNet : public Measure
private:
ULONG64 GetNetOctets(NET net);
ULONG64 GetNetStatsValue(NET net);
- UINT GetBestInterfaceOrByName(const WCHAR* iface);
NET m_Net;
- UINT m_Interface;
+ ULONG m_Interface;
ULONG64 m_Octets;
bool m_FirstTime;
@@ -60,8 +59,6 @@ class MeasureNet : public Measure
static std::vector c_OldStatValues;
static std::vector c_StatValues;
- static MIB_IF_TABLE2* c_Table;
- static UINT c_NumOfTables;
};
#endif