Files
ReLibreHardwareMonitor/Hardware/Nic/NicGroup.cs
T
Nick Babcock 963dd27247 Rework NIC / Network Reporting (#75)
* Rework NIC / Network Reporting

* Switch to monotonic timer for calculating time deltas between reports. Relying on `DateTime` to calculate time deltas is dangerous as it would be susceptible to phenomena such as a user changing their time or leap seconds. The Stopwatch class allows us to get a monotonic timer if it exists.
* Interface statistics reset on wake. Previously this would cause nonsensical negative values to be reported. The fix is to reset the internal state when the interface statistics have been reset.
* Previously, interface hardware already seen when scanned would be re-registered causing zeros to be reported, so the fix is to keep track of what NICs have already been registered
* Corollary, old interfaces were not closed when removed.
* Document the code and constants used (eg: "800" is not indicative of converting bytes to bits and a ratio to a percentage). Hopefully it is much clearer.

Thanks to @nickbabcock
2019-01-13 12:40:03 +01:00

114 lines
3.7 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
namespace OpenHardwareMonitor.Hardware.Nic
{
internal class NicGroup : IGroup
{
private readonly ISettings _settings;
private List<Nic> _hardware = new List<Nic>();
private readonly object _scanLock = new object();
private readonly Dictionary<string, Nic> _nics = new Dictionary<string, Nic>();
public NicGroup(ISettings settings)
{
_settings = settings;
ScanNics(settings);
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAddressChanged;
}
private void ScanNics(ISettings settings)
{
// If no network is marked up (excluding loopback and tunnel) then don't scan
// for interfaces.
if (!NetworkInterface.GetIsNetworkAvailable())
{
return;
}
// When multiple events fire concurrently, we don't want threads interferring
// with others as they manipulate non-thread safe state.
lock (_scanLock)
{
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces()
.Where(DesiredNetworkType)
.OrderBy(x => x.Name);
var scanned = networkInterfaces.ToDictionary(x => x.Id, x => x);
var newNics = scanned.Where(x => !_nics.ContainsKey(x.Key));
var removedNics = _nics.Where(x => !scanned.ContainsKey(x.Key)).ToList();
foreach (var nic in removedNics)
{
nic.Value.Close();
_nics.Remove(nic.Key);
}
foreach (var nic in newNics)
{
_nics.Add(nic.Key, new Nic(nic.Value, settings));
}
_hardware = _nics.Values.OrderBy(x => x.Name).ToList();
}
}
private void NetworkChange_NetworkAddressChanged(object sender, System.EventArgs e)
{
ScanNics(_settings);
}
private static bool DesiredNetworkType(NetworkInterface nic)
{
switch (nic.NetworkInterfaceType)
{
case NetworkInterfaceType.Loopback:
case NetworkInterfaceType.Tunnel:
case NetworkInterfaceType.Unknown:
return false;
default:
return true;
}
}
public string GetReport()
{
var report = new StringBuilder();
foreach (Nic hw in _hardware)
{
report.AppendLine(hw.NetworkInterface.Description);
report.AppendLine(hw.NetworkInterface.OperationalStatus.ToString());
report.AppendLine();
foreach (var sensor in hw.Sensors)
{
report.AppendLine(sensor.Name);
report.AppendLine(sensor.Value.ToString() + sensor.SensorType);
report.AppendLine();
}
}
return report.ToString();
}
public IEnumerable<IHardware> Hardware
{
get
{
return _hardware;
}
}
public void Close()
{
NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAddressChanged;
foreach (var nic in _hardware)
nic.Close();
}
}
}