Skip to content

Commit

Permalink
Merge pull request #82 from richardschneider/announce
Browse files Browse the repository at this point in the history
Announce a service
  • Loading branch information
richardschneider authored Oct 17, 2019
2 parents d16cff2 + cbb8df2 commit a6c5fa4
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/MulticastService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public MulticastService(Func<IEnumerable<NetworkInterface>, IEnumerable<NetworkI

UseIpv4 = Socket.OSSupportsIPv4;
UseIpv6 = Socket.OSSupportsIPv6;
IgnoreDuplicateMessages = true;
}

/// <summary>
Expand All @@ -150,6 +151,18 @@ public MulticastService(Func<IEnumerable<NetworkInterface>, IEnumerable<NetworkI
/// </value>
public bool UseIpv6 { get; set; }

/// <summary>
/// Determines if received messages are checked for duplicates.
/// </summary>
/// <value>
/// <b>true</b> to ignore duplicate messages. Defaults to <b>true</b>.
/// </value>
/// <remarks>
/// When set, a message that has been received within the last minute
/// will be ignored.
/// </remarks>
public bool IgnoreDuplicateMessages { get; set; }

/// <summary>
/// The interval for discovering network interfaces.
/// </summary>
Expand Down Expand Up @@ -619,7 +632,7 @@ void Send(Message msg, bool checkDuplicate, IPEndPoint remoteEndPoint = null)
public void OnDnsMessage(object sender, UdpReceiveResult result)
{
// If recently received, then ignore.
if (!receivedMessages.TryAdd(result.Buffer))
if (IgnoreDuplicateMessages && !receivedMessages.TryAdd(result.Buffer))
{
return;
}
Expand Down
35 changes: 35 additions & 0 deletions src/ServiceDiscovery.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Common.Logging;
using Makaretu.Dns.Resolving;

Expand Down Expand Up @@ -256,6 +257,40 @@ public void Advertise(ServiceProfile service)
catalog.IncludeReverseLookupRecords();
}

/// <summary>
/// Sends an unsolicited MDNS response describing the
/// service profile.
/// </summary>
/// <param name="profile">
/// The profile to describe.
/// </param>
/// <remarks>
/// Sends a MDNS response <see cref="Message"/> containing the pointer
/// and resource records of the <paramref name="profile"/>.
/// <para>
/// To provide increased robustness against packet loss,
/// two unsolicited responses are sent one second apart.
/// </para>
/// </remarks>
public void Announce(ServiceProfile profile)
{
var message = new Message { QR = true };

// Add the shared records.
var ptrRecord = new PTRRecord { Name = profile.QualifiedServiceName, DomainName = profile.FullyQualifiedName };
message.Answers.Add(ptrRecord);

// Add the resource records.
profile.Resources.ForEach((resource) =>
{
message.Answers.Add(resource);
});

Mdns.SendAnswer(message, checkDuplicate: false);
Task.Delay(1000).Wait();
Mdns.SendAnswer(message, checkDuplicate: false);
}

/// <summary>
/// Sends a goodbye message for the provided
/// profile and removes its pointer from the name sever.
Expand Down
1 change: 1 addition & 0 deletions test/MulticastServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public void Can_Create()
{
var mdns = new MulticastService();
Assert.IsNotNull(mdns);
Assert.IsTrue(mdns.IgnoreDuplicateMessages);
}

[TestMethod]
Expand Down
99 changes: 99 additions & 0 deletions test/ServiceDiscoveryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,5 +454,104 @@ public void ResourceRecords()
}
}

[TestMethod]
public void Announce_ContainsSharedRecords()
{
var service = new ServiceProfile("z", "_sdtest-4._udp", 1024, new[] { IPAddress.Loopback });
var done = new ManualResetEvent(false);

var mdns = new MulticastService();
mdns.AnswerReceived += (s, e) =>
{
var msg = e.Message;
if (msg.Answers.OfType<PTRRecord>().Any(p => p.DomainName == service.FullyQualifiedName))
{
done.Set();
}
};
try
{
using (var sd = new ServiceDiscovery(mdns))
{
mdns.NetworkInterfaceDiscovered += (s, e) => sd.Announce(service);
mdns.Start();
Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(3)), "announce timeout");
}
}
finally
{
mdns.Stop();
}
}

[TestMethod]
public void Announce_ContainsResourceRecords()
{
var service = new ServiceProfile("z", "_sdtest-4._udp", 1024, new[] { IPAddress.Loopback });
var done = new ManualResetEvent(false);

var mdns = new MulticastService();
mdns.AnswerReceived += (s, e) =>
{
var msg = e.Message;
foreach (var r in service.Resources)
{
if (!msg.Answers.Contains(r))
{
return;
}
}
done.Set();
};
try
{
using (var sd = new ServiceDiscovery(mdns))
{
mdns.NetworkInterfaceDiscovered += (s, e) => sd.Announce(service);
mdns.Start();
Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(3)), "announce timeout");
}
}
finally
{
mdns.Stop();
}
}

[TestMethod]
public void Announce_SentTwice()
{
var service = new ServiceProfile("z", "_sdtest-4._udp", 1024, new[] { IPAddress.Loopback });
var done = new ManualResetEvent(false);
var nanswers = 0;
var mdns = new MulticastService
{
IgnoreDuplicateMessages = false
};
mdns.AnswerReceived += (s, e) =>
{
var msg = e.Message;
if (msg.Answers.OfType<PTRRecord>().Any(p => p.DomainName == service.FullyQualifiedName))
{
if (++nanswers == 2)
{
done.Set();
}
}
};
try
{
using (var sd = new ServiceDiscovery(mdns))
{
mdns.NetworkInterfaceDiscovered += (s, e) => sd.Announce(service);
mdns.Start();
Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(4)), "announce timeout");
}
}
finally
{
mdns.Stop();
}
}
}
}

0 comments on commit a6c5fa4

Please sign in to comment.