How to handle exceptions with the binding "dbus-c++"

| | August 4, 2015

I’ve recently started out learning C++ language and D-Bus for a project. Due to license issues, I got to use the binding “dbus-c++”. As a result, I’ve suffered from the lack of documentation of this binding and had to come over this.

I’m coding on Ubuntu 14.04.02 LTS and using libdbus-c++-0.9.0.

I found and tried this (great !) tutorial from Emilien Kia : http://blog.emilienkia.net/ . It explains how to implement a basic server / client in c++ using D-Bus. Basically, method calls are performed by the client via D-Bus. In our case, the server only implements one method “SayHello” that just prints out something on the server.

Everything worked as expected and intended when the server is launched BEFORE the client. However, I need to handle reconnection if the client is launched whereas no server is running. Here are my server and client codes :

/****************************
* Server
*
*****************************
*/

#include "adaptor.hpp"
#include <iostream>
#include <fstream>

using namespace std;

/* This "Hello" class handles connection to the D-Bus bus session and implements methods offered by the server */

class Hello : public com::example::Hello_adaptor,
            public DBus::IntrospectableAdaptor,
            public DBus::ObjectAdaptor
{
public:
    Hello(DBus::Connection &connection):
        DBus::ObjectAdaptor(connection, "/com/example/Hello")
    {
    }

    virtual void SayHello(const std::string& name)
    {
        cout << "Hello '" << name << "'" << endl;
    }
};


DBus::BusDispatcher dispatcher;

int main()
{
    DBus::default_dispatcher = &dispatcher;
    DBus::Connection bus = DBus::Connection::SessionBus();

    bus.request_name("com.example.Hello");
    cout << "Server launched" << endl ;

    Hello hello(bus);

    cout << "Waiting for connections" << endl ;
    dispatcher.enter();

    return 0;
}

and here my client :

/****************************
* Client
*
*****************************
*/

#include "proxy.hpp"
#include <iostream>
#include <string>
#include <unistd.h>

using namespace std;

class Hello : public com::example::Hello_proxy,
          public DBus::IntrospectableProxy,
          public DBus::ObjectProxy
{
public:
    Hello(DBus::Connection &connection, const char *path, const char *name):
    DBus::ObjectProxy(connection, path, name)
    {
    }
};

DBus::BusDispatcher dispatcher;

int main(int argc, char** argv)
{
    bool connection = false;
    DBus::default_dispatcher = &dispatcher;
    DBus::Connection bus = DBus::Connection::SessionBus();

    //Attempting to connect to the server as long as the client doesn't reach the server
    while (!connection)
    {
        try
        {
            Hello hello(bus, "/com/example/Hello", "com.example.Hello");
            connection = true;
        }
        catch (exception const& e)
        {
            cout << "Attempting to reconnect" << endl;
            connection = false;
            sleep (3);
        }
    }
    Hello hello(bus, "/com/example/Hello", "com.example.Hello");
    if(argc>=2)
        hello.SayHello(argv[1]);
    else
        hello.SayHello("world");

    return 0;
}

When I launched the client with no server running (i.e before the server is even launched), the programm terminates and aborts with this error :

terminate called after throwing an instance of 'DBus::Error'
what():  The name com.example.Hello was not provided by any .service files
Abandon (core dumped)

I was expecting that sort of message, that’s why I tried to catch exceptions in the “main” of my client (I also tried to catch a specific DBus::Error or Error but the result is the same) but it seems like it doesn’t work. More, I found out that the program doesn’t terminate on the first instantiation of Hello object (in the “try” block) but on the second one, after the “catch” block.

I gave a look into the sources so that I could know where the “DBus::Error was launched” but I failed on that. My Hello client constructor inherits from DBus::ObjectProxy and called the DBus::ObjectProxy constructor, which itself calls the DBus::Object constructor :

/* My client constructor */
Hello(DBus::Connection &connection, const char *path, const char *name):
    DBus::ObjectProxy(connection, path, name)

/* ObjectProxy constructor */
ObjectProxy::ObjectProxy(Connection &conn, const Path &path, const char *service)
  : Object(conn, path, service)
{
    register_obj();
}

/* Object constructor */
Object::Object(Connection &conn, const Path &path, const char *service)
: _conn(conn), _path(path), _service(service ? service : ""), _default_timeout(-1)
{
}

The “Object” class uses as attributs the following objects :

Connection    _conn;
DBus::Path    _path;
std::string   _service;
int           _default_timeout;

Actually, I got stuck on the syntax of _service in Object constructor. I don’t understand what means

_service(service ? service : "")

I focus on “_service” because the error reports the name “com.example.Hello” which stands for the parameter “name” in our Client constructor. Backwards in the sources this parameter “name” stands for the parameter “service” in the Object constructor. I also gave a glance in string constructors but I didn’t find any relevant information.

I think my explanation is not clear at all and if you accept to help me, do not hesitate to ask for further explanation ! As I’m a complete newbie in C++ and software buses I can’t explain well my programs and point out significant details, so please excuse me in advance :) (which accounts for why I got so much trouble with some basic stuffs)

Thanks !

Riwan

EDIT : I fixed my problem. Actually the exception wasn’t thrown during the instantiation but during the method call (hello.SayHello). I shifted my try .. catch block around the method calls and it worked as intended !

Leave a Reply