Page Body

Using the DBUS C API

D-BUS is a message
bus system, a simple way for applications to talk to one another The
low-level API for DBUS is written in C but most of the documentation and
code is written for a higher level binding, such as Python or GLib.
Here I provide tutorial/howto for a basic server and client using the C API
directly, including example code. The DBUS website has Doxygen documentation
for the C API.

NOTE: you should not use this API unless you absolutely have to. Application
developers should use one of the bindings if at all possible. If you are
writing in C then the GLib bindings are recommended.

Common Code

A lot of the code is common no matter what you want to do on the Bus. First
you need to connect to the bus. There is normally a system and a session
bus. The DBUS config may restrict who can connect to the system bus.
Secondly, you need to request a name on the bus. For simplicity I don't cope
with the situation where someone already owns that name.

After you have finished with the bus you should close the connection. Note
that this is a shared connection to the bus so you probably only want to do
this just before the application terminates.

dbus_connection_close(conn);

Sending a Signal

The simplest operation is sending a broadcast signal to the bus. To do this
you need to create a DBusMessage object representing the signal, and
specifying what object and interface the signal represents. You then need to
add any parameters to it as appropriate, and send it to the bus. Finally
you need to free the message. Several methods return false on out of memory,
this should be checked for and handled.

Calling a Method

Calling a remote method is very similar to sending a signal. You need to
create the message and specify the name on the bus it is being send to, and
what object, interface and method is being called. You then add parameters
to the message as above. If you need a reply to the message you need to use
a different method to send the message. This gives you a pending reply
object which you can block on to wait for the reply and get another
DBusMessage* as the reply. From this you can read the parameters
returned by the remote method.

Receiving a Signal

These next two operations require reading messages from the bus and handling
them. There is not a simple way in the C API as of 0.50 to do this. Because
DBUS is designed to use OO bindings and an event based model all the methods
that handle the messages on the wire use callbacks. I have submitted a patch
which should make it into the next release which allows messages to be read
and marshalled from the wire in a non-blocking operation. This is the
dbus_connection_read_write() method, which is required to use the
code on this page.

To receive a signal you have to tell the bus what signals you are interested
in so they are sent to your application, then you read messages off the bus
and can check what type they are and what interfaces and signal names each
signal represents.

// add a rule for which messages we want to see
dbus_bus_add_match(conn,"type='signal',interface='test.signal.Type'",&err); // see signals from the given interface
dbus_connection_flush(conn);
if (dbus_error_is_set(&err)){
fprintf(stderr,"Match Error (%s)\n", err.message);
exit(1);
}

// loop listening for signals being emmitted
while (true){// non blocking read of the next available message
dbus_connection_read_write(conn, 0);
msg = dbus_connection_pop_message(conn);
// loop again if we haven't read a message
if (NULL == msg){
sleep(1);
continue;
}// check if the message is a signal from the correct interface and with the correct name
if (dbus_message_is_signal(msg,"test.signal.Type","Test")){// read the parameters
if (!dbus_message_iter_init(msg,&args))
fprintf(stderr,"Message has no arguments!\n");
else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args))
fprintf(stderr,"Argument is not string!\n");
else {
dbus_message_iter_get_basic(&args,&sigvalue);
printf("Got Signal with value %s\n", sigvalue);
}}// free the message
dbus_message_unref(msg);
}

Note that the use of sleep in this example is to simulate some other thing we are blocking on,
such as select. If the only thing happening in this thread is the DBus communication then the
dbus_connection_read_write call can take a timeout parameter, which is how many ms to block for.
-1 blocks forever.

Exposing a Method to be called

To expose a method which may be called by other DBUS applications you have
to listen for messages as above, then when you get a method call
corresponding to the method you exposed you parse out the parameters,
construct a reply message from the original and populate its parameters with
the return value. Finally you have to send and free the reply.

// loop, testing for new messages
while (true){// non blocking read of the next available message
dbus_connection_read_write(conn, 0);
msg = dbus_connection_pop_message(conn);
// loop again if we haven't got a message
if (NULL == msg){
sleep(1);
continue;
}// check this is a method call for the right interface and method
if (dbus_message_is_method_call(msg,"test.method.Type","Method"))
reply_to_method_call(msg, conn);
// free the message
dbus_message_unref(msg);
}

Code Examples

That should be all you need to write a simple server and client for DBUS
using the C API. The code snippets above come from dbus-example.c which you can download
and test. It contains code for all four operations above.