diff --git a/src/Mdns.csproj b/src/Mdns.csproj
index b713e58..368893a 100644
--- a/src/Mdns.csproj
+++ b/src/Mdns.csproj
@@ -20,10 +20,9 @@
A simple Multicast Domain Name Service based on RFC 6762. Can be used as both a client (sending queries) or a server (responding to queries).
false
https://github.com/richardschneider/net-mdns/releases
- © 2018 Richard Schneider
+ © 2018-2019 Richard Schneider
multicast mdns dns zeroconf
True
- https://github.com/richardschneider/net-mdns/blob/master/LICENSE
https://github.com/richardschneider/net-mdns
@@ -34,7 +33,7 @@
-
+
diff --git a/src/MulticastService.cs b/src/MulticastService.cs
index 2a9a348..287a137 100644
--- a/src/MulticastService.cs
+++ b/src/MulticastService.cs
@@ -364,7 +364,7 @@ void checkResponse(object s, MessageEventArgs e)
///
/// When the service has not started.
///
- public void SendQuery(string name, DnsClass klass = DnsClass.IN, DnsType type = DnsType.ANY)
+ public void SendQuery(DomainName name, DnsClass klass = DnsClass.IN, DnsType type = DnsType.ANY)
{
var msg = new Message
{
@@ -401,7 +401,7 @@ public void SendQuery(string name, DnsClass klass = DnsClass.IN, DnsType type =
///
/// When the service has not started.
///
- public void SendUnicastQuery(string name, DnsClass klass = DnsClass.IN, DnsType type = DnsType.ANY)
+ public void SendUnicastQuery(DomainName name, DnsClass klass = DnsClass.IN, DnsType type = DnsType.ANY)
{
var msg = new Message
{
diff --git a/src/ServiceDiscovery.cs b/src/ServiceDiscovery.cs
index 1a88698..2ca89a0 100644
--- a/src/ServiceDiscovery.cs
+++ b/src/ServiceDiscovery.cs
@@ -14,6 +14,8 @@ namespace Makaretu.Dns
public class ServiceDiscovery : IDisposable
{
static readonly ILog log = LogManager.GetLogger(typeof(ServiceDiscovery));
+ static readonly DomainName LocalDomain = new DomainName("local");
+ static readonly DomainName SubName = new DomainName("_sub");
///
/// The service discovery service name.
@@ -21,7 +23,8 @@ public class ServiceDiscovery : IDisposable
///
/// The service name used to enumerate other services.
///
- public const string ServiceName = "_services._dns-sd._udp.local";
+ public static readonly DomainName ServiceName = new DomainName("_services._dns-sd._udp.local");
+
readonly bool ownsMdns;
List profiles = new List();
@@ -101,7 +104,7 @@ public ServiceDiscovery(MulticastService mdns)
/// Use to initiate a DNS-SD question.
///
///
- public event EventHandler ServiceDiscovered;
+ public event EventHandler ServiceDiscovered;
///
/// Raised when a servive instance is discovered.
@@ -162,9 +165,9 @@ public void QueryUnicastAllServices()
/// When an answer is received the event is raised.
///
///
- public void QueryServiceInstances(string service)
+ public void QueryServiceInstances(DomainName service)
{
- Mdns.SendQuery(service + ".local", type: DnsType.PTR);
+ Mdns.SendQuery(DomainName.Join(service, LocalDomain), type: DnsType.PTR);
}
///
@@ -180,9 +183,14 @@ public void QueryServiceInstances(string service)
/// When an answer is received the event is raised.
///
///
- public void QueryServiceInstances(string service, string subtype)
+ public void QueryServiceInstances(DomainName service, string subtype)
{
- Mdns.SendQuery($"{subtype}._sub.{service}.local", type: DnsType.PTR);
+ var name = DomainName.Join(
+ new DomainName(subtype),
+ SubName,
+ service,
+ LocalDomain);
+ Mdns.SendQuery(name, type: DnsType.PTR);
}
///
@@ -196,9 +204,9 @@ public void QueryServiceInstances(string service, string subtype)
/// When an answer is received the event is raised.
///
///
- public void QueryUnicastServiceInstances(string service)
+ public void QueryUnicastServiceInstances(DomainName service)
{
- Mdns.SendUnicastQuery(service + ".local", type: DnsType.PTR);
+ Mdns.SendUnicastQuery(DomainName.Join(service, LocalDomain), type: DnsType.PTR);
}
///
@@ -231,7 +239,10 @@ public void Advertise(ServiceProfile service)
{
var ptr = new PTRRecord
{
- Name = $"{subtype}._sub.{service.QualifiedServiceName}",
+ Name = DomainName.Join(
+ new DomainName(subtype),
+ SubName,
+ service.QualifiedServiceName),
DomainName = service.FullyQualifiedName
};
catalog.Add(ptr, authoritative: true);
@@ -289,9 +300,10 @@ void OnAnswer(object sender, MessageEventArgs e)
}
// Any DNS-SD answers?
+
var sd = msg.Answers
.OfType()
- .Where(ptr => ptr.Name.EndsWith(".local"));
+ .Where(ptr => ptr.Name.IsSubdomainOf(LocalDomain));
foreach (var ptr in sd)
{
if (ptr.Name == ServiceName)
@@ -364,6 +376,11 @@ void OnQuery(object sender, MessageEventArgs e)
response.AdditionalRecords.Clear();
}
+ if (!response.Answers.Any(a => a.Name == ServiceName))
+ {
+ ;
+ }
+
if (QU)
{
// TODO: Send a Unicast response if required.
diff --git a/src/ServiceInstanceDiscoveryEventArgs.cs b/src/ServiceInstanceDiscoveryEventArgs.cs
index 0724fde..3d70251 100644
--- a/src/ServiceInstanceDiscoveryEventArgs.cs
+++ b/src/ServiceInstanceDiscoveryEventArgs.cs
@@ -17,7 +17,7 @@ public class ServiceInstanceDiscoveryEventArgs : MessageEventArgs
/// Typically of the form "instance._service._tcp.local".
///
///
- public string ServiceInstanceName { get; set; }
+ public DomainName ServiceInstanceName { get; set; }
}
}
diff --git a/src/ServiceInstanceShutdownEventArgs.cs b/src/ServiceInstanceShutdownEventArgs.cs
index 20e12c2..b116418 100644
--- a/src/ServiceInstanceShutdownEventArgs.cs
+++ b/src/ServiceInstanceShutdownEventArgs.cs
@@ -17,7 +17,7 @@ public class ServiceInstanceShutdownEventArgs : MessageEventArgs
/// Typically of the form "instance._service._tcp.local".
///
///
- public string ServiceInstanceName { get; set; }
+ public DomainName ServiceInstanceName { get; set; }
}
}
diff --git a/src/ServiceProfile.cs b/src/ServiceProfile.cs
index 27f1e2e..3fdf652 100644
--- a/src/ServiceProfile.cs
+++ b/src/ServiceProfile.cs
@@ -50,17 +50,18 @@ public ServiceProfile()
///
/// The SRV, TXT and A/AAAA resoruce records are added to the .
///
- public ServiceProfile(string instanceName, string serviceName, ushort port, IEnumerable addresses = null)
+ public ServiceProfile(DomainName instanceName, DomainName serviceName, ushort port, IEnumerable addresses = null)
{
InstanceName = instanceName;
ServiceName = serviceName;
var fqn = FullyQualifiedName;
- var simpleServiceName = ServiceName
+ var simpleServiceName = new DomainName(ServiceName.ToString()
.Replace("._tcp", "")
.Replace("._udp", "")
- .TrimStart('_');
- HostName = $"{InstanceName}.{simpleServiceName}.{Domain}";
+ .Trim('_')
+ .Replace("_", "-"));
+ HostName = DomainName.Join(InstanceName, simpleServiceName, Domain);
Resources.Add(new SRVRecord
{
Name = fqn,
@@ -85,7 +86,7 @@ public ServiceProfile(string instanceName, string serviceName, ushort port, IEnu
///
/// Always "local".
///
- public string Domain { get; } = "local";
+ public DomainName Domain { get; } = "local";
///
/// A unique name for the service.
@@ -101,7 +102,7 @@ public ServiceProfile(string instanceName, string serviceName, ushort port, IEnu
/// The second label is either "_tcp" (for application
/// protocols that run over TCP) or "_udp" (for all others).
///
- public string ServiceName { get; set; }
+ public DomainName ServiceName { get; set; }
///
/// A unique identifier for the service instance.
@@ -109,7 +110,7 @@ public ServiceProfile(string instanceName, string serviceName, ushort port, IEnu
///
/// Some unique value.
///
- public string InstanceName { get; set; }
+ public DomainName InstanceName { get; set; }
///
/// The service name and domain.
@@ -117,7 +118,7 @@ public ServiceProfile(string instanceName, string serviceName, ushort port, IEnu
///
/// Typically of the form "_service._tcp.local".
///
- public string QualifiedServiceName => $"{ServiceName}.{Domain}";
+ public DomainName QualifiedServiceName => DomainName.Join(ServiceName, Domain);
///
/// The fully qualified name of the instance's host.
@@ -126,7 +127,7 @@ public ServiceProfile(string instanceName, string serviceName, ushort port, IEnu
/// This can be used to query the address records (A and AAAA)
/// of the service instance.
///
- public string HostName { get; set; }
+ public DomainName HostName { get; set; }
///
/// The instance name, service name and domain.
@@ -134,7 +135,8 @@ public ServiceProfile(string instanceName, string serviceName, ushort port, IEnu
///
/// ..
///
- public string FullyQualifiedName => $"{InstanceName}.{QualifiedServiceName}";
+ public DomainName FullyQualifiedName =>
+ DomainName.Join(InstanceName, ServiceName, Domain);
///
/// DNS resource records that are used to locate the service instance.
diff --git a/test/MulticastServiceTest.cs b/test/MulticastServiceTest.cs
index d136cfa..d868ab9 100644
--- a/test/MulticastServiceTest.cs
+++ b/test/MulticastServiceTest.cs
@@ -169,6 +169,7 @@ public async Task ReceiveLegacyUnicastAnswer()
mdns.Start();
Assert.IsTrue(ready.WaitOne(TimeSpan.FromSeconds(1)), "ready timeout");
await client.SendAsync(packet, packet.Length, "224.0.0.251", 5353);
+
var r = await client.ReceiveAsync();
var response = new Message();
response.Read(r.Buffer, 0, r.Buffer.Length);
diff --git a/test/ServiceProfileTest.cs b/test/ServiceProfileTest.cs
index 4f0f95e..9a7f009 100644
--- a/test/ServiceProfileTest.cs
+++ b/test/ServiceProfileTest.cs
@@ -102,5 +102,15 @@ public void Subtypes()
var service = new ServiceProfile("x", "_sdtest._udp", 1024);
Assert.AreEqual(0, service.Subtypes.Count);
}
+
+ [TestMethod]
+ public void HostName()
+ {
+ var service = new ServiceProfile("fred", "_foo._tcp", 1024);
+ Assert.AreEqual("fred.foo.local", service.HostName);
+
+ service = new ServiceProfile("fred", "_foo_bar._tcp", 1024);
+ Assert.AreEqual("fred.foo-bar.local", service.HostName);
+ }
}
}