User: Password:
|
|
Subscribe / Log in / New account

clarity of concept

clarity of concept

Posted Nov 5, 2014 23:24 UTC (Wed) by mezcalero (guest, #45103)
In reply to: clarity of concept by tstover
Parent article: Kdbus meets linux-kernel

Actually I think it's not too difficult to map D-Bus concepts to C (and classic UNIX) concepts in an understandable way. I mean, most programs today use C in a more or less object-oriented fashion (even though the language itself doesn't really have any syntactic sugar for that), and as D-Bus is object-oriented you can map things relatively easily.

  • What OO/D-Bus calls a "method" translates to a C "function".
  • What OO/D-Bus calls an "interface" translates to a C "struct" plus the functions you'd use to modify the struct.
  • What D-Bus calls an "object path" in a way translates in C to a pointer to a specific instance of a struct.
  • What D-Bus calls a method "signature" is really like a C signature, or function prototype if you so will.
  • What OO/D-Bus calls a "service" one could translate more or less to a UNIX socket.
  • And finally, the concept of a "bus" one could translate to a directory in the file system that multiple UNIX sockets are placed in.

Now, if you want to call a function on some other process via D-Bus, then you would do a method call, passing an object path, its interface, and the right arguments according to the method's signature, and send that to a specific service, on a specific bus.

And that's really all there is to it. If you understood C then D-Bus isn't particularly difficult. That said, libdbus-1 doesn't really help in making D-Bus digestable. Because it wanted to be a library that people should use for writing higher-level language bindings for, it is a bit too verbose I guess. In systemd we decided to provide a new D-Bus library that's supposed to be easier to use. With that in place calling a D-Bus method becomes really easy:

{
        sd_bus *bus;
        sd_bus_new_system(&bus);
        sd_bus_call_method(bus, 
                "org.freedesktop.timedate1",
                "/org/freedesktop/timedate1",
                "org.freedesktop.timedate1"
                "SetTimezone"
                NULL,
                NULL, 
                "sb",
                "Europe/Berlin",
                1);
       sd_bus_unref(bus);
}

This connects to the system bus (which is where all system services are found on), then call a method on the "org.freedesktop.timedate1" service, referencing an object by its path "/org/freedesktop/timedate1", selecting its interface "org.freedesktop.timedate1", invoking the "SetTimezone" method call. The two NULL pointers are for getting back a more verbose error on failure and for getting some other response data back. In thise case for the sake of just being an example we pass that as NULL because we aren't interested. Then, the signature of the call is "sb", meaning a string followed by a boolean. And finally, that's the wo arguments we pass.

Ignoring the fact that this example doesn't do any error checking this is really as easy as it gets. In effectively four lines of pure C code you can fire off an RPC call.

Now, D-Bus does substantially more than just what the example above shows. It has a scheme for getting notifications back from bus objects ("signals"), it knows introspection, and authentication and all that stuff. But in the essence its really as easy as the example above shows.

Hope this is useful,

Lennart


(Log in to post comments)

clarity of concept

Posted Nov 6, 2014 0:46 UTC (Thu) by sdalley (subscriber, #18550) [Link]

Thank you for this friendly and informative post!

And while I'm at it, thank you too for your part in *documenting* systemd. http://www.freedesktop.org/wiki/Software/systemd/ . I wish the networking side of Linux was documented so well and accessibly.

Stuff that's not documented can't be used by mere mortals.

clarity of concept

Posted Nov 18, 2014 17:26 UTC (Tue) by nix (subscriber, #2304) [Link]

... unless it has next to no capabilities. sysvinit, for example, could be used by mere mortals because you can hardly do anything with it, so there's hardly anything to document. :)

(Though it *is* actually documented, the documentation is hardly ever consulted because, well, who the hell changes /etc/inittab anyway?)

clarity of concept

Posted Nov 6, 2014 1:58 UTC (Thu) by lsl (subscriber, #86508) [Link]

Thanks, Lennart. That was definitely useful.

The stuttering on the destination, path and interface arguments stands out and immediately reminds one of the mentioned heavyweight object system things. Sure, it's cosmetic and probably makes total sense to someone accustomed to D-Bus but…yuck!

When almost every call (aside from tests) looks like that (from grepping the systemd repo), there has to be some other way…

Anyway, I will now try to actually understand D-Bus/kdbus before making any additional comments. ☺

clarity of concept

Posted Nov 6, 2014 8:37 UTC (Thu) by alexl (guest, #19068) [Link]

The "stuttering" is because the example is a bit simple.

The first "org.freedesktop.timedate1" is the destination process, and the "org.freedesktop." part is a java-style reverse-dns prefix to handle the fact that the namespace in dbus is global.

The "/org/freedesktop/timedate1" is the object in this process that we wish to talk to. Since this service typically only has one interesting object and we need a standardized place for it we use something similar to the destination name. It could technically be "/", but then it would be hard for the timeddate1 service to also serve other objects.

The second "org.freedesktop.timedate1" is the interface name we wish to call a method on. An object in dbus may implement several interfaces, and in this case it probably also implements the standard "org.freedesktop.DBus.Properties" and "org.freedesktop.DBus.Introspectable" interfaces too. Think of this as a namespace for the method name argument.

In this case we're just calling the "normal" methods on the timedate service, but we need to name that something and typically it gets the same name as the destination.

clarity of concept

Posted Nov 6, 2014 23:29 UTC (Thu) by iabervon (subscriber, #722) [Link]

It would be nice if the default interface for a service were the service's name, so you wouldn't have to say, "I want org.freedesktop.timedate1, and I want it to act like a org.freedesktop.timedate1", but could say, "I want org.freedesktop.timedate1 (and I want it to act like itself)".

I think this object path is actually a bit misguided, though. If there were two objects in this service, the most likely situation would be something like what I've got on my desktop, where I've got one clock in the local time zone and one in UTC. Paths like "/clocks/me" and "/clocks/universal" would identify different things that this service would want to manage, while leaving room for other sorts of object that the service might also want to manage (maybe /zoneinfo/Buenos_Aires, to report the system's time zone rules for Buenos Aires, so that you can send someone an iCal meeting and they'll know what you expect the UTC offset to be, in case their system's timezone data isn't the same). If you name your object based on your service name, chances are that, if you ever have a second object, it will have equal claim to that name, defeating the purpose of obligatorily having names.

clarity of concept

Posted Nov 7, 2014 1:29 UTC (Fri) by hp (subscriber, #5220) [Link]

You could do that as a convention in the client library (have a function that takes one name and derives the others from it). There isn't a need for a protocol change for it.

It isn't necessarily good practice for services to have one object with everything in one interface anyhow, though it's probably fine for a very simple service.

The object names are only namespaced because a single process may contain unrelated modules. For example all GTK apps could have objects available under /org/gtk.

If you know your process doesn't have multiple modules you could name an object /foo just as you can have a global variable in C called foo instead of my_namespace_foo. What is "OK" is a judgment developers have to make.

There are also cases where a strategy like naming each object with a GUID or something makes sense.

clarity of concept

Posted Nov 7, 2014 3:44 UTC (Fri) by luto (subscriber, #39314) [Link]

I actually think that the reverse anti-stuttering approach might have been better. These cases are examples where the client wants a singleton object in the context of either the running system or the desktop session. The client doesn't really give a crap what service provides the timezone object; it wants to access the timezone object.

What if there were a pseudo-service org.freedesktop.dbus.singletons with the special property that different real services could register different well-known names under the singletons service.

Then you could talk to /org/freedesktop/timedate1 in the singletons pseudo-service.

Anyway, the stuttering issue isn't really a problem, other than aesthetics.

clarity of concept

Posted Nov 11, 2014 21:34 UTC (Tue) by javispedro (guest, #83660) [Link]

I think D-Bus has always had problems in the design of their "broker" service. For example the "com.example.interface at /com/example/interface path" pattern is way too common in most D-Bus servers and it doesn't look right to me. I don't understand for example why one needs to create e.g. /timedate1 and /timedate2 instead of being able to create a single /timedate object which implements the multiple versioned interfaces. I suppose it has something to do with (non-namespaced) properties or similar, but it looks like a design problem.

Also, quite common operations such as e.g. "look for any/all objects implementing interface com.example.interface", which are often used in the complex IPC libraries, are missing in core D-Bus. Thus, one is forced to spawn a multitude of registrar-like daemons for every possible interface. Or, alternatively, "abuse" service names like the MPRIS specification does.

clarity of concept

Posted Nov 11, 2014 23:46 UTC (Tue) by HelloWorld (guest, #56129) [Link]

> I don't understand for example why one needs to create ...
One doesn't.

clarity of concept

Posted Nov 12, 2014 0:31 UTC (Wed) by javispedro (guest, #83660) [Link]

That's why I don't understand it :) But on any running system, I have plenty of services doing this with their object paths, e.g. polkit, udisks, nm/mm, nautilus...

clarity of concept

Posted Nov 16, 2014 21:46 UTC (Sun) by HelloWorld (guest, #56129) [Link]

I suspect that that's due to implementation details. This kind of thing is supported well by D-Bus itself, but not by languages like, say, Java.
http://stackoverflow.com/questions/2598009/method-name-co...

Perhaps similar issues led to what you're observing.

clarity of concept

Posted Nov 6, 2014 3:02 UTC (Thu) by jake (editor, #205) [Link]

Allow me to join the chorus: very useful and well explained, thanks!

jake

clarity of concept

Posted Nov 6, 2014 16:29 UTC (Thu) by atai (subscriber, #10977) [Link]

Now, with regards to Lennart, just hope that the new dbus library is still usable by itself, like the traditional dbus implementation, on Unix-ish systems without dependency or requiring systemd or the Linux kernel so it with the kernel patches discussed here do not turn dbus into a Linux-specific thing but just to make dbus fast on the Linux kernel.

clarity of concept

Posted Nov 6, 2014 16:47 UTC (Thu) by rahulsundaram (subscriber, #21946) [Link]

Do you realize you are replying to Lennart?

clarity of concept

Posted Nov 6, 2014 17:26 UTC (Thu) by ebassi (subscriber, #54855) [Link]

the current DBus daemon and client library still exist, and are maintained, for other OSes.

wrappers on top, like GDBus and QtDBus, either use the DBus daemon or kdbus depending on what's available.

clarity of concept

Posted Nov 6, 2014 22:05 UTC (Thu) by mezcalero (guest, #45103) [Link]

sd-bus supports both the classic dbus1 AF_UNIX transport as well as kdbus as backend. Applications written against the library should in most ways not see any difference. A couple of things won't be available on AF_UNIX though. For example, the credentials concept is much more powerful on kdbus than on AF_UNIX and we cannot emulate that on AF_UNIX.

sd-bus as a library should work fine on non-systemd systems too. A couple of things won't be available then though. For example, it offers APIs to connect to the system bus of local running OS containers, and to system busses of remote systems via SSH.

sd-bus is not portable to other kernels however. We make use of a multitude of Linux APIs, and it's not feasable really to port it, like the rest of systemd. And we will not accept patches for that.

However, this shouldn't really be a problem, as libdbus-1 and gdbus are both powerful libraries that are portable, and can also be used to talk to dbus. If portability to other OSes matters to you you can simply opt for one of those libraries.

Lennart

clarity of concept

Posted Nov 18, 2014 17:29 UTC (Tue) by nix (subscriber, #2304) [Link]

This encourages user applications to become gratuitously nonportable and seems like a bad move.

Libraries meant for general use should be portable, even if the system as a whole that they are part of is not.

clarity of concept

Posted Nov 7, 2014 11:47 UTC (Fri) by judas_iscariote (subscriber, #47386) [Link]

If developers of other unix systems have the need of such library then it is up to them to provide it, if you expect linux userspace plumbers to do the job for other systems you are fooling yourself.

That said, libdbus-1 is still available, maintained and portable, so people can use that for whatever they need. making sd_bus portable will actually be harmful and a supreme waste of time.

clarity of concept

Posted Nov 7, 2014 14:33 UTC (Fri) by foom (subscriber, #14868) [Link]

If they had the same api that might be true. But having two different APIs for the same thing, one easier to use only implemented in a non-portable library, the other harder to use and implemented in a portable library, is just a stupid situation to end up in. (I'd expect someone to make a portable implementation of the sdbus api.)

clarity of concept

Posted Nov 7, 2014 15:28 UTC (Fri) by ebassi (subscriber, #54855) [Link]

why would you port the systemd DBus API?

the GDBus and QtDBus API are already portable, thread safe, well documented, and available on various systems, if you don't want to use libdbus-1.

clarity of concept

Posted Nov 7, 2014 19:01 UTC (Fri) by krake (guest, #55996) [Link]

Indeed!

I think a lot of people are under the misconception that libdbus-1 is intended to be used by application developers.

Its main purpose is to provide the basic protocol support for usage in actual application libraries, very similar to how XCB provides basic X11 protocol support for toolkits.

And quite some of the application developer facing D-Bus libraries have moved to their own protocol implementations, e.g. to provide better integration with the target stack's capabilities.

clarity of concept

Posted Nov 9, 2014 15:16 UTC (Sun) by meyert (subscriber, #32097) [Link]

Is the handling of array of a struct still a pain, or does this become also much easier? Handling of a array of struct in libdbus is really not nice. You must use iterators everywhere...

clarity of concept

Posted Nov 11, 2014 16:13 UTC (Tue) by ceplm (subscriber, #41334) [Link]

I know this is completely offtopic for kDBUS, but we have now moved to the general dBUS waters anyway. And thank you for nice explanation, it makes a lot of sense.

However, one thing which have bothered me always: why is DBUS API so horribly complicated. In the good old days of DCOP (and now I don't care about that particular technology, just that the API could be way simpler) I was able to write this in KJS:

#!/usr/bin/env kjscmd

var dcop = new DCOPClient(this);
var box = new QHBox(this);
var go = new KPushButton(box);
var loc = new KLineEdit(box);

go.pixmap = StdIcons.DesktopIcon("go",32);
go.connect(go, "clicked()", this, "getWeather");

dcop.attach();
box.show();

function getWeather() {
if ( dcop.isAttached() ) {
var icn = new Image(this);
icn.pixmap = dcop.call("KWeatherService",
"WeatherService","icon(QString)", loc.text);
icn.smoothScale(32,32);
go.pixmap = icn.pixmap;
}
}

application.exec();

And that was everything I needed (including complete GUI). The call to DCOP itself was way more simple. I understand that DBUS is capable of doing way more complicated things, but why is it pushed down our throat? I just need a way how to address a simple object and method on it. So why the call you have shown couldn't be just something way more simple like:

impomrt dbus

bus = dbus.get_bus(dbus.SESSION_BUS)
bus.call('org.freedesktop.timedate1', 'SetTimezon', 'Europe/Berlin')

In the moment I don't need more than one object with one method (or few method) why do I need to deal with all this other stuff?

clarity of concept

Posted Nov 11, 2014 16:53 UTC (Tue) by nybble41 (subscriber, #55106) [Link]

The existing Python interface to DBUS has a few more layers than your proposal, but it doesn't seem _that_ complicated:

> import dbus
> 
> dbus.SessionBus() \
>     .get_object('org.freedesktop.timedate1', '/org/freedesktop/timedate1') \
>     .SetTimezone('Europe/Berlin', dbus_interface='org.freedesktop.timedate1')

That's three method calls, the same as your DCOP example. There are more details here: http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html#making-method-calls.

clarity of concept

Posted Nov 12, 2014 11:08 UTC (Wed) by ceplm (subscriber, #41334) [Link]

Which is exactly what I was trying to say: WTF we need any interfaces here at all. Why cannot I have (adjusted to your exmaple):

> import dbus
>
> dbus.SessionBus().get_object('org.freedesktop.timedate1').SetTimezone('Europe/Berlin')

And of course, I would hope for some more Pythonic binding, so it would be more like.

> dbus.SessionBus.get_object('org.freedesktop.timedate1').SetTimezone('Europe/Berlin')

or perhaps

> dbus.SessionBus['org.freedesktop.timedate1'].SetTimezone('Europe/Berlin')

Why do I have to bother with interfaces at all?

Matěj

clarity of concept

Posted Nov 12, 2014 12:22 UTC (Wed) by mchapman (subscriber, #66589) [Link]

> Why do I have to bother with interfaces at all?

It's unclear whether your question is "why do I have to specify an interface" or "why does D-Bus have interfaces at all".

The first problem is, of course, just an artefact of the library you're using. You could have a D-Bus library that somehow determined what interface you wanted automatically, for instance.

As for why D-Bus has interfaces at all, the way I understand it is that it provides an additional degree of modularity. A good example of their use is the systemd D-Bus API [1]. All systemd units can be manipulated via D-Bus objects. There are features that are common to all systemd units, but there are also features that are specific to each systemd unit type. So a D-Bus object for a "service" unit, for instance, implements both the org.freedesktop.systemd1.Unit and org.freedesktop.systemd1.Service interfaces, the D-Bus object for a "socket" unit implements both the org.freedesktop.systemd1.Unit and org.freedesktop.systemd1.Socket interfaces, and so on for each of the other systemd unit types.

Now it would certainly be possible to munge all the methods and properties for Unit into each of Service, Socket, Timer, etc.... but then what about the methods and properties that are independent of systemd? Should they be merged as well? Most (or is it all?) D-Bus objects implement the org.freedesktop.DBus.Introspectable interface, for instance.

Interfaces are fundamentally just a namespacing mechanism -- you can have the same method name in two different interfaces implemented by the one object, but namespacing allow sets of methods and properties to be mixed and matched in different ways.

[1] http://www.freedesktop.org/wiki/Software/systemd/dbus/

clarity of concept

Posted Nov 16, 2014 21:23 UTC (Sun) by HelloWorld (guest, #56129) [Link]

> Which is exactly what I was trying to say: WTF we need any interfaces here at all.
Because that allows an object to implement multiple interfaces that contain methods of the same name but with different semantics.

There's an interesting blog post that explains why this is important:
http://existentialtype.wordpress.com/2011/04/16/modules-m...

clarity of concept

Posted Nov 17, 2014 7:16 UTC (Mon) by ceplm (subscriber, #41334) [Link]

I was missing a word in my rant: why we need MANDATORY interfaces? Surely they could be optional, and for large objects they could be essential (although, it could be argued that too big objects are a design bug), but why should the time zone setting object (with just a few methods) should have multiple interfaces.

clarity of concept

Posted Nov 17, 2014 11:24 UTC (Mon) by mchapman (subscriber, #66589) [Link]

> I was missing a word in my rant: why we need MANDATORY interfaces?

Please see my earlier post. All D-Bus objects can -- and in my experience, usually do -- implement methods and properties from multiple interfaces. Now it may be perfectly logical to have a "default" interface per object which handles unqualified names, but that seems like it's best just handled by your client library. If your client library doesn't make this easy for you, use a different one.

Anyway, this discussion is pretty moot. The D-Bus specification [1] has been around for over a decade, and although it may have its warts it works well enough most of the time. You can argue that it's wrong, but it's not going to change the fact that it already exists.

[1] http://dbus.freedesktop.org/doc/dbus-specification.html

clarity of concept

Posted Nov 17, 2014 21:37 UTC (Mon) by ceplm (subscriber, #41334) [Link]

First, of course, this discussion is completely moot, I don’t expect anything to change. However, I don’t think it is useless to discuss completely theoretical questions. Actually, I really do enjoy, that I could finally express my thoughts and doubts about the API.

Second, argument “API sucks, but it could be meliorated by library” is in my opinion just that, an admission that API sucks.

clarity of concept

Posted Nov 14, 2014 17:53 UTC (Fri) by stef0x77 (guest, #88431) [Link]

Cockpit http://cockpit-project.org/ is hands down the easiest way to use DBus. For example, log into Cockpit, and type stuff like this in your javascript console to get a taste:

proxy = cockpit.dbus('org.freedesktop.hostname1').proxy()
proxy.Hostname
proxy.SetStaticHostname('mypinkpony.local', true)

You need Cockpit 0.31 or later. See here for a full example:

http://stef.thewalter.net/using-dbus-from-javascript-in-c...

... and here for full documentation:

http://files.cockpit-project.org/guide/latest/api-cockpit...

clarity of concept

Posted Nov 13, 2014 21:16 UTC (Thu) by oak (guest, #2786) [Link]

DBUS had already in the beginning (decade ago) couple of other important philosophical differences from doing C-code (or using CORBA):
* CORBA calls are by default synchronous, like function calls, but DBUS calls are by default asynchronous. If you don't expect reply, but are just notifying something, messages are fire & forget
* Message recipients don't need to exist before being called, DBUS daemon can "auto-activate" them when messages are sent to them


Copyright © 2018, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds