blob: 076120452e1c2337679d7fc82f8c1f6623ebef70 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020, 2021 Robert Bosch GmbH
* Author: Constantin Ziesche (constantin.ziesche@bosch.com)
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
using Makaretu.Dns;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
namespace BaSyx.Discovery.mDNS
{
public class DiscoveryServer
{
private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
private const int DISCOVER_THREAD_DELAY = 10000;
public event EventHandler<ServiceDiscoveredEventArgs> ServiceDiscovered;
public event EventHandler<ServiceInstanceEventArgs> ServiceInstanceDiscovered;
public event EventHandler<ServiceInstanceEventArgs> ServiceInstanceShutdown;
public string ServiceType { get; }
private CancellationTokenSource cancellationToken;
private readonly Thread discoverThread;
private readonly MulticastService mdns;
public DiscoveryServer(string serviceType)
{
ServiceType = serviceType;
discoverThread = new Thread(Discover);
mdns = new MulticastService();
}
private void Discover()
{
ServiceDiscovery sd = new ServiceDiscovery(mdns);
mdns.NetworkInterfaceDiscovered += (s, e) =>
{
foreach (var networkInterface in e.NetworkInterfaces)
{
logger.Info($"Network-Interface: '{networkInterface.Name}' found");
}
};
sd.ServiceDiscovered += Sd_ServiceDiscovered;
sd.ServiceInstanceDiscovered += Sd_ServiceInstanceDiscovered;
sd.ServiceInstanceShutdown += Sd_ServiceInstanceShutdown;
try
{
mdns.Start();
cancellationToken = new CancellationTokenSource();
while (!cancellationToken.IsCancellationRequested)
{
sd.QueryAllServices();
Thread.Sleep(DISCOVER_THREAD_DELAY);
}
}
finally
{
sd.Dispose();
mdns.Stop();
}
}
private void Sd_ServiceDiscovered(object sender, DomainName serviceName)
{
logger.Info($"service '{serviceName}' discovered");
ServiceDiscovered?.Invoke(sender, new ServiceDiscoveredEventArgs() { ServiceName = serviceName.ToString() });
if(serviceName.ToString().Contains(ServiceType))
mdns.SendQuery(serviceName, type: DnsType.PTR);
}
private void Sd_ServiceInstanceDiscovered(object sender, ServiceInstanceDiscoveryEventArgs e)
{
logger.Info($"service instance '{e.ServiceInstanceName}' discovered");
var args = GetServiceInstanceEventArgs(e);
ServiceInstanceDiscovered?.Invoke(sender, args);
}
private void Sd_ServiceInstanceShutdown(object sender, ServiceInstanceShutdownEventArgs e)
{
logger.Info($"service instance '{e.ServiceInstanceName}' is shutting down");
var args = GetServiceInstanceEventArgs(e);
ServiceInstanceShutdown?.Invoke(sender, args);
}
private ServiceInstanceEventArgs GetServiceInstanceEventArgs(MessageEventArgs e)
{
var servers = e.Message.AdditionalRecords.OfType<SRVRecord>();
var addresses = e.Message.AdditionalRecords.OfType<AddressRecord>();
var txtRecords = e.Message.AdditionalRecords.OfType<TXTRecord>()?.SelectMany(s => s.Strings);
ServiceInstanceEventArgs args = new ServiceInstanceEventArgs();
if (txtRecords?.Count() > 0)
args.TxtRecords.AddRange(txtRecords);
if (servers?.Count() > 0 && addresses?.Count() > 0)
{
foreach (var server in servers)
{
logger.Info($"host '{server.Target}' for '{server.Name}' at port '{server.Port}'");
var serverAddresses = addresses.Where(w => w.Name == server.Target);
if (serverAddresses?.Count() > 0)
{
foreach (var serverAddress in serverAddresses)
{
logger.Info($"host '{serverAddress.Name}' at {serverAddress.Address}");
args.Servers.Add(new Server()
{
Name = server.Name.ToString(),
Target = server.Target.ToString(),
Port = server.Port,
Address = serverAddress.Address
});
}
return args;
}
}
}
return args;
}
public void Start()
{
logger.Info("Discover thread starting...");
discoverThread.Start();
logger.Info("Discover thread started successfully" );
}
public void Stop()
{
logger.Info("Discover thread stopping...");
cancellationToken?.Cancel();
bool success = discoverThread.Join(DISCOVER_THREAD_DELAY + 500);
logger.Info("Discover thread stopped successfully:" + success);
}
}
public class ServiceInstanceEventArgs
{
public List<Server> Servers { get; set; }
public List<string> TxtRecords { get; set; }
public ServiceInstanceEventArgs()
{
Servers = new List<Server>();
TxtRecords = new List<string>();
}
}
public class Server
{
public IPAddress Address { get; set; }
public int Port { get; set; }
public string Target { get; set; }
public string Name { get; set; }
}
public class ServiceDiscoveredEventArgs
{
public string ServiceName { get; internal set; }
}
}