DBus tutorial, part 2

In the previous post we talked about DBUS buses and connection names. In this post we will have a look other basic concepts: object paths and interface names.

When you start d-feet and you select a software “well-known” name, such as org.freedesktop.UPower, you see, on the right side, a list of objects paths.

Every dbus server applications expose objects and every object has a path, which is a slash separated name like /org/freedesktop/UPower.

Every object implements one or more interfaces. An interface is a association of methods and properties that another app can call or get/set. Every interface is identified by a name, which is, like the connection name, a reverse domain name separated by dots (ex. org.freedesktop.DBus.Properties).

Just to summarize:

  • a DBUS server application has a well-known name (ex. org.freedesktop.UPower);
  • a DBUS server application exposes one on more objects (ex. /org/freedesktop/UPower, /org/freedesktop/UPower/devices/BAT_1);
  • any object implements one or more interfaces (ex. org.freedesktop.DBus.Properties).

You can think of interfaces like the Java or C# ones but in my opinion the most easy way to learn what an interface is to look at d-feet, which has a really good graphical representation of interfaces:

immagine_interfacce

Ok. Enough explanations. Let’s start with some code.
In the following example we will call the GetCriticalAction of the org.freedesktop.UPower interface exposed by the /org/freedesktop/UPower object of the org.freedesktop.UPower application. Uff… what a naming!

The GetCriticalAction method has the signature:

GetCriticalAction: () -> (String action)

That means that this method doesn’t take any arguments and returns a string, which is named action.

#include <dbus/dbus.h>
#include <stdio.h>
#include <stdlib.h>

static void check_and_abort(DBusError *error);

int main() {
	DBusConnection *connection = NULL;
	DBusError error;
	DBusMessage *msgQuery = NULL;
	DBusMessage *msgReply = NULL;
	const char *interfaceName = NULL;
	const char *versionValue = NULL;

	dbus_error_init(&error);
	connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
	check_and_abort(&error);

	interfaceName = "org.freedesktop.UPower";

	msgQuery = dbus_message_new_method_call(
		interfaceName,
		"/org/freedesktop/UPower",
		"org.freedesktop.UPower",
		"GetCriticalAction");

	msgReply = dbus_connection_send_with_reply_and_block(connection, msgQuery, 1000, &error);
	check_and_abort(&error);
	dbus_message_unref(msgQuery);

	dbus_message_get_args(msgReply, &error, DBUS_TYPE_STRING, &versionValue, DBUS_TYPE_INVALID);

	printf("The critical action is: %s\n", versionValue);
	
	dbus_message_unref(msgReply);
	
	return 0;
}

static void check_and_abort(DBusError *error) {
	if (!dbus_error_is_set(error)) return;
	puts(error->message);
	abort();
}

Let’s talk about the critical bits. In the previous post you have just seen how to make a connection to the DBus session bus; in this example we are using the system bus. This is the meaning (obvious) of dbus_bus_get call.

The dbus_message_new_method_call is used to create a new message that must be sent to the bus. The arguments are the coordinates of the process, the object, the interface and the method to call:

msgQuery = dbus_message_new_method_call(
	interfaceName,
	"/org/freedesktop/UPower",
	"org.freedesktop.UPower",
	"GetCriticalAction");

When the message is created the function dbus_connection_send_with_reply_and_block will send the message on the bus and wait for the response of the other application for one second (the 1000 in argument list). The function returns the reply:

msgReply = dbus_connection_send_with_reply_and_block(connection, msgQuery, 1000, &error);

Every DBus message created or returned must be deallocated with the dbus_message_unref call:

dbus_message_unref(msgQuery);

Now we must extract the result string from the reply message and we do it with dbus_message_get_args, which is ok for basic types:

dbus_message_get_args(msgReply, &error, DBUS_TYPE_STRING, &versionValue, DBUS_TYPE_INVALID);

Let’s try this code:

$ ./provadue 
The critical action is: HybridSleep

Ok. We have just called a DBUS-exposed object method!

In the next post we will talk about properties.

Advertisements
DBus tutorial, part 2

4 thoughts on “DBus tutorial, part 2

  1. You have no idea how incredible it is to find an up to date guide on Dbus in C. I’m studying your tutorial in order to interact with the Dbus API in the Bluez 5 stack. Almost every other guide is outdated and there is a lack of central documentation.

    Again, many many many thanks for everything you are doing here!

  2. u have no idea how incredible it is to find an up to date guide on Dbus in C. I’m studying your tutorial in order to interact with the Dbus API in the Bluez 5 stack. Almost every other guide is outdated and there is a lack of central documentation.

    Again, many many many thanks for everything you are doing here!

  3. David says:

    Ohhh yes, thanks a loooot having taken the time to write this tutorial. I have been crawling the web for a very long time prior to find your tuto, and this is the only one which explains (and is up to date) D-Bus C API so clearly. Bravo Mister ! and thanks again

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s