Dbus_Tutorial.pdf

(97 KB) Pobierz
Introduction:
D-Bus is a message bus system, a simple way for applications to talk to one another, D-Bus supplies a
system and a session daemons.
The system daemon is launched at the system startup level and used mainly for hardware events, while
the session daemon is launched when the user login to a desktop environment and it is for use for
desktop applications to connect to each other.
Note :The Dbus developer always recommend the usage of a DBus binding library, such as dbus-glib or
dbus-qt, instead of using the DBus API directly, they said that the DBus API is not yet frozen and by
using this API directly the programmer is signing up for some pain, in my opinion, in order to
understand clearly any DBus binding libraries, it is a very good idea to dive into the DBus low level
programming, keep in mind that what we are going to use here is the trivial part of the DBus API.
Before start doing any code, there is some terms that one should be familiar with:
DBus Connection:
DBusConnection is the structure to use for opening a connection to the daemon, either the system bus
daemon by specifying DBUS_BUS_SYSTEM or to the session bus daemon using
DBUS_BUS_SESSION.
DBus Message:
It is simply a message between two process, all the DBus intercommunication are done using
DBusMessage, these messages can have the following types, method calls, method returns, signals, and
errors. The DBusMessage structure can carry out parameters, by appending boolean integers, real
numbers, string, arrays, ... to the message.
path:
Is the path of a remote Object, example /org/freedesktop/DBus.
Interface:
Is the interface on a given Object to talk with.
Signal:
It is a DBus message to make a signal emission.
Method Call:
It is a DBus message used to invoke a method on a remote object.
DBus Error:
The DBusError is the structure that holds the error code which occurs by calling a DBus method.
Getting a bus connection:
DBusConnection *connection;
DBusError error;
dbus_error_init(&error); /* Initialize the error structure */
connection = dbus_bus_get(DBUS_BUS_SESSION,&error); /* Or DBUS_BUS_SYSTEM */
if ( dbus_error_is_set(&error) )
{
printf("Error connecting to the daemon bus: %s",error.message);
dbus_error_free(&error);
}
For now, we have learned the basic concepts of DBus, next we will learn internal details of a DBus
based application, by examples.
Example 1: Reserving a bus name
Just to get more familiar with DBus programming, in this example we will see how we can reserve a
bus name for our small application. There is some restriction that DBus applies to the bus names, they
are a valid UTF-8 string and must have at least one '.' which separates the elements name, each element
must contains at least one character, example "org.freedesktop". , for a full list read the DBus
specification section Bus names .
#include <stdio.h>
#include <dbus/dbus.h>
int main()
{
DBusConnection *connection;
DBusError error;
char *name = "org.share.linux";
dbus_error_init(&error);
connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
if ( dbus_error_is_set(&error) )
{
printf("Error connecting to the daemon bus: %s",error.message);
dbus_error_free(&error);
return 1;
}
dbus_bool_t ret = dbus_bus_name_has_owner(connection,name,&error);
if ( dbus_error_is_set(&error) )
{
1034719544.003.png 1034719544.004.png
dbus_error_free(&error);
printf("DBus Error: %s\n",error.message);
return 1;
}
if ( ret == FALSE )
{
printf("Bus name %s doesn't have an owner, reserving it...\n",name);
int request_name_reply =
dbus_bus_request_name( connection,name, DBUS_NAME_FLAG_DO_NOT_QUEUE,
&error);
if ( dbus_error_is_set(&error) )
{
dbus_error_free(&error);
printf("Error requesting a bus name: %s\n",error.message);
return 1;
}
if ( request_name_reply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER )
{
printf("Bus name %s Successfully reserved!\n",name);
return 0;
}
else
{
printf("Failed to reserve name %s\n",name);
return 1;
}
}
else
/*
if ret of method dbus_bus_name_has_owner is TRUE, then this is useful for
detecting if your application is already running and had reserved a bus name
unless somebody stole this name from you, so better to choose a correct bus
name
*/
{
printf("%s is already reserved\n", name);
return 1;
}
return 0;
}
We have used the DBUS_NAME_FLAG_DO_NOT_QUEUE flag, DBus will not queue us in case the
bus name that we want to reserve is already used. For a full list of flags for dbus_bus_request_name
and return code see the DBus API . A requested bus name can always be released using
dbus_bus_release_name.
To Compile the above code, the DBus developement package should be installed, depending on your
distro the name of this package may differ, but should be something like libdbus-dev (On a Slackware
system all the package comes with their development files). Then you compile the code with the
following command:
gcc `pkg-config --libs --cflags dbus-1` example1.c -o example1
1034719544.005.png
 
pkg-config tries to find dbus-1.pc file, usually this file is located with others in /usr/lib/pkgconfig, and
those kind of files contains information about the library(ies) to link.
Example 2: Connecting two desktop applications
In this example, we will use DBus to connect two desktop applications, one listen to DBus messages
and the other send DBus messages, but before starting, the listener program should not just start and
exit, it has to wait for events, so we have to find a way to organize the events sent to our program, a
simple solution for this is to use the main event loop from glib, when using it we can keep our program
in sleep mode until receiving events, another problem occurs is the fact that how we can integrate our
bus connection with the glib main event loop, here comes dbus-glib, so our tiny program will depend
also on dbus-glib for just one call, dbus_connection_setup_with_g_main, this call integrates the glib
main loop and the DBus bus events.
A question raises here, if we want to use just DBus, how we can avoid the usage of its glib binding, the
answer is not simple, first we have to write our own loop events, and integrate it with the bus events, a
good start is to look at the DBus source as they have a helpful code in dbus/dbus-mainloop, but to
simplify our job we will use dbus-glib.
listen.c In this program we will use dbus_bus_add_match(DbusConnection *,const char *rule,
DBusError *) to add a match for the messages that we want to receive, the rule string has a specific
format, see DBus match rule for full details.
#include <stdio.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <glib.h>
static DBusHandlerResult
dbus_filter (DBusConnection *connection, DBusMessage *message, void *user_data)
{
if ( dbus_message_is_signal(message,"org.share.linux","Customize" ) )
{
printf("Message cutomize received\n");
return DBUS_HANDLER_RESULT_HANDLED;
}
if ( dbus_message_is_signal(message,"org.share.linux","Quit" ) )
{
printf("Message quit received\n");
GMainLoop *loop = (GMainLoop*) user_data;
g_main_loop_quit(loop);
return DBUS_HANDLER_RESULT_HANDLED;
}
1034719544.001.png
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
int main()
{
DBusConnection *connection;
DBusError error;
/* glib main loop */
GMainLoop *loop;
loop = g_main_loop_new(NULL,FALSE);
dbus_error_init(&error);
connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
if ( dbus_error_is_set(&error) )
{
printf("Error connecting to the daemon bus: %s",error.message);
dbus_error_free(&error);
return 1;
}
dbus_bus_add_match (connection,
"type='signal',interface='org.share.linux'",NULL);
dbus_connection_add_filter (connection, dbus_filter, loop, NULL);
/* dbus-glib call */
dbus_connection_setup_with_g_main(connection,NULL);
/* run glib main loop */
g_main_loop_run(loop);
return 0;
}
send.c
#include <stdio.h>
#include <dbus/dbus.h>
static void
send_config(DBusConnection *connection)
{
DBusMessage *message;
message = dbus_message_new_signal ("/org/share/linux",
"org.share.linux",
"Config");
/* Send the signal */
dbus_connection_send (connection, message, NULL);
dbus_message_unref (message);
}
static void
send_quit (DBusConnection *connection)
{
DBusMessage *message;
message = dbus_message_new_signal ("/org/share/linux",
"org.share.linux",
1034719544.002.png
Zgłoś jeśli naruszono regulamin