diff --git a/UbntDiscovery/Discovery/BroadcastUdpClient.cs b/UbntDiscovery/Discovery/BroadcastUdpClient.cs new file mode 100644 index 0000000..5845ecb --- /dev/null +++ b/UbntDiscovery/Discovery/BroadcastUdpClient.cs @@ -0,0 +1,26 @@ +using System.Net; +using System.Net.Sockets; + +namespace UbntDiscovery +{ + class BroadcastUdpClient : UdpClient + { + public BroadcastUdpClient() : base() + { + //Calls the protected Client property belonging to the UdpClient base class. + Socket s = this.Client; + //Uses the Socket returned by Client to set an option that is not available using UdpClient. + s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); + s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1); + } + + public BroadcastUdpClient(IPEndPoint ipLocalEndPoint) : base(ipLocalEndPoint) + { + //Calls the protected Client property belonging to the UdpClient base class. + Socket s = this.Client; + //Uses the Socket returned by Client to set an option that is not available using UdpClient. + s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); + s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1); + } + } +} diff --git a/UbntDiscovery/Device.cs b/UbntDiscovery/Discovery/Device.cs similarity index 81% rename from UbntDiscovery/Device.cs rename to UbntDiscovery/Discovery/Device.cs index 9c9891c..8e49f46 100644 --- a/UbntDiscovery/Device.cs +++ b/UbntDiscovery/Discovery/Device.cs @@ -47,7 +47,7 @@ public class Device { "ACP", "airCam PRO" }, { "AirCamPRO", "airCam PRO" }, { "AirCamDome", "airCam Dome" }, { "AirCamMini", "airCam Mini" }, { "AirCam", "airCam" }, { "NVR", "airVision NVR" }, { "ACD", "airCam Dome" }, { "ACM", "airCam Mini" }, { "AC", "airCam" }, { "TSW-5-POE", "TOUGHSwitch 5 PoE" }, { "TSW-8-POE", "TOUGHSwitch 8 PoE" }, { "TSW-8", "TOUGHSwitch 8" }, - { "TSW-PoE PRO", "TOUGHSwitch PoE PRO" }, { "TSW-PoE", "TOUGHSwitch PoE" } }; + { "TSW-PoE PRO", "TOUGHSwitch PoE PRO" }, { "TSW-PoE", "TOUGHSwitch PoE" }, { "P5B-400", "M5 NanoBeam 400" } }; public Device() { @@ -73,7 +73,9 @@ public String WirelessModeDescription get { if (WirelessMode < WirelessModes.Length) + { return WirelessModes[WirelessMode]; + } return String.Format("Unknown {0}", WirelessMode); } @@ -99,5 +101,52 @@ public override string ToString() { return String.Format("{1}:{0}", Hostname, FirstAddress.IpAddress); } + + public bool Equals(Device other) + { + if (Hostname != other.Hostname) + { + return false; + } + if (Platform != other.Platform) + { + return false; + } + if (Firmware != other.Firmware) + { + return false; + } + if (SSID != other.SSID) + { + return false; + } + + if (Uptime != other.Uptime) + { + return false; + } + if (WirelessMode != other.WirelessMode) + { + return false; + } + + int addressCount = Addresses.Count; + if (addressCount != other.Addresses.Count) + { + return false; + } + + for (int i = 0; i < addressCount; i++) + { + DeviceAddress a = Addresses[i]; + DeviceAddress b = other.Addresses[i]; + if (!a.Equals(b)) + { + return false; + } + } + + return true; + } } } diff --git a/UbntDiscovery/DeviceAddress.cs b/UbntDiscovery/Discovery/DeviceAddress.cs similarity index 100% rename from UbntDiscovery/DeviceAddress.cs rename to UbntDiscovery/Discovery/DeviceAddress.cs diff --git a/UbntDiscovery/DeviceDiscovery.cs b/UbntDiscovery/Discovery/DeviceDiscovery.cs similarity index 79% rename from UbntDiscovery/DeviceDiscovery.cs rename to UbntDiscovery/Discovery/DeviceDiscovery.cs index ec85e53..73534b2 100644 --- a/UbntDiscovery/DeviceDiscovery.cs +++ b/UbntDiscovery/Discovery/DeviceDiscovery.cs @@ -22,17 +22,11 @@ protected virtual void OnDeviceDiscovered(Device e) public Boolean IsScanning { get; set; } - /// - /// Endpoint to listen - /// - private IPEndPoint _EP1; - /// /// Endpoint to broadcast /// private IPEndPoint _EP2; - private HashSet _PacketHash; /// /// Packet data to broadcast @@ -42,20 +36,19 @@ protected virtual void OnDeviceDiscovered(Device e) public DeviceDiscovery() { IsScanning = false; - _PacketHash = new HashSet(); - _EP1 = new IPEndPoint(IPAddress.Any, 2048); _EP2 = new IPEndPoint(IPAddress.Broadcast, 10001); } - public async Task DiscoveryAsync(CancellationToken ct) + public async Task DiscoveryAsync(CancellationToken ct, IPAddress interfaceAddress) { - - var udpClient = new UdpClient(_EP1); - udpClient.EnableBroadcast = true; + IPEndPoint interfaceEndpoint = new IPEndPoint(interfaceAddress, 2048); + var udpClient = new BroadcastUdpClient(interfaceEndpoint); + //udpClient.EnableBroadcast = true; await udpClient.SendAsync(_Datagram, _Datagram.Length, _EP2); udpClient.EnableBroadcast = false; ct.Register(() => udpClient.Close() ); - + + HashSet packetHash = new HashSet(); while (!ct.IsCancellationRequested) { @@ -73,15 +66,16 @@ public async Task DiscoveryAsync(CancellationToken ct) DiscoveryPacket dpack = new DiscoveryPacket(receiveResult.Buffer); Device device = dpack.DecodePacket(); - Boolean result = _PacketHash.Add(Utils.CalculateHash(receiveResult.Buffer)); + Boolean result = packetHash.Add(Utils.CalculateHash(receiveResult.Buffer)); if (result) + { OnDeviceDiscovered(device); - + } } udpClient.Close(); - _PacketHash.Clear(); + packetHash.Clear(); } diff --git a/UbntDiscovery/DiscoveryPacket.cs b/UbntDiscovery/Discovery/DiscoveryPacket.cs similarity index 100% rename from UbntDiscovery/DiscoveryPacket.cs rename to UbntDiscovery/Discovery/DiscoveryPacket.cs diff --git a/UbntDiscovery/MainWindowModel.cs b/UbntDiscovery/MainWindowModel.cs index 77d3068..76a808e 100644 --- a/UbntDiscovery/MainWindowModel.cs +++ b/UbntDiscovery/MainWindowModel.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Net; +using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -9,18 +12,18 @@ namespace UbntDiscovery { public class MainWindowModel { - public ObservableCollection Devices { get; private set; } + public ObservableCollection Devices { get; private set; } public DeviceDiscovery DeviceDiscovery { get; private set; } public MainWindow MainWindow { get; private set; } private CancellationTokenSource _cts; - private Task discoveryTask; public MainWindowModel(MainWindow mainWindow) { Devices = new ObservableCollection(); MainWindow = mainWindow; DeviceDiscovery = new DeviceDiscovery(); - DeviceDiscovery.DeviceDiscovered += DeviceDiscovery_DeviceDiscovered; + DeviceDiscovery.DeviceDiscovered += DeviceDiscovery_DeviceDiscovered; + _cts = new CancellationTokenSource(); } private void DeviceDiscovery_DeviceDiscovered(Device device) @@ -30,26 +33,38 @@ private void DeviceDiscovery_DeviceDiscovered(Device device) public async Task ScanAsync() { - if (discoveryTask != null && (discoveryTask.Status == TaskStatus.WaitingForActivation || discoveryTask.Status == TaskStatus.Running) ) - { - _cts.Cancel(); - Devices.Clear(); - } + _cts.Cancel(); + Devices.Clear(); try { var cts = new CancellationTokenSource(); _cts = cts; - discoveryTask = DeviceDiscovery.DiscoveryAsync(_cts.Token).ContinueWith((t) => cts.Dispose()); - await discoveryTask; + String strHostName = Dns.GetHostName(); + // Find host by name + IPHostEntry iphostentry = Dns.GetHostEntry(strHostName); + + // Enumerate IP addresses + List tasks = new List(); + foreach (IPAddress ipaddress in iphostentry.AddressList) + { + if (ipaddress.AddressFamily == AddressFamily.InterNetwork) + { + Task discoveryTask = DeviceDiscovery.DiscoveryAsync(cts.Token, ipaddress); + tasks.Add(discoveryTask); + } + } + foreach (Task discoveryTask in tasks) + { + await discoveryTask; + } + cts.Dispose(); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } - - } public void ClearDevices() @@ -62,13 +77,15 @@ public void AddDevice(Device device) { MainWindow.Dispatcher.Invoke(() => { + foreach (Device existingDevice in Devices) + { + if (existingDevice.Equals(device)) + { + return; + } + } Devices.Add(device); - }); } - - - - } } diff --git a/UbntDiscovery/UbntDiscovery.csproj b/UbntDiscovery/UbntDiscovery.csproj index 993a5d3..857b776 100644 --- a/UbntDiscovery/UbntDiscovery.csproj +++ b/UbntDiscovery/UbntDiscovery.csproj @@ -67,9 +67,10 @@ MSBuild:Compile Designer - - - + + + + MSBuild:Compile @@ -79,7 +80,7 @@ App.xaml Code - + MainWindow.xaml Code