using System; using System.Collections.Generic; using System.Linq; using PepperDash.Core; using Crestron.SimplSharp; using PepperDash.Essentials.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.DeviceInfo { public static class NetworkDeviceHelpers { /// /// Event raised when ArpTable changes /// public static event ArpTableEventHandler ArpTableUpdated; /// /// Delegate called by ArpTableUpdated /// /// contains the entire ARP table and a bool to note if there was an error in retrieving the data public delegate void ArpTableEventHandler(ArpTableEventArgs args); private static readonly char NewLineSplitter = CrestronEnvironment.NewLine.ToCharArray().First(); private static readonly string NewLine = CrestronEnvironment.NewLine; private static readonly CCriticalSection Lock = new CCriticalSection(); /// /// Last resolved ARP table - it is recommended to refresh the arp before using this. /// public static List ArpTable { get; private set; } /// /// Force recheck of ARP table /// public static void RefreshArp() { var error = false; try { Lock.Enter(); var consoleResponse = string.Empty; if (!CrestronConsole.SendControlSystemCommand("showarptable", ref consoleResponse)) return; if (string.IsNullOrEmpty(consoleResponse)) { error = true; return; } ArpTable.Clear(); Debug.LogMessage(LogEventLevel.Verbose, "ConsoleResponse of 'showarptable' : {0}{1}", NewLine, consoleResponse); var myLines = consoleResponse.Split(NewLineSplitter) .ToList() .Where(o => (o.Contains(':') && !o.Contains("Type", StringComparison.OrdinalIgnoreCase))) .ToList(); foreach (var line in myLines) { var item = line; var seperator = item.Contains('\t') ? '\t' : ' '; var dataPoints = item.Split(seperator); if (dataPoints == null || dataPoints.Length < 2) continue; var ipAddress = SanitizeIpAddress(dataPoints.First().TrimAll()); var macAddress = dataPoints.Last(); ArpTable.Add(new ArpEntry(ipAddress, macAddress)); } } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Exception in \"RefreshArp\" : {0}", ex.Message); error = true; } finally { Lock.Leave(); OnArpTableUpdated(new ArpTableEventArgs(ArpTable, error)); } } private static void OnArpTableUpdated(ArpTableEventArgs args) { if (args == null) return; var handler = ArpTableUpdated; if (handler == null) return; handler.Invoke(args); } static NetworkDeviceHelpers() { ArpTable = new List(); } /// /// Removes leading zeros, leading whitespace, and trailing whitespace from an IPAddress string /// /// Ip Address to Santitize /// Sanitized Ip Address public static string SanitizeIpAddress(string ipAddressIn) { try { var ipAddress = IPAddress.Parse(ipAddressIn.TrimStart('0')); return ipAddress.ToString(); } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Unable to Santize Ip : {0}", ex.Message); return ipAddressIn; } } /// /// Resolves a hostname by IP Address using DNS /// /// IP Address to resolve from /// Resolved Hostname - on failure to determine hostname, will return IP Address public static string ResolveHostnameFromIp(string ipAddress) { try { var santitizedIp = SanitizeIpAddress(ipAddress); var hostEntry = Dns.GetHostEntry(santitizedIp); return hostEntry == null ? ipAddress : hostEntry.HostName; } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Exception Resolving Hostname from IP Address : {0}", ex.Message); return ipAddress; } } /// /// Resolves an IP Address by hostname using DNS /// /// Hostname to resolve from /// Resolved IP Address - on a failure to determine IP Address, will return hostname public static string ResolveIpFromHostname(string hostName) { try { var hostEntry = Dns.GetHostEntry(hostName); return hostEntry == null ? hostName : hostEntry.AddressList.First().ToString(); } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Exception Resolving IP Address from Hostname : {0}", ex.Message); return hostName; } } } /// /// Object to hold data about an arp entry /// public class ArpEntry { public readonly IPAddress IpAddress; public readonly string MacAddress; /// /// Constructs new ArpEntry object /// /// string formatted as ipv4 address /// mac address string - format is unimportant public ArpEntry(string ipAddress, string macAddress) { if (string.IsNullOrEmpty(ipAddress)) { throw new ArgumentException("\"ipAddress\" cannot be null or empty"); } if (string.IsNullOrEmpty(macAddress)) { throw new ArgumentException("\"macAddress\" cannot be null or empty"); } IpAddress = IPAddress.Parse(ipAddress.TrimStart().TrimStart('0').TrimEnd()); MacAddress = macAddress; } } /// /// Arguments passed by the ArpTableUpdated event /// public class ArpTableEventArgs : EventArgs { /// /// The retrieved ARP Table /// public readonly List ArpTable; /// /// True if there was a problem retrieving the ARP Table /// public readonly bool Error; /// /// Constructor for ArpTableEventArgs /// /// The entirety of the retrieved ARP table /// True of an error was encountered updating the ARP table public ArpTableEventArgs(List arpTable, bool error) { ArpTable = arpTable; Error = error; } /// /// Constructor for ArpTableEventArgs - assumes no error encountered in retrieving ARP Table /// /// The entirety of the retrieved ARP table public ArpTableEventArgs(List arpTable) { ArpTable = arpTable; Error = false; } } }