Dodji's "DBus code oriented tutorial"
=====================================

Authors: Dodji Seketeli (dodji gnome org)

Last Modification date: 2005-03-28 

0) How to get this tutorial
--------------------------

To get the tarball of this tutorial (source code + this file) : 
	http://dodji.seketeli.free.fr/dbusping-tutorial.tar.gz

To browse the sources online:
	http://dodji.seketeli.free.fr/dbusping-tutorial

You can also grab it from my GNU-ARCH repository:
	tla register-archive http://dodji.seketeli.free.fr/arch
	tla get dodji@torimasen.com--2005/examples--dbusping--0.1


I) DBus concepts 
------------------

To know more about the big picture, go visit 
http://www.freedesktop.org/Software/dbus .

II) Spirit of the tutorial
--------------------------

What I tried to do here is a practical example of how to
write a service process that serves request coming from client applications.

The paradigm I have tried to highlight here is the remote method call
paradigm. In short, a client application invokes a method on an object
running in a remote service process and gets a reply back.

III) Disclaimer and prerequisites
---------------------------------

The code of the tutorial is written in C. Throughout this small paper I use
the C++ oriented notation Class::method() do designate methods of classes.
This is just for convenience as I tried to keep the design of the code as object
oriented as I could.

To compile this tutorial, you need libdbus and libdbus-glib version 0.23.

Today, the last released version of DBus is 0.31. It introduces some small changes. So
The code of this tutorial won't compile with 0.31. The problem is my current
distro (Debian sarge) does not have 0.31 yet and still has 0.23. I will update
the code of the tutorial when DBus 0.31 shows up on the distro I use.
In any case, this tutorial can still give you a very precise view of how
to use DBus.

A makefile is provided with the project, but I can only ensure it will work
on GNU/Linux. I don't really care about other platforms. I accept patches
though.

IV) The real meat
-------------------

A) The service process 
------------------------------------
The service process is a simple ping service. 
It contains an object, instance of a class called PingServer.
The service instantiates *one* instance of the PingServer class, and uses
it to serve the incoming requests.

The PingServer class has methods such as :
enum PingServerStatus PingServer::do_ping(), or
enum PingServerStatus PingServer::get_version (unsigned char **a_version), or
enum PingServerStatus PingServer::get_about (unsigned char **a_about_string), or 
enum PingServerStatus PingServer::get_date_as_string (unsigned char **a_date) ;

What they do is self explanatory.

The PingServer class contains nothing DBus specific. It is a just a classical
class that is just fine to be used by some a "client code" that run in the same
address space.
The code of the PingServer class is in the ping-server.h and ping-server.c files.

What is DBus specific is the ping-service code. The ping-service 
is the service process.
It is an executable that listens to requests (or messages) coming from client applications (via the Desktop Bus)
and uses an instance of the PingServer class to serve these requests.

DBus support several types of messages: 
	-Signals messages (or events), 
	-method calls messages 
	-method return messages
	-error messages

The PingService uses 3 types of messages: method calls, method returns and error messages.
It will listen to method call messages coming from client apps, it will send method return message back,
or error messages if it cannot serve the request for a given reason.

B) The client side 
-------------------

On the client side, the DBus specific part is a class named PingServiceProxy

Most of the methods of this class mirrors the methods of the PingServer:
enum PingServiceProxyStatus PingServiceProxy::do_ping(),
enum PingServiceProxyStatus PingServiceProxy::get_version (unsigned char**a_version) ...

The job of this PingServiceProxy class is
	-provide a way for client apps to call methods of the PingServer class running in a
	 remote PingService service process
        -shield client apps from DBus plumbing
In short, client apps willing to call the methods of the PingServer class that runs in the distant
PingService service process will just have instantiate the PingServiceProxy class and call methods
of that class as methods actually proxy the methods of the remote PingServer class .

The code of the PingServiceProxy sits in the ping-service-proxy.c file.

Of course, a real client application is provided too. It's a command line tool named ping-client.
It has options like --get-service-version, or --get-service-date etc ...

As you may have understood, this client instantiates a PingServerProxy class, and uses it methods
to actually call methods of the remote PingServer class.

V) Compiling and trying launching the bits 
--------------------------------------------

To compile, cd where the file Makefile is and type 'make'.
If you want to remove the binaries and recompile again, type 'make clean all' .
To compile using g++, type 'make CC=g++'.

Once you have compiled, you should see two executable binaries:
'ping-service' and 'ping-client'.

ping-service is the service executable. It's the one that listen to requests and serve them.
ping-client is a command line tool that sends requests to the ping-service, gets replies back,
and print the result on the screen.

To be able to have everything work, make your session DBus daemon is launched.
To be sure launch a terminal and type: 
'ps -ef | grep dbus-daemon-1'

You should see at least two lines that resemble:
message   2959     1  0 Mar26 ?        00:00:00 /usr/bin/dbus-daemon-1 --system
dodji    14360     1  0 13:10 ?        00:00:00 dbus-daemon-1 --fork --print-pid 8 --print-address 6 --session

What is important is that 2 instances of dbus-daemon-1 are running, one with the option --system, and the other one
with option --session (at least).

If you don't have the session bus running (the one with the --session option), then you will have to launch
it yourself and set a couple of environment variables needed for DBus enabled apps to work properly. 

To launch the session bus, type 'dbus-launch --auto-syntax > dbus-env.sh' . 
Then, type 'source dbus-env.sh'. This should launch the session bus and set the environment
variables DBUS_SESSION_PID and DBUS_SESSION_BUS_ADDRESS that are needed for DBus enabled apps
to be able to locate the Bus.

In any case *before* you launch a DBus enabled app, make sure the environment variable
DBUS_SESSION_PID and DBUS_SESSION_BUS_ADDRESS are set and exported.

Okay, now your environment should be correctly setup. Launch the ping-service executable.
Your should the following line displayed on screen:

Initializing PingService service process ...
        Getting the current logging session bus... [OK]
	wire the dbus machinery in glib main loop... [OK]
PingService service process up and running [OK]


If you see that, it means the PingService process is up and running.

Now, you can play with the client. Type './ping-client' to see the options.
To have the ping-service process sends you the date (for example) type
'./ping-client --get-service-date'

You should see a line similar to this one appear on the screen:
PingIface::getDateAsString(): Mon Mar 28 15:59:00 2005


Try the beast, read the code and send me comments.

Cheers,

Dodji.

