DNS Based Service Discovery (DNSSD)

So lately I have been doing a lot of research into DNSSD. Here are my findings including but not limited to an explanation of what DNSSD is, how it can be used in .NET development with code samples, and a list of external resources.

What is DNSSD?
In the simplest terms DNSSD is a method of service discovery that is based upon one of the most well known and widely used lookup protocols. DNSSD is robust enough that if setup properly it could have a use on the internet. However I am only going to be discussing LAN usage where DNSSD truly shines.

Zeroconf
DNSSD is most widely known as one of the major components of Zeroconf networking. Zeroconf networking is a set of technologies that allow two or more computers to communicate with each other without any external configuration. Zeroconf is a whole different topic though that hopefully we can cover later. If you would like more information about Zeroconf check out http://www.zeroconf.org. It isn’t the most exciting read but it is all there!

Why use DNSSD?
Service Discovery is an interesting problem that usually goes something like this. You have an application that is capable of communicating P2P(Chat, File Sharing, Printer Sharing, Distributed Computing). It is a non-standard application (possibly only for your own personal or corporate use) so you don’t want or need to get a TCP port set aside. A number of machines are going to be running this application and there is a need to dynamically discover which machines these are and on what port they are expecting to communicate with their peers.

The first thought that generally comes to mind is to set aside one machine to act as a registration server that all of the peers running the application occasionally ping to inform the server that they are online. Although this method works very well in many instances it turns a decentralized p2p system into a semi-centralized p2p system. Meaning that if the “server” went offline the P2P “sessions” currently in progress would continue to work however no new “sessions” could be initiated without the help of the registration server.

DNSSD with the help of multicast DNS is able to clear up this issue. As defined on multicastdns.org “Multicast DNS is a way of using familiar DNS programming interfaces, packet formats and operating semantics, in a small network where no conventional DNS server has been installed.” DNSSD is not dependant on the multicast DNS technology, meaning service discovery with DNSSD can be done with a traditional DNS server setup however we must use the multicast DNS technology in order to eliminate the need for a DNS server in our quest for decentralization.

How do you implement DNSSD?
Although DNSSD is not just an Apple technology it is well known that Apple is the largest advocate and implementer of DNSSD and Zeroconf technology. For this reason Apple is the single greatest resource for DNSSD development.

Apple’s Bonjour
Bonjour is a Apple’s answer to Zeroconf management. It provides a framework for using DNSSD and it is where I have done most of my experimentation with DNSSD. Bonjour offers a version for Windows as well as a Windows SDK.

Example #1
The first example that I am going to give shows how to use the console application that you can find at c:\program files\bonjour sdk\samples\c\dns-sd.exe once you install the Bonjour SDK for Windows.

Execute the following commands as shown below in a dos prompt.


click for larger view

Keep your command prompt open. Now if you have iTunes on another machine on the same LAN open it up and check your preferences to see if you have look for shared music checked. If so then you should see a shared library titled “test” in your left menu. That’s right….iTunes being an Apple product is probably one of the most highly exposed practical applications of DNSSD.

To watch the magic happen in real time you can create and drop this registration by doing the following:

Return to the previously used command prompt window. You should still see “Got a reply for test._daap._tcp.local.: Name now registered and active” as the last line.

Press CTRL+C which will end the program

Your iTunes “test” library will disappear almost instantaneously.

Now press the up key on your keyboard to get the last executed command back and press enter…

Repeat the last few steps until your satisfied!

WARNING: I did this quite a few times before I got bored of watch it magically appear and disappear, can be quite addictive ;-)

So what was that all about?
That was probably the most simplified example of DNSSD experimentation that I could start off with. I am sure that everyone probably tried to click on the library in iTunes and iTunes was quick to tell them that there is no library available at that location.

In order to dissect what we actually just did lets first take a look at the command that we executed in order to make it all happen.

dns-sd -R test _daap._tcp . 1234

dns-sd
is of course the program name that we are executing.

-R
is the switch that we are passing to the program in order to let it know what exactly we are trying to do. A full list of switches is available by simply executing “dns-sd” without any parameters. -R in this case stands for register, because we are registering a DNS entry. “-R” takes in a command line that is formatted like so:
dns-sd -R “name” “type” “domain” “port” ["txt"…]

test
is the name that we are giving our instance of this particular service we are registering

_daap._tcp
is the Type of service that we are registering. In our example we are using “_daap._tcp” because this is apples reserved name for iTunes sharing. (I believe it stands for Digital Audio Access Protocol).

.
we pass a period in as the domain in order to simply choose our local machine

1234
is the port number that I randomly made up for our imaginary iTunes shared library.

It is also important to note that there is an optional TXT parameter that we neglected to pass in this instance. A DNS TXT record can be up to 65535 (0xFFFF) bytes long and it is used in DNSSD to pass additional information about the service that is being offered. An example taken from the DNSSD specifications suggests that printing via the LPR protocol often specifies a short queue name and the TXT parameter is good place for that type of information.

So ok I can make a fake library in iTunes…how is this going to help me?
Well when it comes to basic examples the iTunes trick is about as simple as you can get. This next example is going to be more practical and hopefully it will give some ideas as to how you can use this in your own application.

Example #2
In this example we will cover how to discover services that are being exposed via DNSSD. Using the same dns-sd.exe program we will pass in a -B for browse.

First off you are going to have to go through example one and register a service on your machine. You can modify the service instance name and type if wanted or just leave it the same. For the sake of consistency I am going to leave it the same in this example.

The next thing you need to do is start up another command prompt. This is where you are going to do the browsing and you can do this on either the same machine or from another machine on your network.

Execute the following commands as shown in command window below:


click for larger view

You should get something similar to the output you are seeing above. However please note that I have my command window set smaller than the output so it is wrapping.

The interesting thing here is that it is showing the broadcasted service from your other command window. If you CTRL+C the window that is broadcasting (the other window), you will notice that on this window a new record will be added and it will look similar to this next shot.


click for larger view

Notice that the first record was for adding a record so in the A/R column you will see where the record was added and then later removed. Hopefully this is starting to make practical sense by now?

Example #3
In example three I am going to cover a small application that I wrote that basically wraps around the browse function examined in Example #2. The example is written in C# and although there is a .Net component that is still being worked on I wasn’t aware of this when I was working on this wrapper code. Hopefully the .Net component will be finished up and deployed soon.

//The method that handles the click of the start button
private void startButton_Click(object sender, System.EventArgs e)
{
//define a new threadstart
ThreadStart job = new ThreadStart(threadJob);
//define a new thread
Thread = new Thread(job);
//start the thread
thread.Start();
}

//the thread method
private void threadJob()
{
//create a new process object
Process = new Process();
//don't use shell execute
process.StartInfo.UseShellExecute = false;
//we are redirecting the standard output here and then we get it later
process.StartInfo.RedirectStandardOutput = true;
//don't create a console window that pops up…it is not needed
process.StartInfo.CreateNoWindow = true;
//here is the file that we want to execute
process.StartInfo.FileName = "C:\\Program Files\\Bonjour SDK\\samples\\C\\dns-sd.exe";
//here are the parameters we want to pass it
process.StartInfo.Arguments = "-B _daap._tcp. .";
//here we set the working directory
process.StartInfo.WorkingDirectory = "C:\\Program Files\\Bonjour SDK\\samples\\C";
//go ahead and start the process
process.Start();
//create an instance of stream reader and get the standard output from the process
StreamReader myStreamReader = process.StandardOutput;

//create a blank string for later user
string str = "";
//while the process has not executed run the following
while( !process.HasExited )
//while we can still peak and see something in the outputstream run this
while( myStreamReader.Peek().ToString() != string.Empty )
{
//assign the next line that is read to str
str = myStreamReader.ReadLine();
//if the line starts with a T that means we are dealing with the header
//line that is printed on the console and we don't want to process
if (str.Substring(0,1) != "T")
{
//create an array of strings called x and use a regular expression //to split up the output line by whitespace
string[] x = Regex.Split (str.Trim(), @"\s+");
//if there are 7 items in the array created from split proceed
if (x.Length == 7)
{
//If the second item (index of 1) reads "Add" proceed //otherwise bounce to else
if(x[1] == "Add")
{
//Add the instance to the combo box
comboBox1.Items.Add(x[6]);
}
else
{
//Remove the instance from the combo box
comboBox1.Items.Remove(x[6]);
}

}
}
}
}

//close the process
process.Close();
}

So basically what the above piece of code does is create a thread the constantly checks the standardoutput of the “dns-d.exe -B _daap._tcp. .” command. If it detects output that states that a new instance is added or removed it adds or removes the record from the combo box. This is a very trivial example but with something like this you could have a drop down that allows a user to select another pc that is available to interface with software you have running.

IMPORTANT:
Since it is in a thread it is possible that you could sleep the thread for any amount of time you desire in order to preserve precious processing power, however I must note that you won’t even notice that it is checking if you don’t decide to sleep it.

Example #4
The last example simply shows how we can do a simple query to find out more information on a particular instance of a service that we discover is available. Once we get the instance name by using the -B switch we are able to use the instance name to find more details by using the -L switch. The following example gives us an example as to how the query and results will look.


click for larger view

Almost identical to the -B switch except the -L switch wants us to specify an instance name before the type and domain information. (The instance name is “test” in our example. )

Hopfully this information is useful to someone and I would love to know if anyone who reads this will decide to apply this knowledge to a real application. So feel free to contact me via comment!

There are not a whole lot of good resources but the two that I will point you to for more information are the specs for dns-sd and zeroconf:

http://www.dns-sd.org
http://www.zeroconf.org

If anyone is interested in learning more about ZeroConf let me know! I am considering writing an article on the topic and knowing that it may be useful to some might be a nice incentive!

Also please contact me with any questions about this article or mistakes it may have in it ;-)

10 Responses to “DNS Based Service Discovery (DNSSD)”

  1. Mark Van Dyke on June 13th, 2005 at 9:43 am

    Pretty cool! I was not aware of this technology. You did a good job of breaking it down.

  2. Good jarb with the article. We need to finish the program.

  3. WOW, you look like your mom! Hey Ryan, this might be freaky, but I am an old friend of Tina Michelle Finnerty’s, actually Tamela Suzanne as well… Julie from Florida…

    Give your mom my email address and have her write me, ok???

  4. My company is thinking about using Bonjour for its new video codec product. I would be very interested in any more info you have on it!

  5. Thank you so much for posting this tutorial! I’ve been trying to find a way to use bonjour in Visual C++ .net 2005 (non console application) and with minor modifications it worked like a charm.

  6. Great articale on DNS-SD – the best I’ve found oustide Stuart Cheshire’s book.

    You referred to a .NET component – is this project still alive ?

    Henry

  7. I have been working on a library for use in production systems. If anyone is interested in beta testing it and/or licensing it for commercial systems please let me know.

  8. Thanks for this, very useful.

  9. Much more helpful as a startup guide than the docs that come with dns-sd! Thanks, confidence in own sanity restored.

  10. [...] DNS Based Service Discovery (DNSSD). [...]

Leave a Reply