From ec7edae1de32434a9b14b5953e60bf6150e6a50e Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 10 Oct 2019 11:28:25 +1300 Subject: [PATCH 1/6] feat(ServiceDiscovery): announce a new service --- src/ServiceDiscovery.cs | 35 +++++++++++++ test/ServiceDiscoveryTest.cs | 96 ++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/src/ServiceDiscovery.cs b/src/ServiceDiscovery.cs index 2ca89a0..823e308 100644 --- a/src/ServiceDiscovery.cs +++ b/src/ServiceDiscovery.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Common.Logging; using Makaretu.Dns.Resolving; @@ -256,6 +257,40 @@ public void Advertise(ServiceProfile service) catalog.IncludeReverseLookupRecords(); } + /// + /// Sends an unsolicited MDNS response describing the + /// service profile. + /// + /// + /// The profile to describe. + /// + /// + /// Sends a MDNS response containing the pointer + /// and resource records of the . + /// + /// To provide increased robustness against packet loss, + /// two unsolicited responses are sent one second apart. + /// + /// + 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); + Task.Delay(1000).Wait(); + Mdns.SendAnswer(message); + } + /// /// Sends a goodbye message for the provided /// profile and removes its pointer from the name sever. diff --git a/test/ServiceDiscoveryTest.cs b/test/ServiceDiscoveryTest.cs index 21287ae..d65123e 100644 --- a/test/ServiceDiscoveryTest.cs +++ b/test/ServiceDiscoveryTest.cs @@ -454,5 +454,101 @@ 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().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(1)), "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(1)), "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(); + mdns.AnswerReceived += (s, e) => + { + var msg = e.Message; + if (msg.Answers.OfType().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(2)), "announce timeout"); + } + } + finally + { + mdns.Stop(); + } + } } } From 856ac8bf6c820e7f3d408fdd54fee011f1f2515d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 10 Oct 2019 11:35:52 +1300 Subject: [PATCH 2/6] test(ServiceDiscovery.Announce): wait at leasr 3 seconds for failure --- test/ServiceDiscoveryTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/ServiceDiscoveryTest.cs b/test/ServiceDiscoveryTest.cs index d65123e..92279ab 100644 --- a/test/ServiceDiscoveryTest.cs +++ b/test/ServiceDiscoveryTest.cs @@ -475,7 +475,7 @@ public void Announce_ContainsSharedRecords() { mdns.NetworkInterfaceDiscovered += (s, e) => sd.Announce(service); mdns.Start(); - Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "announce timeout"); + Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(3)), "announce timeout"); } } finally @@ -509,7 +509,7 @@ public void Announce_ContainsResourceRecords() { mdns.NetworkInterfaceDiscovered += (s, e) => sd.Announce(service); mdns.Start(); - Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "announce timeout"); + Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(3)), "announce timeout"); } } finally @@ -542,7 +542,7 @@ public void Announce_SentTwice() { mdns.NetworkInterfaceDiscovered += (s, e) => sd.Announce(service); mdns.Start(); - Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(2)), "announce timeout"); + Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(3)), "announce timeout"); } } finally From 41647b101a5b34beb63fbd5cf23bef8dd93c459d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 10 Oct 2019 11:40:57 +1300 Subject: [PATCH 3/6] fix(ServiceDiscovery): always send announce message --- src/ServiceDiscovery.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ServiceDiscovery.cs b/src/ServiceDiscovery.cs index 823e308..f2b3175 100644 --- a/src/ServiceDiscovery.cs +++ b/src/ServiceDiscovery.cs @@ -286,9 +286,9 @@ public void Announce(ServiceProfile profile) message.Answers.Add(resource); }); - Mdns.SendAnswer(message); + Mdns.SendAnswer(message, checkDuplicate: false); Task.Delay(1000).Wait(); - Mdns.SendAnswer(message); + Mdns.SendAnswer(message, checkDuplicate: false); } /// From 9c9ad3a17d9aa2c611daf2610ae0d71fe2383a75 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 11 Oct 2019 12:53:55 +1300 Subject: [PATCH 4/6] feat(MulticastService): enable/disable ignoring duplicate message --- src/MulticastService.cs | 13 +++++++++++++ test/MulticastServiceTest.cs | 1 + test/ServiceDiscoveryTest.cs | 5 ++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/MulticastService.cs b/src/MulticastService.cs index afae2cb..023dd27 100644 --- a/src/MulticastService.cs +++ b/src/MulticastService.cs @@ -132,6 +132,7 @@ public MulticastService(Func, IEnumerable @@ -150,6 +151,18 @@ public MulticastService(Func, IEnumerable public bool UseIpv6 { get; set; } + /// + /// Determines if received messages are checked for duplicates. + /// + /// + /// true to ignore duplicate messages. Defaults to true. + /// + /// + /// When set, a message that has been received within the last minute + /// will be ignored. + /// + public bool IgnoreDuplicateMessages { get; set; } + /// /// The interval for discovering network interfaces. /// diff --git a/test/MulticastServiceTest.cs b/test/MulticastServiceTest.cs index 9c25936..93e3a15 100644 --- a/test/MulticastServiceTest.cs +++ b/test/MulticastServiceTest.cs @@ -19,6 +19,7 @@ public void Can_Create() { var mdns = new MulticastService(); Assert.IsNotNull(mdns); + Assert.IsTrue(mdns.IgnoreDuplicateMessages); } [TestMethod] diff --git a/test/ServiceDiscoveryTest.cs b/test/ServiceDiscoveryTest.cs index 92279ab..f1cf84b 100644 --- a/test/ServiceDiscoveryTest.cs +++ b/test/ServiceDiscoveryTest.cs @@ -524,7 +524,10 @@ 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(); + var mdns = new MulticastService + { + IgnoreDuplicateMessages = false + }; mdns.AnswerReceived += (s, e) => { var msg = e.Message; From 246fcfc394439b885fca2ed793693262c3d6bb0e Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 11 Oct 2019 13:04:47 +1300 Subject: [PATCH 5/6] test(ServiceDiscovery.Announce): better timeout --- test/ServiceDiscoveryTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ServiceDiscoveryTest.cs b/test/ServiceDiscoveryTest.cs index f1cf84b..db9ea75 100644 --- a/test/ServiceDiscoveryTest.cs +++ b/test/ServiceDiscoveryTest.cs @@ -545,7 +545,7 @@ public void Announce_SentTwice() { mdns.NetworkInterfaceDiscovered += (s, e) => sd.Announce(service); mdns.Start(); - Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(3)), "announce timeout"); + Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(4)), "announce timeout"); } } finally From cbb8df2561c8f95d62dccb5aeaedbf2dffb27616 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 11 Oct 2019 13:47:56 +1300 Subject: [PATCH 6/6] feat(MulticastService): implement ignoring duplicate message --- src/MulticastService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MulticastService.cs b/src/MulticastService.cs index 023dd27..e10ebce 100644 --- a/src/MulticastService.cs +++ b/src/MulticastService.cs @@ -632,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; }