Files
Vocaluxe/ServerLib/CDiscover.cs
T

137 lines
4.5 KiB
C#

#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 <http://www.gnu.org/licenses/>.
#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<string> knownServer = new List<string>();
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);
}
}
}