So you’re writing an application. At some point, you have a problem where you want to be able to talk to an instance of your program while it’s running. It turns out, this is fiendishly difficult for Free Unix-based desktops, and many programs get it wrong. On my Fedora 9 system, looking in /tmp, I see listings like gconfd-walters (GConf), hsperfdata_walters (OpenJDK), pulse-walters (Pulseaudio), emacs500 (GNU Emacs). All of these programs are broken. The root cause of this is the failure of Unix to provide a standard per-user, per-machine temporary directory. If we had that, things would be dramatically simpler, but we don’t.
You can’t use /tmp because it’s not per-user. Any time you rely on a well-known name in /tmp (like the above list), your application is subject to denial-of-service attacks if another user creates that file before you log in. Security aside, it’s also just harder to deal with because you have to check for whether or not the data in your temporary directory is stale or not (is something listening on that socket, or is it left over from a session crash?), and that’s yet more painful code.
You can’t use $HOME because it’s not per-machine (think of all the sites that subject users to the pain of NFS), and won’t always support Unix domain socket files.
Now, there are other solutions; you can use the X server, which is what Firefox does I believe. If your application is single-instance this isn’t too bad, but there is an easier way:
Enter solution: DBus
The best solution is to use DBus. The key feature here is that the DBus session bus provides exactly what we want: a per-user, per-machine namespace, as well as a fairly sane IPC system we can use to pass messages. Here’s how you use it.
- Decide on a service name for your application. For the purposes of this discussion, we’ll call it org.openssh.Ssh, for no particular reason.
- In your application startup, try to acquire this name on the session bus, using DBus. If you’re successful, your application can now provide a service. To pick a completely random example, this service might be multiplexing SSH connections. If something else already owns the service, then you can act as a client; you might send the message org.openssh.GetControlMasterSocketPath to return the path to another Unix-domain socket, because your application has a non-DBus protocol for communication.
In this example, we just used DBus to retrieve the path to another local, randomly-named Unix domain socket. That’s perfectly fine – DBus is not the one true IPC system. Programs like Pulseaudio and OpenSSH already have defined protocols, and there is nothing wrong with that, we don’t need to replace them with DBus. However, DBus is the best candidate for a one true atomic session namespace.
Again, all examples used in this blog post are completely hypothetical, and have no relation to the silliness of requiring users to try to hack around this issue on their own computers with variables like ControlMaster and ControlPath to enable a useful feature of your application.