diff --git a/Library/MeasureNet.cpp b/Library/MeasureNet.cpp index 8a89cc2d..37679669 100644 --- a/Library/MeasureNet.cpp +++ b/Library/MeasureNet.cpp @@ -21,14 +21,18 @@ #include "Rainmeter.h" #include "System.h" -BYTE* CMeasureNet::c_Table = NULL; -UINT CMeasureNet::c_NumOfTables = 0; std::vector CMeasureNet::c_StatValues; std::vector CMeasureNet::c_OldStatValues; - -FPGETIFTABLE2EX CMeasureNet::c_GetIfTable2Ex = NULL; -FPFREEMIBTABLE CMeasureNet::c_FreeMibTable = NULL; -bool CMeasureNet::c_UseNewApi = false; +BYTE* CMeasureNet::c_Table = NULL; +ULONG CMeasureNet::c_Size = 0; +UINT CMeasureNet::c_NumOfTables = 0; +BYTE* CMeasureNet::c_AATable = NULL; +ULONG CMeasureNet::c_AASize = 0; +bool CMeasureNet::c_IpInterfaceChanged = true; +HANDLE CMeasureNet::c_NotificationHandle = NULL; +FPGETIFENTRY2 CMeasureNet::c_GetIfEntry2 = NULL; +FPNOTIFYIPINTERFACECHANGE CMeasureNet::c_NotifyIpInterfaceChange = NULL; +FPCANCELMIBCHANGENOTIFY2 CMeasureNet::c_CancelMibChangeNotify2 = NULL; extern CRainmeter* Rainmeter; @@ -83,6 +87,18 @@ bool CMeasureNet::Update() return PostUpdate(); } +/* +** IpInterfaceChangeCallback +** +*/ +VOID NETIOAPI_API_ CMeasureNet::IpInterfaceChangeCallback(PVOID CallerContext, PMIB_IPINTERFACE_ROW Row, MIB_NOTIFICATION_TYPE NotificationType) +{ + if (NotificationType == MibAddInstance || NotificationType == MibDeleteInstance) + { + c_IpInterfaceChanged = true; + } +} + /* ** UpdateIFTable ** @@ -91,133 +107,59 @@ bool CMeasureNet::Update() */ void CMeasureNet::UpdateIFTable() { - bool logging = false; - - if (c_UseNewApi) + if (c_IpInterfaceChanged || c_NotificationHandle == NULL || c_AATable == NULL) { - if (c_Table) + // Gotta reserve few bytes for the tables + ULONG flags = GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST; + + ULONG ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, (PIP_ADAPTER_ADDRESSES)c_AATable, &c_AASize); + if (ret == ERROR_BUFFER_OVERFLOW) { - c_FreeMibTable(c_Table); - c_Table = NULL; + delete [] c_AATable; + c_AATable = new BYTE[c_AASize]; + + ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, (PIP_ADAPTER_ADDRESSES)c_AATable, &c_AASize); } - if (c_GetIfTable2Ex(MibIfTableNormal, (MIB_IF_TABLE2**)&c_Table) == NO_ERROR) + if (ret == ERROR_SUCCESS) { - MIB_IF_TABLE2* ifTable = (MIB_IF_TABLE2*)c_Table; - - if (c_NumOfTables != ifTable->NumEntries) + UINT numOfTables = 0; + for (PIP_ADAPTER_ADDRESSES addrPtr = (PIP_ADAPTER_ADDRESSES)c_AATable; addrPtr != NULL; addrPtr = addrPtr->Next) { - c_NumOfTables = ifTable->NumEntries; - logging = true; + ++numOfTables; } - if (CRainmeter::GetDebug() && logging) + if (c_NumOfTables != numOfTables) { - Log(LOG_DEBUG, L"------------------------------"); - LogWithArgs(LOG_DEBUG, L"* NETWORK-INTERFACE: Count=%i", c_NumOfTables); - - for (size_t i = 0; i < c_NumOfTables; ++i) - { - std::wstring type; - switch (ifTable->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; - default: - type += L"Other"; - break; - } - - LogWithArgs(LOG_DEBUG, L"%i: %s", (int)i + 1, ifTable->Table[i].Description); - LogWithArgs(LOG_DEBUG, L" Alias: %s", ifTable->Table[i].Alias); - LogWithArgs(LOG_DEBUG, L" Type=%s(%i), Hardware=%s, Filter=%s", - type.c_str(), ifTable->Table[i].Type, - (ifTable->Table[i].InterfaceAndOperStatusFlags.HardwareInterface == 1) ? L"Yes" : L"No", - (ifTable->Table[i].InterfaceAndOperStatusFlags.FilterInterface == 1) ? L"Yes" : L"No"); - } - Log(LOG_DEBUG, L"------------------------------"); - } - } - else - { - // Something's wrong. Unable to get the table. - c_Table = NULL; - c_NumOfTables = 0; - } - } - else - { - if (c_Table == NULL) - { - // Gotta reserve few bytes for the tables - DWORD value = 0; - if (GetNumberOfInterfaces(&value) == NO_ERROR) - { - if (c_NumOfTables != value) - { - c_NumOfTables = value; - logging = true; - } + c_NumOfTables = numOfTables; + delete [] c_Table; if (c_NumOfTables > 0) { - DWORD size = sizeof(MIB_IFTABLE) + sizeof(MIB_IFROW) * c_NumOfTables; - c_Table = new BYTE[size]; + c_Size = ((c_GetIfEntry2) ? sizeof(MIB_IF_ROW2) : sizeof(MIB_IFROW)) * c_NumOfTables; + c_Table = new BYTE[c_Size]; } - } - } - - if (c_Table) - { - DWORD ret, size = 0; - - MIB_IFTABLE* ifTable = (MIB_IFTABLE*)c_Table; - - if ((ret = GetIfTable(ifTable, &size, FALSE)) == ERROR_INSUFFICIENT_BUFFER) - { - delete [] c_Table; - c_Table = new BYTE[size]; - - ifTable = (MIB_IFTABLE*)c_Table; - - ret = GetIfTable(ifTable, &size, FALSE); - } - - if (ret == NO_ERROR) - { - if (c_NumOfTables != ifTable->dwNumEntries) + else { - c_NumOfTables = ifTable->dwNumEntries; - logging = true; + c_Table = NULL; + c_Size = 0; } - if (CRainmeter::GetDebug() && logging) - { - Log(LOG_DEBUG, L"------------------------------"); - LogWithArgs(LOG_DEBUG, L"* NETWORK-INTERFACE: Count=%i", c_NumOfTables); + c_IpInterfaceChanged = true; + } - for (size_t i = 0; i < c_NumOfTables; ++i) + if (c_IpInterfaceChanged && CRainmeter::GetDebug()) + { + Log(LOG_DEBUG, L"------------------------------"); + LogWithArgs(LOG_DEBUG, L"* NETWORK-INTERFACE: %s", (c_GetIfEntry2) ? L"GetIfEntry2" : L"GetIfEntry"); + + if (c_Table) + { + int i = 0; + for (PIP_ADAPTER_ADDRESSES addrPtr = (PIP_ADAPTER_ADDRESSES)c_AATable; addrPtr != NULL; addrPtr = addrPtr->Next) { - std::string desc((char*)ifTable->table[i].bDescr, ifTable->table[i].dwDescrLen); - std::wstring type; - switch (ifTable->table[i].dwType) + switch (addrPtr->IfType) { case IF_TYPE_ETHERNET_CSMACD: type += L"Ethernet"; @@ -242,19 +184,76 @@ void CMeasureNet::UpdateIFTable() break; } - LogWithArgs(LOG_DEBUG, L"%i: %s", (int)i + 1, ConvertToWide(desc.c_str()).c_str()); - LogWithArgs(LOG_DEBUG, L" Type=%s(%i)", - type.c_str(), ifTable->table[i].dwType); + std::wstring oper; + switch (addrPtr->OperStatus) + { + case IfOperStatusUp: + oper += L"Up"; + break; + case IfOperStatusDown: + oper += L"Down"; + break; + case IfOperStatusTesting: + oper += L"Testing"; + break; + case IfOperStatusUnknown: + oper += L"Unknown"; + break; + case IfOperStatusDormant: + oper += L"Dormant"; + break; + case IfOperStatusNotPresent: + oper += L"NotPresent"; + break; + case IfOperStatusLowerLayerDown: + oper += L"LowerLayerDown"; + break; + } + + LogWithArgs(LOG_DEBUG, L"%i: %s", ++i, addrPtr->Description); + LogWithArgs(LOG_DEBUG, L" IfIndex=%u, LUID=%llu, AdapterName=%s", addrPtr->IfIndex, addrPtr->Luid.Value, ConvertToWide(addrPtr->AdapterName).c_str()); + LogWithArgs(LOG_DEBUG, L" Type=%s (%i), Oper=%s (%i)", type.c_str(), addrPtr->IfType, oper.c_str(), addrPtr->OperStatus); } - Log(LOG_DEBUG, L"------------------------------"); } + else + { + Log(LOG_DEBUG, L"None."); + } + + Log(LOG_DEBUG, L"------------------------------"); } - else + } + else + { + // Something's wrong. Unable to get the table. + DisposeBuffer(); + } + + c_IpInterfaceChanged = false; + } + + if (c_AATable && c_Table) + { + memset(c_Table, 0, c_Size); + + if (c_GetIfEntry2) + { + PMIB_IF_ROW2 ifRowPtr = (PMIB_IF_ROW2)c_Table; + for (PIP_ADAPTER_ADDRESSES addrPtr = (PIP_ADAPTER_ADDRESSES)c_AATable; addrPtr != NULL; addrPtr = addrPtr->Next) { - // Something's wrong. Unable to get the table. - delete [] c_Table; - c_Table = NULL; - c_NumOfTables = 0; + (*ifRowPtr).InterfaceIndex = addrPtr->IfIndex; + c_GetIfEntry2(ifRowPtr); + ++ifRowPtr; + } + } + else + { + PMIB_IFROW ifRowPtr = (PMIB_IFROW)c_Table; + for (PIP_ADAPTER_ADDRESSES addrPtr = (PIP_ADAPTER_ADDRESSES)c_AATable; addrPtr != NULL; addrPtr = addrPtr->Next) + { + (*ifRowPtr).dwIndex = addrPtr->IfIndex; + GetIfEntry(ifRowPtr); + ++ifRowPtr; } } } @@ -271,18 +270,17 @@ ULONG64 CMeasureNet::GetNetOctets(NET net) { ULONG64 value = 0; - if (c_UseNewApi) + if (c_GetIfEntry2) { - MIB_IF_ROW2* table = (MIB_IF_ROW2*)((MIB_IF_TABLE2*)c_Table)->Table; + PMIB_IF_ROW2 table = (PMIB_IF_ROW2)c_Table; if (m_Interface == 0) { // Get all interfaces for (UINT i = 0; i < c_NumOfTables; ++i) { - // Ignore the loopback and filter interfaces - if (table[i].Type == IF_TYPE_SOFTWARE_LOOPBACK || - table[i].InterfaceAndOperStatusFlags.FilterInterface == 1) continue; + // Ignore the loopback interface + if (table[i].Type == IF_TYPE_SOFTWARE_LOOPBACK) continue; switch (net) { @@ -326,14 +324,14 @@ ULONG64 CMeasureNet::GetNetOctets(NET net) } else { - MIB_IFROW* table = (MIB_IFROW*)((MIB_IFTABLE*)c_Table)->table; + PMIB_IFROW table = (PMIB_IFROW)c_Table; if (m_Interface == 0) { // Get all interfaces for (UINT i = 0; i < c_NumOfTables; ++i) { - // Ignore the loopback + // Ignore the loopback interface if (table[i].dwType == IF_TYPE_SOFTWARE_LOOPBACK) continue; switch (net) @@ -396,17 +394,16 @@ ULONG64 CMeasureNet::GetNetStatsValue(NET net) // Get all interfaces for (size_t i = 0; i < statsSize; ++i) { - // Ignore the loopback and filter interfaces + // Ignore the loopback interface if (c_NumOfTables == statsSize) { - if (c_UseNewApi) + if (c_GetIfEntry2) { - if (((MIB_IF_TABLE2*)c_Table)->Table[i].Type == IF_TYPE_SOFTWARE_LOOPBACK || - ((MIB_IF_TABLE2*)c_Table)->Table[i].InterfaceAndOperStatusFlags.FilterInterface == 1) continue; + if (((PMIB_IF_ROW2)c_Table)[i].Type == IF_TYPE_SOFTWARE_LOOPBACK) continue; } else { - if (((MIB_IFTABLE*)c_Table)->table[i].dwType == IF_TYPE_SOFTWARE_LOOPBACK) continue; + if (((PMIB_IFROW)c_Table)[i].dwType == IF_TYPE_SOFTWARE_LOOPBACK) continue; } } @@ -535,15 +532,15 @@ void CMeasureNet::UpdateStats() { ULONG64 in, out; - if (c_UseNewApi) + if (c_GetIfEntry2) { - in = (DWORD)((MIB_IF_TABLE2*)c_Table)->Table[i].InOctets; - out = (DWORD)((MIB_IF_TABLE2*)c_Table)->Table[i].OutOctets; + in = ((PMIB_IF_ROW2)c_Table)[i].InOctets; + out = ((PMIB_IF_ROW2)c_Table)[i].OutOctets; } else { - in = ((MIB_IFTABLE*)c_Table)->table[i].dwInOctets; - out = ((MIB_IFTABLE*)c_Table)->table[i].dwOutOctets; + in = ((PMIB_IFROW)c_Table)[i].dwInOctets; + out = ((PMIB_IFROW)c_Table)[i].dwOutOctets; } if (c_OldStatValues[i * 2 + 0] != 0 && c_OldStatValues[i * 2 + 1] != 0) @@ -664,21 +661,30 @@ void CMeasureNet::WriteStats(const WCHAR* iniFile) */ void CMeasureNet::InitializeNewApi() { - if (CSystem::GetOSPlatform() >= OSPLATFORM_VISTA) + HMODULE IpHlpApi = GetModuleHandle(L"IpHlpApi"); + c_GetIfEntry2 = (FPGETIFENTRY2)GetProcAddress(IpHlpApi, "GetIfEntry2"); + + if (c_GetIfEntry2) { - HMODULE IpHlpApiLibrary = GetModuleHandle(L"IpHlpApi.dll"); - if (IpHlpApiLibrary) + c_NotifyIpInterfaceChange = (FPNOTIFYIPINTERFACECHANGE)GetProcAddress(IpHlpApi, "NotifyIpInterfaceChange"); + c_CancelMibChangeNotify2 = (FPCANCELMIBCHANGENOTIFY2)GetProcAddress(IpHlpApi, "CancelMibChangeNotify2"); + + if (c_NotifyIpInterfaceChange && c_CancelMibChangeNotify2) { - c_GetIfTable2Ex = (FPGETIFTABLE2EX)GetProcAddress(IpHlpApiLibrary, "GetIfTable2Ex"); - c_FreeMibTable = (FPFREEMIBTABLE)GetProcAddress(IpHlpApiLibrary, "FreeMibTable"); + c_NotifyIpInterfaceChange(AF_UNSPEC, (PIPINTERFACE_CHANGE_CALLBACK)IpInterfaceChangeCallback, NULL, FALSE, &c_NotificationHandle); + + if (c_NotificationHandle == NULL) + { + c_NotifyIpInterfaceChange = NULL; + c_CancelMibChangeNotify2 = NULL; + Log(LOG_ERROR, L"NotifyIpInterfaceChange function failed."); + } } - - c_UseNewApi = (IpHlpApiLibrary && c_GetIfTable2Ex && c_FreeMibTable); - - if (!c_UseNewApi) + else { - c_GetIfTable2Ex = NULL; - c_FreeMibTable = NULL; + c_NotifyIpInterfaceChange = NULL; + c_CancelMibChangeNotify2 = NULL; + Log(LOG_ERROR, L"NotifyIpInterfaceChange/CancelMibChangeNotify2 function not found in IpHlpApi.dll."); } } @@ -696,22 +702,32 @@ void CMeasureNet::InitializeNewApi() */ void CMeasureNet::FinalizeNewApi() { - if (c_UseNewApi) + if (c_NotificationHandle) { - if (c_Table) - { - c_FreeMibTable(c_Table); - } - - c_GetIfTable2Ex = NULL; - c_FreeMibTable = NULL; + c_CancelMibChangeNotify2(c_NotificationHandle); + c_NotificationHandle = NULL; } - else - { - delete [] c_Table; - } - c_Table = NULL; - c_NumOfTables = 0; - c_UseNewApi = false; + c_GetIfEntry2 = NULL; + c_NotifyIpInterfaceChange = NULL; + c_CancelMibChangeNotify2 = NULL; + + DisposeBuffer(); +} + +/* +** DisposeBuffer +** +*/ +void CMeasureNet::DisposeBuffer() +{ + delete [] c_AATable; + c_AATable = NULL; + c_AASize = 0; + + delete [] c_Table; + c_Table = NULL; + c_Size = 0; + + c_NumOfTables = 0; } diff --git a/Library/MeasureNet.h b/Library/MeasureNet.h index 9886bef2..8b1ba597 100644 --- a/Library/MeasureNet.h +++ b/Library/MeasureNet.h @@ -24,8 +24,9 @@ #include #include "Measure.h" -typedef NETIO_STATUS (NETIOAPI_API_ * FPGETIFTABLE2EX)(MIB_IF_TABLE_LEVEL Level, PMIB_IF_TABLE2* Table); -typedef VOID (NETIOAPI_API_ * FPFREEMIBTABLE)(PVOID Memory); +typedef NETIO_STATUS (NETIOAPI_API_ * FPGETIFENTRY2)(PMIB_IF_ROW2 Row); +typedef NETIO_STATUS (NETIOAPI_API_ * FPNOTIFYIPINTERFACECHANGE)(ADDRESS_FAMILY Family, PIPINTERFACE_CHANGE_CALLBACK Callback, PVOID CallerContext, BOOLEAN InitialNotification, HANDLE* NotificationHandle); +typedef NETIO_STATUS (NETIOAPI_API_ * FPCANCELMIBCHANGENOTIFY2)(HANDLE NotificationHandle); class CMeasureNet : public CMeasure { @@ -56,6 +57,9 @@ protected: ULONG64 GetNetOctets(NET net); ULONG64 GetNetStatsValue(NET net); + static void DisposeBuffer(); + static VOID NETIOAPI_API_ IpInterfaceChangeCallback(PVOID CallerContext, PMIB_IPINTERFACE_ROW Row, MIB_NOTIFICATION_TYPE NotificationType); + double m_CurrentTraffic; double m_TrafficValue; UINT m_Interface; @@ -65,11 +69,17 @@ protected: static std::vector c_OldStatValues; static std::vector c_StatValues; static BYTE* c_Table; + static ULONG c_Size; static UINT c_NumOfTables; + static BYTE* c_AATable; + static ULONG c_AASize; - static FPGETIFTABLE2EX c_GetIfTable2Ex; - static FPFREEMIBTABLE c_FreeMibTable; - static bool c_UseNewApi; + static bool c_IpInterfaceChanged; + static HANDLE c_NotificationHandle; + + static FPGETIFENTRY2 c_GetIfEntry2; + static FPNOTIFYIPINTERFACECHANGE c_NotifyIpInterfaceChange; + static FPCANCELMIBCHANGENOTIFY2 c_CancelMibChangeNotify2; }; #endif