レナート   Wunschkonzert, Ponyhof und Abenteuerspielplatz   ﻟﻴﻨﺎﺭﺕ

Wed, 11 Feb 2009

How to Version D-Bus Interfaces Properly and Why Using / as Service Entry Point Sucks

So you are designing a D-Bus interface and want to make it future-proof. Of course, you thought about versioning your stuff. But you wonder how to do that best. Here are a few things I learned about versioning D-Bus APIs which might be of general interest:

Version your interfaces! This one is pretty obvious. No explanation needed. Simply include the interface version in the interface name as suffix. i.e. the initial release should use org.foobar.AwesomeStuff1, and if you do changes you should introduce org.foobar.AwesomeStuff2, and so on, possibly dropping the old interface.

When should you bump the interface version? Generally, I'd recommend only bumping when doing incompatible changes, such as function call signature changes. This of course requires clients to handle the org.freedesktop.DBus.Error.UnknownMethod error properly for each function you add to an existing interface. That said, in a few cases it might make sense to bump the interface version even without breaking compatibility of the calls. (e.g. in case you add something to an interface that is not directly visible in the introspection data)

Version your services! This one is almost as obvious. When you completely rework your D-Bus API introducing a new service name might be a good idea. Best way to do this is by simply bumping the service name. Hence, call your service org.foobar.AwesomeService1 right from the beginning and then bump the version if you reinvent the wheel. And don't forget that you can acquire more than one well-known service name on the bus, so even if you rework everything you can keep compatibilty. (Example: BlueZ 3 to BlueZ 4 switch)

Version your 'entry point' object paths! This one is far from obvious. The reasons why object paths should be versioned are purely technical, not philosophical: for signals sent from a service D-Bus overwrites the originating service name by the unique name (e.g. :1.42) even if you fill in a well-known name (e.g. org.foobar.AwesomeService1). Now, let's say your application registers two well-known service names, let's say two versions of the same service, versioned like mentioned above. And you have two objects -- one on each of the two service names -- that implement a generic interface and share the same object path: for the client there will be no way to figure out to which service name the signals sent from this object path belong. And that's why you should make sure to use versioned and hence different paths for both objects. i.e. start with /org/foobar/AwesomeStuff1 and then bump to /org/foobar/AwesomeStuff2 and so on. (Also see David's comments about this.)

When should you bump the object path version? Probably only when you bump the service name it belongs to. Important is to version the 'entry point' object path. Objects below that don't need explicit versioning.

In summary: For good D-Bus API design you should version all three: D-Bus interfaces, service names and 'entry point' object paths.

And don't forget: nobody gets API design right the first time. So even if you think your D-Bus API is perfect: version things right from the beginning because later on it might turn out you were not quite as bright as you thought you were.

A corollary from the reasoning behind versioning object paths as described above is that using / as entry point object path for your service is a bad idea. It makes it very hard to implement more than one service or service version on a single D-Bus connection. Again: Don't use / as entry point object path. Use something like /org/foobar/AwesomeStuff!

posted at: 19:03 | path: /projects | permanent link to this entry | 6 comments


Posted by Ted Gould at Wed Feb 11 22:11:39 2009
Hmm, it would seem that effectively going from /org/foobar/AwesomeStuff to /org/foobar/AwesomeStuff1 would be the same as going from 1 to 2.  And, if you do get something right, you wouldn't have the uglyness of a number at the end.  Off chance, but it could happen :)

Posted by Havoc at Thu Feb 12 03:58:42 2009
That comment in EggDBus about rewriting signal emitters is flat-earth wrong. I would not recommend paying attention. There are good reasons the signal emitter is rewritten, and ignoring those is likely to result in races and bad code.

The dbus spec strongly assumes people aren't asinine and don't use "/" as their object path.
If people use "/" then that's their bug, not the spec's bug. File a bug vs. anyone using "/"
Do you name every single variable "TheOneGlobalObject" in C or Java and expect it to work? No, because it's absurd. But the dbus object path is the global variable name of the object

Claiming that "/foo/bar" is redundant with bus name org.foo.bar is like claiming you can name all your C global variables "TheOneGlobalObject" conflicting with each other, just because your executable is already called foobar or just because it's running on a host called foobar.org. Those names are in different scopes for different purposes.

The bus name is about routing the message, it should never affect how the message is processed, by either sender or receiver. There is already an object path and an interface and a method name used to decide how to process the message.

If you try to use the bus name for this, it's probably because you fucked up the object path. Well, fix the object path. Don't write some nonsense whining comment.

It is almost certainly going to create races and bugs if you use the bus name for something other than routing. Also it's going to break legitimately useful ways of using dbus. It's quite intentional that processes can have multiple bus names; I've written numerous programs that do this.

There are also perfectly good ways to still make things async while tracking the unique bus name. See hippo-dbus-helper which does this, iirc.

Frankly I think it's crazy that anyone is trying to get EggDBus in GLib with that comment in there with multiple factual errors - how can someone write the official dbus binding without understanding how dbus works? Or even bothering to ask, apparently?

Posted by davidz at Thu Feb 12 04:24:53 2009
Hi Havoc,

Sorry if my comment in EggDBus upset you.

I completely agree that people shouldn't be using "/" as the object path. FWIW, part of the reason that Lennart wrote this blog entry is because of discussions I had with him where I pointed out why you shouldn't use "/" as the object path (as he was already doing in existing services in the wild). In fact he suggested I should blog about it but I passed and then he did it.

Apparently a good explanation like the one I've been giving has been needed. All previous answers given to people been vague on the level of "don't do it, trust us, really". Apparently that didn't work out very well.

I don't your comments with EggDBus are very constructive, of course we can't fix up objects path like your are suggesting. There are tons of deployed services, fixing them up as you suggest would break ABI. Not going to happen. At least not on desktop linux.

It's like this: All we have at the client side is a signal. How the heck do you suggest we determine what proxy to deliver it to so we can turn it into a GLib signal? Funny enough you even seem to agree that the spec is slightly broken

http://bugs.freedesktop.org/show_bug.cgi?id=18982#c7

If you really want to help (instead of just ranting in a blog comment) maybe you could send a patch and/or more detail criticism via e.g. mail. Thanks.

Posted by Vudentz at Thu Feb 12 04:56:04 2009
Hmm, I wouldn't go as far as suggesting this versioning scheme for everyone. The reason is that many bindings are already using the introspection data, so I guess it is more productive/natural to mark the API version via introspection annotations.

If you take python binding which does use the introspection data quite nicely, I don't think it would be of any benefit to change a bus/interface/path name to something else when it already detects API changes, not only it will take more time to maintain but also more

Posted by davidz at Thu Feb 12 05:02:02 2009
And just to make it perfectly clear. EggDBus does relies on this guarantee

"There is this guarantee: that if you get a NameOwnerChanged indicating that
unique name :X owns name A, and then you get a signal from :X, and you have not
received a new NameOwnerChanged, then you know that :X owned A at the time the
signal was dispatched by the bus.

This allows a binding to (if it wants to) track the list of all aliases for a
given unique name, in a correct and secure manner."

that Havoc mentions in the freedesktop bug. I spent a lot time getting that code right in EggDBus so I'm fairly sure it is race free and correct.

The crux of the problem, what the EggDBus comment says, is how to handle broken services for which a given unique name :1.42 owns A and B which both exports an object at "/" implementing the same interface.

Like it or not, services like these are allowed to exist in the wild simply because of how the D-Bus protocol is defined.

So a complete binding need to handle this scenario somehow. Just saying "file bugs to force ABI changes" isn't really helpful.

Claiming that (the) EggDBus (comment) is full of factual errors (without really saying exactly what errors) isn't really useful either. And, Havoc, suggesting that I didn't bother to ask is not really true either - I specifically ask you to look at EggDBus back in December but you never got back to me. Frankly, I'm a little disappointed by this whole outburst.

Posted by Vudentz at Thu Feb 12 05:02:28 2009
...but also more difficult since the errors could become too obvious.

Leave a Comment:

Your Name:


Your E-mail (optional):


Comment:


As a protection against comment spam, please type the following number into the field on the right:
Secret Number Image

Please note that this is neither a support forum nor a bug tracker! Support questions or bug reports posted here will be ignored and not responded to!


It should be obvious but in case it isn't: the opinions reflected here are my own. They are not the views of my employer, or Ronald McDonald, or anyone else.

Please note that I take the liberty to delete any comments posted here that I deem inappropriate, off-topic, or insulting. And I excercise this liberty quite agressively. So yes, if you comment here, I might censor you. If you don't want to be censored your are welcome to comment on your own blog instead.


Lennart Poettering <mzoybt (at) 0pointer (dot) net>
Syndicated on Planet GNOME, Planet Fedora, planet.freedesktop.org, Planet Debian Upstream. feed RSS 0.91, RSS 2.0
Archives: 2005, 2006, 2007, 2008, 2009, 2010, 2011

Valid XHTML 1.0 Strict!   Valid CSS!