#region license // This file is part of Vocaluxe. // // Vocaluxe is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Vocaluxe is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Vocaluxe. If not, see . #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Timers; namespace ServerLib { public delegate void OnServerDiscovered(string ipAddress, string hostname); public class CDiscover { public const string Timeout = "Timeout"; public const string Finished = "Finished"; private readonly string _Keyword; private readonly string _BroadcastAddress; private readonly int _Port; private Thread _DiscoverThread; private bool _DiscoverRunning; private OnServerDiscovered _OnDiscovered; private readonly System.Timers.Timer _BroadcastTimer; public CDiscover(int port, string keyword, string broadcastAddress = "255.255.255.255") { _BroadcastAddress = broadcastAddress; _Port = port; _Keyword = keyword; _DiscoverRunning = false; _BroadcastTimer = new System.Timers.Timer(); _BroadcastTimer.Elapsed += _OnBroadcastEvent; _BroadcastTimer.Interval = 2500; } public void StartBroadcasting() { _BroadcastTimer.Start(); } public void Stop() { _BroadcastTimer.Stop(); _DiscoverRunning = false; } public void Discover(OnServerDiscovered onDiscovered, int timeout = 5000) { if (_DiscoverRunning) return; _DiscoverRunning = true; _DiscoverThread = new Thread(() => _Discover(timeout)) {Name = "Client discover"}; _OnDiscovered = onDiscovered; _DiscoverThread.Start(); } private void _OnBroadcastEvent(object source, ElapsedEventArgs e) { Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) {EnableBroadcast = true}; IPAddress broadcast = IPAddress.Parse(_BroadcastAddress); byte[] sendbuf = Encoding.UTF8.GetBytes(_Keyword); IPEndPoint ep = new IPEndPoint(broadcast, _Port); s.SendTo(sendbuf, ep); s.Close(); } private void _Discover(int timeout) { UdpClient listener = null; Stopwatch timer = new Stopwatch(); List knownServer = new List(); bool foundSomething = false; timer.Start(); while (_DiscoverRunning && timer.ElapsedMilliseconds < timeout * 2) { try { listener = new UdpClient(_Port); IPEndPoint groupEp = new IPEndPoint(IPAddress.Any, _Port); listener.Client.ReceiveTimeout = timeout; byte[] bytes = listener.Receive(ref groupEp); string message = Encoding.UTF8.GetString(bytes, 0, bytes.Length); foundSomething = true; if (!knownServer.Contains(groupEp.Address.ToString())) { knownServer.Add(groupEp.Address.ToString()); if (_OnDiscovered != null) { IPHostEntry e = Dns.GetHostEntry(groupEp.Address); string hostname = e.HostName; _OnDiscovered(groupEp.Address.ToString(), hostname); } } listener.Close(); } catch (Exception) { if (listener != null) listener.Close(); } } _DiscoverRunning = false; if (_OnDiscovered != null) _OnDiscovered(!foundSomething ? Timeout : Finished, String.Empty); } } }