Simplify sdbus-c++ code using xml files

Erit Lvx
3 min readNov 8, 2021

--

Photo by Shahadat Rahman on Unsplash

DBus is a widely used IPC mechanism in many of the embedded applications. A number of DBus bindings are available that abstracts the low level working of the DBus and provides a convenient way to use. A particular DBus binding that I came across in recent days was the sdbus-c++ bindings. Although the Github page of sdbus-c++ provides a detailed information on how to use the bindings, there were a couple of challenges that I faced when using the library for an embedded application. This post will explain an easy way to use XML files and generate sdbus-c++ code to be used for a application.

sdbus-c++ provides a method of using convenience sdbus-c++ API layer to simplify the DBus implementation. However, this could be further simplified, by writing a XML file and then using a special code generator to generate the convenience sdbus-c++ APIs.

An example of how convenience sdbus-c++ API looks:

dbusObject->registerMethod("dbusMethod") .onInterface(interfaceName).implementedAs( []{
std::cout << "DBus method invoked \n":
});

The above declaration, declares a DBus method named dbusMethod , on a DBus interface named interfaceName with an implementation as mentioned in the lambda declaration.

Writing XML file

Now lets write a simple XML file that describes a DBus API. Our DBus API will accept a vector of bytes as input argument and return a hash value in the string form.

API signature :

std::string getHashString(std:vector<uint8_t> inData);

The equivalent xml file for the above function is:

<?xml version="1.0" encoding="UTF-8"?><node name="/org/medium/erit">
<interface name="org.medium.erit">
<method name="getHashString">
<arg type="a{y}" name="inData" direction="in" />
<arg type="s" name="hashString" direction="out" />
<annotation name="org.freedesktop.DBus.Method.Async"
value="clientserver" />
</method>
</interface>
</node>

The following are the important things to note in the XML file:

  1. The input and output arguments, are to be specified according to the DBus specification for data types. eg. i for integer, b for boolean, y for byte, etc.
  2. The annotation name describes the nature of the DBus API. sdnus-c++ provides the support for both synchronous and asynchronous APIs. This behavior can be controlled at either of the sides, i.e client or server. The parameter value="clientserver" states that the API is asynchronous at both client and server.
  3. When making the client application as asynchronous, make sure that the client application waits till the response is provided by the server.

Generating the glue codes from XML files

The next step is to use the xml file and generate glue-codes or interface files to the sdbus-c++ library. This is achieved using the code generator sdbus-c++-xml2cpp .

Run the following command to generate the glue codes:

sdbus-c++-xml2cpp generateHash.xml --adaptor=generateHash-server-glue.h --proxy=generateHash-client-glue.h

The following glue codes are generated:

generateHash-client-glue.h

generateHash-server-glue.h

Using the generated glue code

Using the generated glue code is as easy as inheriting the class(in respective client and server application) and then implementing the pure virtual methods. The base class(glue-code) provides public APIs that can be called from the application. The response of this API is provided in the virtual methods, since it is an asynchronous reply mechanism.

The following is a dummy implementation of the client application:

Client Application

And there we go, in a few steps we have completely avoided the implementation required for internal working of DBus. This approach lets the application developer avoid the nuances of low level working of sdbus or dbus and focus completely on the application development.

In my next article, I will write about how to configure AppArmor policy restrictions for a DBus application.

--

--

Erit Lvx

Erit Lvx is my alias name and derived from the Netflix scifi Dark.