Wednesday, December 23, 2009

Bonjour Monsieur Linux

I was poking around with mDNSResponder the other day. mDNSResponder is the library code and daemon implementation for mDNS (multicast DNS, also known as "zero-conf") and DNS-SD (DNS service discovery), sometimes known as "Bonjour". I have no idea which of these terms is a trademark, a technology, an implementation, or a slur. I'll go with mDNS and DNS-SD.

If you use a Mac, you've seen mDNS in that your computers sometimes grow weird names like macbookpro.local. Surprisingly, these names work as well as DNS names like www.google.com. You can ping them or gethostbyname on m.

Those names come from mDNS - that is, they are part of a distributed naming domain "local" that is jointly managed by all mDNS-enabled computers on the local net. These domain names are only transparent to the unix shell because naming services on OS X knows about them.

If you have shared your music with iTunes, you're using DNS-SD - that is, iTunes publishes a "service" (music sharing) using DNS-SD and then searches for other music databases the same way.

The DNS-SD C API and code that run below it are all open source, so it is possible to create cross-platform service discovery code. If you try to do this, you will have to pick one of two models:
  • Run the DNS-SD daemon (if it doesn't already run) and use the DNS-SD API that uses IPC to talk to the daemon. This configuration is what Apple ships for OS X - the efficiency comes from having only one copy of cached DNS-SD data.
  • Compile the DNS-SD network implementation (which is normally in the daemon) into your app directly; Apple recommends this only for embedded systems.
Here are my two tips if you want to try to make this work - that is, this is what kept me up until 4 AM. (Hint: 4 am = stupid...I really solved the bugs the next day after having had a cup of coffee and some sleep.)
  1. You can't use gethostbyname to resolve a host into an IP address, despite what Apple's docs say - this only works on platforms like OS X that support mDNS host names "natively".

    The normal flow of operations is to browse for services, "resolve" them to hosts. On a non-Mac platform you need to do a third mDNS operation: use mDNS to resolve the host to an IP address using something like DNSServiceQueryRecord (with a record type of kDNSServiceType_A to convert the host to an address).

  2. If you are compiling the mDNS library into your app, you need to initialize it with mDNS_Init_AdvertiseLocalAddresses. This flag will tell mDNS to publish a mapping of your dynamic host name (my_machine.local or whatever) to your actual IP address for each interface.

    If you do not publish, other machines will be able to find and resolve your service, but will fail to then convert your host to an IP. You will be able to get their IPs though. This bug can be masked on OS X, which always publishes itself since you use DNS-SD in daemon form.


No comments:

Post a Comment