Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_services._dns-sd._udp.local. (find all service types) does not work #8

Open
ewmailing opened this issue Jun 8, 2018 · 11 comments
Open

Comments

@ewmailing
Copy link

According to the DNS-SD specification, _services._dns-sd._udp.local. is a special name for "Service Type Enumeration" which is supposed to find all service types on the network.

This is really useful for making debugging tools, such as making a Service Discovery browser.

Unfortunately, I am unable to get any results when I try plugging "_services._dns-sd._udp." (or "_services._dns-sd._udp") as the System.Devices.Dnsd.ServiceName in the aqsQueryString.

See this for the summary on this feature.
https://developer.apple.com/library/archive/qa/qa1337/_index.html

I've tested Bonjour, Avahi, and Android's Network Service Discovery, and they all handle this case correctly.

First, is there any way to get this to work? (Perhaps I need a change to the aqsQueryString?)

Second, if not, is there somebody to report this bug to, so this can be fixed?

Third, is there a different way I can get the list of available service types through a different means as a workaround?

@stammen
Copy link
Owner

stammen commented Jun 9, 2018

Thanks for your issue reporting. I am no longer supporting this repo. It was intended as sample code only. You can report issues with dnssd at https://wpdev.uservoice.com/. Thanks!

@stammen
Copy link
Owner

stammen commented Jun 13, 2018

@ewmailing We have filed a bug on this. The internal dev team will investigate.

@stammen
Copy link
Owner

stammen commented Jun 13, 2018

@ewmailing Did you try using _services._dns-sd._udp.local

@ewmailing
Copy link
Author

ewmailing commented Jun 13, 2018

Yes, I tried a lot of permutations including that one. I just retested the following variations (un/re)-commenting out the different lines:

        Vector<Platform::String^>^ propertyKeys = ref new Vector<Platform::String^>();
        propertyKeys->Append(L"System.Devices.Dnssd.ServiceName");
        propertyKeys->Append(L"System.Devices.Dnssd.InstanceName");
        propertyKeys->Append(L"System.Devices.Dnssd.Domain");
		
        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp.local.\"";
        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp.local\"";
        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp.\"";
        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp\"";

			aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp\" AND System.Devices.Dnssd.Domain:=\"local\"";

        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp\" AND System.Devices.Dnssd.Domain:=\"local.\"";
        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp.\" AND System.Devices.Dnssd.Domain:=\"local.\"";
        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:=\"_services._dns-sd._udp.\" AND System.Devices.Dnssd.Domain:=\"local\"";
	
			
        mServiceWatcher = DeviceInformation::CreateWatcher(aqsQueryString, propertyKeys, DeviceInformationKind::AssociationEndpointService);

Also out of desperation, I tried using instanceName for _services.

        //				aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.InstanceName:=\"_services\" AND System.Devices.Dnssd.ServiceName:=\"_dns-sd._udp\" AND System.Devices.Dnssd.Domain:=\"local\"";

			aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.InstanceName:=\"_services\" AND System.Devices.Dnssd.ServiceName:=\"_dns-sd._udp\"";

@stammen
Copy link
Owner

stammen commented Jul 11, 2018

The special query “_services._dns-sd._udp.local” is not currently supported by the WINRT APIs. The dev team is aware of this issue. I do not know when the fix will become available.

@smadasam
Copy link

smadasam commented Jul 17, 2018

Even though DNS-SD has a special meaning to these types of queries, the AQS filter is processed literally by the system on the results produced by the DNS-SD protocol plugin. The system does not have special understanding of the underlying protocols or device stacks Windows supports.

For instance, if a protocol accepts the filter (service==any) to mean return all services, but returns and object where serivce==foo, it will be filtered out because "foo" == "any" is literally evaluated to false.

Anyway if you want to get unblocked, here is a workaround. The filter is just a logical expression and is executed with short circuit evaluation. For instance, if exp1 always evaluates to true, then (exp1 || service=any) will also always evaluate true. service==any is not even evaluated. You can extend that further. If you actually wanted to add a real filter, you could write it like this (exp1 || service==any) && real_filter.

@ewmailing
Copy link
Author

Thank you for the response. Yes, I am interested in getting unblocked on this. But can you elaborate further on this because I think I've tried what you suggested but it's not working for me, so I am still missing something?

So my thinking was to simply remove the explicit queries on ServiceName, hoping I would by default capture everything. But that didn't work.

So I would omit the ServiceName part in the query like so:

aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.Domain:="local"";

But instead of getting all services on my network, I got nothing.

I also tried removing the Domain like so:

aqsQueryString = L"System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54}";

But that also returns nothing.

And I also tried both:
aqsQueryString = L"";
and
aqsQueryString = nullptr;

But that still returns nothing.

Is there some magic "any" keyword that I need to put into the query? (I just tried using literally "any" for my ServiceName, but that didn't work either.)

@smadasam
Copy link

I'll work on getting you an answer for Windows.Devices.Enumeration, but in the meantime, have you tried the DNS-SD watcher API?

https://docs.microsoft.com/en-us/uwp/api/windows.networking.servicediscovery.dnssd.dnssdservicewatcher

Seems like that might work better if that is just what you need.

@ewmailing
Copy link
Author

I have not tried it because I was scared off by all the "DnssdServiceWatcher is not supported and may be altered or unavailable in the future. Instead, use the Windows.Devices.Enumeration API" messages.

I just tried to use it, but I'm honestly really lost on how to use it. (I do not understand how to hook into the event callbacks, and my attempt to subclass it says I'm not allowed to use a sealed class type as a base class.) Do you have any examples on how to use it (C++/CX)?

I see nothing in the API that specifies parameters for what you are looking for. Is the idea that this classes's callback will trigger for all services of any name, which I then use to create my own list of service types?

@smadasam
Copy link

I think it will likely be there for the foreseeable future, so I would not be too worried. Ideally it would wrap the WDE (Windows.Devices.Enumeration) functionality to keep consistency and parity on the platform, but it looks like it calls into the network APIs directly.

How to hook up event handlers? Watchers and handlers are a common pattern in WinRT. The WDE sample has code for using a device watcher. Model that pattern.

I am not super familiar with the DNS-SD protocol, but this is working for me.
System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:="_sshsvc._tcp" AND System.Devices.Dnssd.Domain:="local"

and even

System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:="_sshsvc._tcp"

I found a bunch of XBOXes and IoT devices.

Using "_services._dns-sd._udp" as the service, I don't find anything with WDE. Using Win32 network APIs, it finds things, so maybe the old DnsSd API will work?

Using "_ipp._tcp" seems to work in WDE.

@ewmailing
Copy link
Author

ewmailing commented Jul 19, 2018

How to hook up event handlers? Watchers and handlers are a common pattern in WinRT. The WDE sample has code for using a device watcher. Model that pattern.

I see from the the WDE examples you linked to that adding a device is done like the example in this repo.

So quickly hacking this into the project in this repo, I think the following may work:

        mServiceWatcher2->Added += ref new TypedEventHandler<Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceWatcher ^, Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceInstance ^>(this, &DnssdServiceWatcher::OnServiceAdded2);

where

	  void  DnssdServiceWatcher::OnServiceAdded2(Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceWatcher ^ sender, Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceInstance ^ args)
{
}

And mServiceWatcher2 is defined as:

		        Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceWatcher^ mServiceWatcher2;

That part seems to get past the compiler, but my remaining problem is, how do I instantiate a Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceWatcher instance?

All the examples in WDE and this repo call some overloaded form DeviceInformation::CreateWatcher(), but this does not return a DnssdServiceWatcher instance. The following will fail to compile:

        mServiceWatcher2 = DeviceInformation::CreateWatcher();

Additionally, I have been unsuccessful with direct instantiation (compiler error).
mServiceWatcher2 = ref new Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceWatcher::DnssdServiceWatcher();

I am not super familiar with the DNS-SD protocol, but this is working for me.
System.Devices.AepService.ProtocolId:={4526e8c1-8aac-4153-9b16-55e86ada0e54} AND System.Devices.Dnssd.ServiceName:="_sshsvc._tcp" AND System.Devices.Dnssd.Domain:="local"

I'm not sure if we are misunderstanding each other here, so just to be clear , I am not having a problem with finding specific service types. That example and other ones like it work fine with the example in this repo and the UWP DNSSD in general. The problem I'm trying to get around is when I don't know the service types and I want to get a list of all service types on my current network. Since service types are decentralized and anybody can create an their own service type, I can't know ahead of time what service types to look for (_sshsvc, _ipp, etc).

Using a quick back of the envelope calculation, if I assumed 15 character names with upper case and lower case letters, digits, and underscores, and both udp and tcp service types, this would give me like 1e27 permutations to brute force search for.

So _services._dns-sd._udp is reserved as a special wildcard trigger for the DNS-SD service to return all actual service types on your network.

My original example for wanting this is so I could make a DNS-SD debugging tool (similar to the one I linked earlier). But that theoretical tool would show me all services on my network, not just the one for a single service type. So for example, if there was some service called _frungy._tcp that I've never heard of but is advertising on my network, this theoretical debugging tool would reveal it to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants