protected virtual void OnDeviceFound(EVADevice newDevice) { EventHandler <DiscoveryDeviceFoundEventArgs> handler = DeviceFound; if (handler != null) { handler(this, new DiscoveryDeviceFoundEventArgs(newDevice)); } }
public async Task <EVADevices> StartAsync(IPAddress newIP) { if (p_IsRunning) { throw new EVADiscoveryException("Discovery is already running."); } else { p_IsRunning = true; } IPAddress sendAddress = p_BoxIP; if (newIP != null) { if (!newIP.Equals(p_BoxIP)) { p_BoxIP = newIP; sendAddress = p_BoxIP; } } else { sendAddress = new IPAddress(0); } OnStartDiscovery(sendAddress, p_DiscoveryPort); EVADevices foundDevices = new EVADevices(); discovery = new TaskCompletionSource <EVADevices>(); ctSource = new CancellationTokenSource(); List <Task> netIOTasks = new List <Task> { // listening task // do not use the cancellation token here, because socket operations are hard to abort // instead we'll receive our own packet and terminate the loop, if cancellation was requested Task.Factory.StartNew(() => { using (UdpClient listener = new UdpClient(p_DiscoveryPort)) { IPEndPoint ep = new IPEndPoint(IPAddress.Any, p_DiscoveryPort); bool canceled = false; while (!canceled) { byte[] data = listener.Receive(ref ep); if (DiscoveryUdpPacket.IsAnswer(data)) { OnPacketReceived(ep, data); EVADevice foundDevice = new EVADevice(ep, new DiscoveryUdpPacket(data)); if (!foundDevices.ContainsKey(foundDevice.Address)) { foundDevices.Add(foundDevice.Address, foundDevice); OnDeviceFound(foundDevice); if (p_StopOnFirstFound) { canceled = true; } } } if (ctSource.IsCancellationRequested) { canceled = true; } } } }), // broadcast discovery packets, do not use cancellation token for the outer loop // the first packet is sent with a 10 ms delay, later the interval will grow up to 1000 ms Task.Factory.StartNew(async() => { IPEndPoint ep = new IPEndPoint(p_BroadcastAddress, p_DiscoveryPort); byte[] data = new DiscoveryUdpPacket(sendAddress).ToBytes(); int delay = 10; using (UdpClient sender = new UdpClient()) { bool canceled = false; while (!canceled) { try { await Task.Delay(delay, ctSource.Token); } catch (TaskCanceledException) { } if (ctSource.IsCancellationRequested) { canceled = true; } sender.Send(data, data.Length, ep); if (!canceled) { OnPacketSent(sendAddress, p_DiscoveryPort, data); delay = 1000; } } // send one more packet to terminate listening loop sender.Send(data, data.Length, ep); } }), // timeout task, cancelable Task.Delay(DiscoveryTimeout * 1000, ctSource.Token).ContinueWith((t) => { p_TimeoutElapsed = true; ctSource.Cancel(); }, TaskContinuationOptions.NotOnCanceled) }; while (netIOTasks.Count > 0) { try { Task finished = await Task.WhenAny(netIOTasks); netIOTasks.Remove(finished); if (finished is Task <Task> && !p_TimeoutElapsed) { netIOTasks.Add(((Task <Task>)finished).Result); } else { if (!ctSource.IsCancellationRequested && (p_TimeoutElapsed || (p_StopOnFirstFound && foundDevices.Count > 0))) { ctSource.Cancel(); } } } catch (TaskCanceledException e) { netIOTasks.Remove(e.Task); } catch (AggregateException age) { foreach (Exception e in age.InnerExceptions) { if (e is TaskCanceledException) { Task t = ((TaskCanceledException)e).Task; if (netIOTasks.Count > 0 && netIOTasks.Contains(t)) { netIOTasks.Remove(t); } } else { throw e; } } } catch (Exception e) { throw e; } } OnStopDiscovery(foundDevices.Count, p_Canceled); p_IsRunning = false; discovery.SetResult(foundDevices); return(foundDevices); }
internal DiscoveryDeviceFoundEventArgs(EVADevice Device) { p_Device = Device; }