Front-end mDNS: announcing and finding network services with JavaScript

Multicast DNS (or mDNS) lets you announce a service you're offering in the network you're connected to, and other devices can find (discover) it. For example, you could announce that your computer is running an FTP service. It's the same thing that Apple does with its Bonjour protocol and that's how you can find printers without knowing their IP address: they broadcast their existence, and your computer picks it up automatically for you.

Services have to be registered with a domain ending in .local. E.g. _ssh._tcp.local. The Wikipedia page has some background on why.

However, the title of this post has "front-end" on it, and that's because I wanted to talk about dns-sd.js, a library that lets you both register and discover services in the network. It's all written in JavaScript so it can run on a browser environment, in this case Firefox OS.

It uses some Firefox OS-only APIs such as mozTCPSocket, so it only runs on Gecko/Gaia environments, but I'm sure it could be modified to work on other environments if they exposed a similar functionality in JS.

Suppose you're running an echo server in your Firefox OS phone, and want to announce it to other peers in your network. An Echo server just replies with the same data you sent it, so it's a good way to get started with writing a network server :-)

The following is how we would announce and discover said server:

Permissions (for the server and the client apps)

The first thing you need to do is to ensure you're asking for the proper permissions for your app in the manifest.webapp file. dns-sd.js requires permission to use TCP and UDP sockets, so make sure the permissions field looks at least like this:


{
  "tcp-socket": {},
  "udp-socket": {}
}

Otherwise you'll get errors such as "UDPSocket is not defined".

Loading the library (both server and clients)

Grab dns-sd.js from the dist folder in the repository, and include it in your app, before any code that uses it. For example, you could use something like this in the head section:


<script src="js/lib/dns-sd/dns-sd.js" defer></script>
<script src="js/app.js" defer></script>

It will register a window.DNSSD object, so you can just refer to it as DNSSD.

Registering / announcing your service (for the server)

To announce the service, we would do this:


DNSSD.registerService('_echo._tcp.local', 7, {});

Finding echo servers in the network (for the clients)

We could use Justin's DNS browser example to make sure the service is found by other clients in the network:

Or we could set up a discovered listener and start the discovery process:


DNSSD.addEventListener('discovered', function(evt) {
  // A service broadcast event was received
  // i.e. we "discovered" something new
});

DNSSD.startDiscovery();

Each discovered event is associated to a host with an IP address. A host can evidently send multiple updates, as services are enabled/disabled.

Right now dns-sd.js only provides you with a list of service names in the host, but not the ports, so you might need to either deduct or hardcode them ;-) I filed a bug for this.

The most interesting bits of data in the discovered events are:

  • address - the address of the host which is exposing services
  • services - an array with the names of the services in the host

So if we were looking for echo servers, we should look at the list of services each time we get an update from a host:


var echoServices = event.services.filter(function(service) {
  return service.match('echo');
});

And we would have a list of hosts running echo services in echoServices!