Publishing Services over mDNS in C

For some time now I’ve been looking into mDNS-advertised services. My aim was to advertise a service using mDNS in a C program.

Typically, doing this is really easy: call the Bonjour or Avahi APIs, and the system-wide daemon will do the rest for you. The problem arises when there is no system-wide daemon such as mDNSResponder (if you’re on a Mac or Windows) or Avahi (for the other OSes). This usually happens when you’re on an embedded system, like a router that runs Linux.

One way to solve this would be to cross-compile Avahi or Apple’s mDNSResponder for your platform. I chose another alternative – embedding a simple mDNS responder into the C program. Of course this implementation needs to be as lightweight as possible, meaning little or no external dependencies.

I thought it would be trivial to read the specifications and implement the mDNS protocol, but it turned out to be quite a bit of work. A few days into writing my own implementation, I found mdnsd written by Daniel Pelleg. I almost killed myself.

So here, I present my implementation that works – tinysvcmdns. To publish a service, you need only make 4 calls:

  1. mdnsd_start() to start the main thread
  2. mdnsd_set_hostname() to set the hostname and IP address
  3. mdnsd_register_svc() to register a service and begin an announcement
  4. mdnsd_stop() when you no longer need to respond to mDNS queries

It may be buggy, and it doesn’t do name collision detections, but it works. I hope to improve upon it as I use it in my project(s). tinysvcmdns is open-source, under the GNU LGPL “modified” BSD license (Update 2012-03-26: changed the software license).

mdnsd pretty much has a similar offering, but it implements features like name collision detection.

If you have the need to publish services over mDNS very simply, I hope you can benefit from this post, and will not re-invent the wheel like I did.

MIDI to USB (Serial) Converter

MIDI is actually just serial data at 31,250bps in 8N1 format that is transmitted over a 5-pin DIN cable. This means you can receive MIDI data from your musical instrument using a serial port, or an FTDI cable.

Receiving MIDI data over the FTDI cable doesn’t magically turn your USB serial device into a MIDI device – you need to be running a software bridge or a driver that pretends to be a virtual MIDI device emitting these messages. For this purpose, I shall use the Serial MIDI Converter from SpikenzieLabs.

I’m using Mac OS X 10.6.6 and the latest Java update, so I didn’t need any extra JAR files.

Wiring It Up

The circuit is relatively simple – you need the DIN socket, an opto-isolator, 2 resistors, and optionally a diode. In my case, parts came from a scrap bin, so I used a 330 ohm resistor instead of a 220 ohm for Rb and a 1K for Rd instead of 280 ohms. For the opto-isolator, element14 had some non-RoHS CNY17-2 on sale, so I just used that.

Note that the RXD output is only meant for interfacing with a TTL circuit like an FTDI chip/cable or MAX232 transceiver, not the RS232 serial port directly.

You can find the same circuit diagram (with different values & parts) in the official MIDI Electrical Specification Diagram.

Continue reading

mdns-repeater: mDNS across subnets

Update 21-Sep-2011: Added an Installation section and updated the binaries on Bitbucket.

Update 20-Oct-2020: Moved repository to GitHub

As you may know, I have a couple of Apple devices. Apple is fond of using Multicast DNS (mDNS) for their service discovery. The recent addition to these services being AirPrint (wireless printing service) and AirPlay (wireless audio/video streaming) from your iOS devices.

My home is setup in such a way that the wired and wireless networks are on 2 separate subnets. mDNS uses a multicast address that is “administratively scoped”, meaning the packets will not travel across subnets. I tried fiddling around with iptables rules and looked around for how I can route these packets across the subnets, but to no avail.

There is another solution – a repeater daemon that sits on the router and repeats packets between the 2 subnets. Avahi is used to provide mDNS services and it has a reflector mode that does exactly this. A more lightweight solution was TiVoBridge, which supposedly performs the same task but it’s much smaller. I tried to compile and set up TiVoBridge, but it required a config file and I couldn’t really get it to work the way I wanted it to. There’s an even lighter-weight solution called SAY, but it uses libpcap.

Enter mdns-repeater – a small Linux daemon that does exactly what I want it to do. I have a Linksys WRT54G which runs dd-wrt. This program was intended to be compiled for and installed on the Linksys router. As with all other programs that run on the router, it requires no configuration.

The default dd-wrt configuration has 2 interfaces – vlan1 for the WAN interface and br0 for the wireless interface (and 4-port switch). The program accepts the arguments vlan1 and br0 and begins repeating packets from vlan1 to br0 and vice-versa. I can now get my iOS devices to detect wired servers like a print server for AirPrint.

mdns-repeater is released under GPLv2. Feel free to change it to repeat whatever protocol you want. Patches to add functionality and bug fixes are welcome. You can contact me via bitbucket.orggithub.com, or if you clone the repository my email is in the commits.

Continue reading

Raw binary protocol analysis with Wireshark

I’m currently trying to analyze a binary protocol between 2 devices, but their communication does not occur over the network, neither can it be sniffed easily. Since this involves communication between 2 parties, I think the most apt software for analyzing such “conversations” would be Wireshark.

Wireshark allows for custom protocol dissectors. Writing such a dissector is usually done in C for speed, but I didn’t really want to setup the whole compilation environment to compile Wireshark. Fortunately, the Wireshark (Windows) binaries are compiled with Lua scripting support, which can also be used to write dissectors (although they run slower than C implementations).

Continue reading