D-Bus Tutorial
D-Bus Tutorial
in/programming/d-bus-tutorial
1.0 D-Bus
D-Bus is a mechanism for interprocess communication under Linux and other Unix-
like systems. D-Bus has a layered architecture. At the lowest level is the D-Bus wire
protocol described in the D-Bus Specification. The libdbus library is an
implementation of the wire protocol. It provides the C Language interface for
communication between two processes. At the highest level is the D-Bus daemon,
or the message bus daemon. Processes can connect to a D-Bus daemon and
exchange messages. There may be multiple D-Bus daemons running in the system
at a time. First, there is the system D-BUS daemon for communication between the
kernel, system-wide services and the user. Then, there is the session D-
BUS daemon, primarily intended for communication between processes for the
desktop applications of the logged-in user.
libdbus is a low level API from the freedesktop.org project. There are other higher
level implementations, viz., GDBus for GIO, QtDBus for Qt, dbus-java and sd-bus,
for the systemd software suite.
Message Types
There are four types of
messages, SIGNAL, METHOD_CALL, METHOD_RETURN and ERROR.
Service
A service is a daemon process that provides some utility in the system. A service is
a server process which does work for the clients. A service has a singleton object.
Object
An object is an entity in a process, which does some work. An object is identified by
a path name. A path is like a complete file name in the system. So, an object might
have a path name like, /com/example/someserver. An object has members, which
means methods and signals.
Interfaces
An interface is a group of functions. An object supports one or more interfaces. The
interfaces supported by an object specify the members of that object.
Connection names
When an application connects with the D-Bus daemon, it is assigned a unique
connection name. A unique connection name starts with the colon character ":".
For each connection name there is an application which is its primary owner. All
messages sent to a name are delivered to the primary owner. Then, there is a
queue of secondary owners. As soon as a primary owner relinquishes the name, the
application at the top of the queue of aspiring secondary owners takes charge and
becomes the new primary owner.
DBusError dbus_error;
void print_dbus_error (char *str);
bool isinteger (char *ptr);
dbus_error_init (&dbus_error);
if (!conn)
exit (1);
if (dbus_error_is_set (&dbus_error))
print_dbus_error ("dbus_bus_get");
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
fprintf (stderr, "Dbus: not primary owner, ret = %d\n", ret);
exit (1);
}
DBusMessage *message;
if (!str1 || !str2)
error = true;
if (!error) {
if (isinteger (str1))
i = atol (str1);
else
error = true;
}
if (!error) {
if (isinteger (str2))
j = atol (str2);
else
error = true;
}
if (!error) {
// send reply
DBusMessage *reply;
char answer [40];
DBusMessageIter iter;
dbus_message_iter_init_append (reply, &iter);
char *ptr = answer;
if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &ptr)) {
fprintf (stderr, "Error in dbus_message_iter_append_basic\n");
exit (1);
}
dbus_connection_flush (conn);
dbus_message_unref (reply);
}
else // There was an error
{
DBusMessage *dbus_error_msg;
char error_msg [] = "Error in input";
if ((dbus_error_msg = dbus_message_new_error (message, DBUS_ERROR_FAILED, error_msg)) ==
NULL) {
fprintf (stderr, "Error in dbus_message_new_error\n");
exit (1);
}
dbus_connection_flush (conn);
dbus_message_unref (dbus_error_msg);
}
}
else
{
print_dbus_error ("Error getting message");
}
}
}
return 0;
}
while (*ptr) {
if (!isdigit ((int) *ptr++))
return false;
}
return true;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <dbus/dbus.h>
DBusError dbus_error;
void print_dbus_error (char *str);
dbus_error_init (&dbus_error);
if (dbus_error_is_set (&dbus_error))
print_dbus_error ("dbus_bus_get");
if (!conn)
exit (1);
if (ret == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
break;
if (ret == DBUS_REQUEST_NAME_REPLY_IN_QUEUE) {
fprintf (stderr, "Waiting for the bus ... \n");
sleep (1);
continue;
}
if (dbus_error_is_set (&dbus_error))
print_dbus_error ("dbus_bus_get");
}
DBusMessage *request;
DBusMessageIter iter;
dbus_message_iter_init_append (request, &iter);
char *ptr = input;
if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &ptr)) {
fprintf (stderr, "Error in dbus_message_iter_append_basic\n");
exit (1);
}
DBusPendingCall *pending_return;
if (!dbus_connection_send_with_reply (conn, request, &pending_return, -1)) {
fprintf (stderr, "Error in dbus_connection_send_with_reply\n");
exit (1);
}
if (pending_return == NULL) {
fprintf (stderr, "pending return is NULL");
exit (1);
}
dbus_connection_flush (conn);
dbus_message_unref (request);
dbus_pending_call_block (pending_return);
DBusMessage *reply;
if ((reply = dbus_pending_call_steal_reply (pending_return)) == NULL) {
fprintf (stderr, "Error in dbus_pending_call_steal_reply");
exit (1);
}
dbus_pending_call_unref (pending_return);
char *s;
if (dbus_message_get_args (reply, &dbus_error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) {
printf ("%s\n", s);
}
else
{
fprintf (stderr, "Did not get arguments in reply\n");
exit (1);
}
dbus_message_unref (reply);
return 0;
}
The makefile for building the software is given below. The spaces to the left
of gcc and rm commands are for the tab character.
#
# Makefile
#
%.o: %.c
gcc -Wall -c $< `pkg-config --cflags dbus-1`
add-server: add-server.o
gcc add-server.o -o add-server `pkg-config --libs dbus-1`
add-client: add-client.o
gcc add-client.o -o add-client `pkg-config --libs dbus-1`
.PHONY: clean
clean:
rm *.o add-server add-client
6.0 REFERENCES
o D-Bus Specification
o https://dbus.freedesktop.org/doc/dbus-specification.html
o D-Bus low-level public API
o https://dbus.freedesktop.org/doc/api/html/group__DBus.html
o dbus-daemon
o https://dbus.freedesktop.org/doc/dbus-daemon.1.html