Overview
Dbus is a high level inter process communication protocol. Linux operating systems offer lower level inter process communication facilities such as pipes, shared memory, signals, semaphores, sockets etc. Applications running on Linux operating systems tend to build their own protocols for communicating with other applications running on the same OS using these as primitives. This creates a more complex mesh like communication network among processes. Where each link represents a different protocol. DBus aims to simplify the complexity of a mesh network and standardize the communication protocol. Dbus achieves this by providing a high level common channel like architecture for communication among processes.
Complex mesh communication network among processes.
Simplified bus architecture for communication.
DBus protocol includes an IPC and an RPC framework. The IPC mechanism is high level. It works with message frames rather than byte streams and has its own wire protocol. The message frame contains a header and a payload. The header contains the metadata about the message for example information about sender process, recipient process, type of fields etc. The payload contains actual data. The RPC framework of DBus protocol require applications to expose objects hierarchies at well defined object paths. Applications use these paths to call methods, access properties and listen to the signals emitted by other applications. DBus offers two types of communication models. First, the request-response model. It is based on method calls. An application gets access to the remote object exposed by other application. The application calls a method on the object and waits for the return value. Second, the publish-subscribe model. Here one application can register a signal handler and wait for other application to emit a specific signal. Under the hood, DBus can work with either AF_UNIX sockets or TCP/IP sockets for communication. DBus also has a built in type system. It enables DBus to marshal data on to the wire an un-marshal data from the wire into the memory.
Concepts
DBus protocol builds upon a few basic concepts. Understanding these concepts gives a clear picture of how everything fits together.
1. Bus: Virtual channel that mediates the message between processes. There are two type of buses. System Bus and Session Bus. System Bus is a global bus that is used by both system and user processes. A Session Bus is specific to a user login session. An application can create a new Session Bus for communicating with other processes in that session.
2. Service: A process that exposes APIs over DBus. It can be uniquely identified by a reverse domain name for example:`org.bluez`.
3. Client: A process that consumes APIs over DBus.
4. Peer: Process that acts as Client and Service at the same time.
5. Object Path: Client uses the object path to reference an object exposed by the Service. For example`org/bluez/hci0` is the path of a remote object exposed by BlueZ representing a bluetooth adapter.
6. Object: All objects exposed by the service implement Interfaces and have a unique object path.
7. Interface: A collection of methods, properties and signals. Developer of a service chooses which interface they implement. Developers can also add a new interface and its implementation. Interfaces also have reverse domain style unique names for example:`org.freedesktop.NetworkManager`.
8. Method: A client calls a method exposed by a remote object. A method call is an example of request-resonpse model of communication. It can used in a blocking or an async way by using an event loop. A method call is used for one-to-one communication between a client and a service. It is always initiated by the client.
9. Signal: A Client listens to a signal exposed by the remote object by attaching a signal handler to it. A signal is an example of publish-subscribe model of communication. It is generally used for one-to-many type of communication. A service initiates this communication by emitting the signal.
10. Property: A variable that an object exposes.
11. Signature: Type signature of a method (types of arguments and return values) in DBus type system.
Example: DBus python bindings
Here we look at an example to show the usage of sd-bus (an implementation of DBus protocol) and dbus-python python bindings to read the network connectivity status.`NetworkManager` process exposes network status using DBus APIs. We use python3.5 on Ubuntu to construct a small program to read network status.
- Import the dbus library and other required modules.
import dbus# Import Glib to setup an event loop which runs signal handlers.from dbus.mainloop.glib import DBusGMainLoopfrom gi.repository import GLib
- Setup an event loop. We define a callback as the signal handler for`StateChanged` signal emitted by`NetworkManger`. The event loop will take care of calling the callback when it receives the signal.
DBusGMainLoop(set_as_default=True)# Define the loop.loop = GLib.MainLoop()
- Connect to the`System Bus`.
system_bus = dbus.SystemBus()
- Get a proxy object for the remote object exposed by`NetworkManger` at path`/org/freedesktop/NetworkManager `.
proxy_object = system_bus.get_object( 'org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager')
- Define the signal handler.
Define our signal handler callback.# Network Manager states:## NM_STATE_DISCONNECTED -> 20# NM_STATE_DISCONNECTING -> 30# NM_STATE_CONNECTING -> 40# NM_STATE_CONNECTED_LOCAL -> 50# NM_STATE_CONNECTED_SITE -> 60# NM_STATE_CONNECTED_GLOBAL -> 70def network_state_change_handler(new_state): print(new_state)
- Attach the signal handler to the`System Bus` on the interface`org.freedesktop.NetworkManager`
system_bus.add_signal_receiver( network_state_change_handler, signal_name='StateChanged', dbus_interface='org.freedesktop.NetworkManager')
- Start the event loop defined earlier to start listening for the signal.
loop.run()
- Run the python3 program we wrote in the steps above in the console.
$ python3 network-status-check.py
To test it disconnect and re-connect to your WiFi network and you will see the different states being printed on the console. Something like:
50 ## NM_STATE_CONNECTED_LOCAL20 ## NM_STATE_DISCONNECTED40 ## NM_STATE_CONNECTING50 ## NM_STATE_CONNECTED_LOCAL70 ## NM_STATE_CONNECTED_GLOBAL
The python-dub tutorial does a good job of explaining the different usage of dbus APIs. It covers various use cases such as exposing your API over DBus and emitting signals etc.
Caveats and Criticisms
Despite being around for more than 15 years DBus didn’t get much traction outside of its ecosystem. But in this article, we do not analyze why it failed to be popular. Instead, we look at its shortcomings to understand when to use it and when not to. Although DBus works with TCP sockets but it doesn’t include a built-in encryption mechanism. Using it directly with TCP is not a good idea. DBus performs multiple data copies and context switches, sending a message involves relaying it via`bus-daemon`(which implements the software bus abstraction), this compromises the performance. This implies sending large chunks of data over DBus is not a good idea. Other concerning issues that have been reported include uncontrolled memory usage and the message being dropped without an error in some scenarios. Also, some bugs in DBus remain unresolved for more than 7 years.
Further Reading & References
1. DBus official page
2. DBus specification
3. Great article about sdus, kdbus, systemd and the ecosystem.
4. Python dbus library official tutorial.
5. On using BlueZ with DBus APIs.
6. on DBus in 2005
8. Slides from Mylene Josserand’s presentation on DBus.
originally published on Medium (March 2018): https://medium.com/asymmetry/an-introduction-to-dbus-e89ad93c874d

