Skip to content

Commit

Permalink
ServiceBrowser: to query for multiple services, StartBrowse must be p…
Browse files Browse the repository at this point in the history
…rovided with all the services at once. This makes it easy to handle the querying for all services together. This combined query also queries for A/AAAA records if the IPAddress for a host is not known.
  • Loading branch information
tmds committed Dec 13, 2013
1 parent a9f0a07 commit ca805b9
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 104 deletions.
125 changes: 109 additions & 16 deletions Tmds/MDns/NetworkInterfaceHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,19 @@ public NetworkInterfaceHandler(ServiceBrowser serviceBrowser, NetworkInterface n
ServiceBrowser = serviceBrowser;
NetworkInterface = networkInterface;
_index = NetworkInterface.Information.GetIPProperties().GetIPv4Properties().Index;
_queryTimer = new Timer(OnQueryTimerElapsed);
}

public void StartBrowse(Name name)
public void StartBrowse(IEnumerable<Name> names)
{
var serviceHandler = new ServiceHandler(this, name);
_serviceHandlers.Add(name, serviceHandler);
foreach (var name in names)
{
var serviceHandler = new ServiceHandler(this, name);
_serviceHandlers.Add(name, serviceHandler);
}
if (_isEnabled)
{
serviceHandler.StartBrowse();
StartQuery();
}
}

Expand All @@ -64,11 +68,7 @@ public void Enable()
_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 1);

StartReceive();

foreach (var serviceHandlerKV in _serviceHandlers)
{
serviceHandlerKV.Value.StartBrowse();
}
StartQuery();
}
}

Expand All @@ -83,10 +83,11 @@ public void Disable()
{
_isEnabled = false;

StopQuery();

foreach (var serviceHandlerKV in _serviceHandlers)
{
ServiceHandler serviceHandler = serviceHandlerKV.Value;
serviceHandler.StopBrowse();
serviceHandler.ServiceInfos.Clear();
}

Expand Down Expand Up @@ -188,15 +189,18 @@ private void OnReceive(IAsyncResult ar)
var reader = new DnsMessageReader(stream);
Header header = reader.ReadHeader();

if (header.IsQuery && header.QuestionCount == 1 && header.AnswerCount == 0)
if (header.IsQuery && header.AnswerCount == 0)
{
Question question = reader.ReadQuestion();
Name serviceName = question.QName;
if (_serviceHandlers.ContainsKey(serviceName))
for (int i = 0; i < header.QuestionCount; i++)
{
if (header.TransactionID != _serviceHandlers[serviceName].LastTransactionId)
Question question = reader.ReadQuestion();
Name serviceName = question.QName;
if (_serviceHandlers.ContainsKey(serviceName))
{
OnServiceQuery(serviceName);
if (header.TransactionID != _lastQueryId)
{
OnServiceQuery(serviceName);
}
}
}
}
Expand Down Expand Up @@ -499,6 +503,91 @@ private void AddServiceHostInfo(ServiceInfo service)
service.Addresses = hostInfo.Addresses;
}

private void StartQuery()
{
_queryCount = 0;
ScheduleQueryTimer(0);
}

private void StopQuery()
{
ScheduleQueryTimer(Timeout.Infinite);
}

private void OnQueryTimerElapsed(object obj)
{
lock (this)
{
QueryParameters queryParameters = ServiceBrowser.QueryParameters;
DateTime now = DateTime.Now;

bool sendQuery = false;
_lastQueryId = (ushort)_randomGenerator.Next(0, ushort.MaxValue);
var writer = new DnsMessageWriter();
writer.WriteQueryHeader(_lastQueryId);

foreach (var serviceKV in _serviceHandlers)
{
Name Name = serviceKV.Key;
var ServiceInfos = serviceKV.Value.ServiceInfos;
bool sendQueryForService = false;
if (_queryCount < queryParameters.StartQueryCount)
{
sendQueryForService = true;
}
else
{
if (ServiceInfos.Count == 0)
{
sendQueryForService = true;
}
else
{
foreach (ServiceInfo service in ServiceInfos)
{
if (service.LastQueryTime <= now.AddMilliseconds(-queryParameters.QueryInterval))
{
sendQueryForService = true;
}
}
}
}
if (sendQueryForService)
{
OnServiceQuery(Name);
writer.WriteQuestion(Name, RecordType.PTR);
}
sendQuery = sendQuery || sendQueryForService;
}

foreach (var hostKV in _hostInfos)
{
var name = hostKV.Key;
var adresses = hostKV.Value.Addresses;
if (hostKV.Value.Addresses == null)
{
writer.WriteQuestion(name, RecordType.All);
sendQuery = true;
}
}

if (sendQuery)
{
var packets = writer.Packets;
Send(packets);

_queryCount++;
}

ScheduleQueryTimer(_queryCount >= queryParameters.StartQueryCount ? queryParameters.QueryInterval : queryParameters.StartQueryInterval);
}
}

private void ScheduleQueryTimer(int ms)
{
_queryTimer.Change(ms, Timeout.Infinite);
}

private bool _isEnabled;
private Socket _socket;
private readonly int _index;
Expand All @@ -508,5 +597,9 @@ private void AddServiceHostInfo(ServiceInfo service)
private readonly Dictionary<Name, ServiceInfo> _serviceInfos = new Dictionary<Name, ServiceInfo>();
private readonly Dictionary<Name, HostInfo> _hostInfos = new Dictionary<Name, HostInfo>();
private readonly Dictionary<Name, ServiceHandler> _serviceHandlers = new Dictionary<Name, ServiceHandler>();
private int _queryCount;
private readonly Timer _queryTimer;
private Random _randomGenerator = new Random();
private ushort _lastQueryId;
}
}
26 changes: 10 additions & 16 deletions Tmds/MDns/ServiceBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Threading;
using System.Linq;
using NetworkInterfaceInformation = System.Net.NetworkInformation.NetworkInterface;

namespace Tmds.MDns
Expand All @@ -32,25 +33,19 @@ public ServiceBrowser()

public void StartBrowse(string serviceType)
{
serviceType = serviceType.ToLower();

if (_serviceTypes.Contains(serviceType))
{
return;
}
_serviceTypes.Add(serviceType);
StartBrowse(new [] { serviceType });
}

if (!IsBrowsing)
public void StartBrowse(IEnumerable<string> serviceTypes)
{
if (IsBrowsing)
{
StartBrowsing();
throw new Exception("Already browsing");
}
var name = new Name(serviceType + ".local.");
lock (_interfaceHandlers)
StartBrowsing();
foreach (var interfaceHandler in _interfaceHandlers)
{
foreach (var interfaceHandler in _interfaceHandlers)
{
interfaceHandler.Value.StartBrowse(name);
}
interfaceHandler.Value.StartBrowse(serviceTypes.Select(st => new Name(st.ToLower() + ".local.")));
}
}

Expand Down Expand Up @@ -241,7 +236,6 @@ private void SynchronizationContextPost(SendOrPostCallback cb)

private readonly HashSet<ServiceAnnouncement> _services = new HashSet<ServiceAnnouncement>();
private readonly Dictionary<Tuple<string, Name>, ServiceAnnouncement> _serviceAnnouncements = new Dictionary<Tuple<string, Name>, ServiceAnnouncement>();
private readonly List<string> _serviceTypes = new List<string>();
private Dictionary<int, NetworkInterfaceHandler> _interfaceHandlers;
}
}
72 changes: 0 additions & 72 deletions Tmds/MDns/ServiceHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,83 +26,11 @@ public ServiceHandler(NetworkInterfaceHandler networkInterfaceHandler, Name name
{
Name = name;
NetworkInterfaceHandler = networkInterfaceHandler;
_timer = new Timer(OnTimerElapsed);
ServiceInfos = new List<ServiceInfo>();
}

public void StartBrowse()
{
_queryCount = 0;
ScheduleTimer(0);
}

public void StopBrowse()
{
ScheduleTimer(Timeout.Infinite);
}

public Name Name { get; private set; }
public NetworkInterfaceHandler NetworkInterfaceHandler { get; private set; }
public List<ServiceInfo> ServiceInfos { get; private set; }
public ushort LastTransactionId { get; set; }

private void OnTimerElapsed(object obj)
{
lock (NetworkInterfaceHandler)
{
QueryParameters queryParameters = NetworkInterfaceHandler.ServiceBrowser.QueryParameters;
DateTime now = DateTime.Now;

bool sendQuery = false;
if (_queryCount < queryParameters.StartQueryCount)
{
sendQuery = true;
}
else
{
if (ServiceInfos.Count == 0)
{
sendQuery = true;
}
else
{
foreach (ServiceInfo service in ServiceInfos)
{
if (service.LastQueryTime <= now.AddMilliseconds(-queryParameters.QueryInterval))
{
sendQuery = true;
}
}
}
}

if (sendQuery)
{
NetworkInterfaceHandler.OnServiceQuery(Name);
LastTransactionId = (ushort)_randomGenerator.Next(0, ushort.MaxValue);

var writer = new DnsMessageWriter();
writer.WriteQueryHeader(LastTransactionId);
writer.WriteQuestion(Name, RecordType.PTR);

var packets = writer.Packets;
NetworkInterfaceHandler.Send(packets);

_queryCount++;
}

ScheduleTimer(_queryCount >= queryParameters.StartQueryCount ? queryParameters.QueryInterval : queryParameters.StartQueryInterval);
}
}

private void ScheduleTimer(int ms)
{
_timer.Change(ms, Timeout.Infinite);
}

private int _queryCount;
private readonly Timer _timer;
private Random _randomGenerator = new Random();
}

}

0 comments on commit ca805b9

Please sign in to comment.