Thursday, July 26, 2012

Dbus Tutorial - Intro and Resources

Introduction
Introspection
Network Manager 
Create a Service 
Gobject Introspection



Introduction to dbus

dbus (Desktop Bus) is a system, used mostly in Linux, that various applications and daemons and the operating system use to communicate with each other.

You can also use dbus to send text command, instead of a mouse click, that control applications and settings and windows and actions and much more.

For example, you can use dbus to pull information from Network Manager, like the name of a wireless access point. You can send commands to it, like to enable networking or to connect to a specific access point. Many of these actions you can also do other ways, for example through shell commands.

Learning dbus is learning a whole new dimension of how to control your system. And it's much like learning a new language.


Resources

We will use the d-feet application (sudo apt-get install d-feet) to search for dbus resources on our system. We will use the dbus-send shell command to interact with dbus.

That's it. One helper application and one command. The rest is up to you.


dbus Grammar

Here's a sample dbus command. All it does is tell Network Manager to enable networking, just like you right-clicked on the NM icon and ticked "Enable Networking". In english, we would say something a bit more like: "Hey Network Manager, (you) please turn on (entire) networking"

dbus commands have four important elements: Destination, path, method, and message.

$ dbus-send --system --print-reply \                  # (Hey,)
            --dest=org.freedesktop.NetworkManager \   # destination (Network Manager)
            /org/freedesktop/NetworkManager \         # path    (you)
            org.freedesktop.DBus.Properties.Set \     # method  (turn)
            string:"org.freedesktop.NetworkManager" \ # message (networking)
            string:"NetworkingEnabled" \              # message (entire) 
            variant:boolean:true                      # message (on)


dbus grammar is very simple, but that doesn't mean it is easy the first time you try it. The grammar is meant for machines.

Destination: Which process/program/application you are talking to.
Path: Which resource you are talking about.
Method: What you are telling the destination to do with the path.
Message: Specific information needed for the method to make sense.

For example: "Sally, please throw the red ball to Fred."

You are talking to Sally (in english Grammar, often but not always the subject).
Sally is the destination.

The red ball is the resource (in english grammar, usually the direct object).
The red ball is the path.

"Throw" is the action you want Sally to do with the ball (in english grammar, usually the verb)
Throw is the method.

"To Fred" is additional information that makes the throw successful.
To Fred is message that is needed by the method.


dbus Syntax

The grammar is the hardest part - restructuring your statement clearly in those four terms. After that, it's easy.

The syntax of the actual command using dbus-send  is explained thoroughly in man dbus-send, though some of the teminology differs a bit.

dbus-send   [--system   |   --session]   [--dest=NAME]  [--print-reply]
       [--type=TYPE] <destination object="" path=""> <message name=""> [contents ...]

system vs. session simply refers to which bus. There are usually two running, one at user (session) level, and one at admin/sudo/root (system) level.

"type" simply means if it's a signal or a method call. Signals are usually one-way, little response is generated. A method call usually creates a response, even if just an acknowledgement.

"print reply" prints the response from dbus, if any.


A more simple (and slightly rearranged) syntax that we use is:

dbus-send   [ --system| --session] --print-reply --dest=DEST PATH METHOD [MESSAGE]

$ dbus-send --system --print-reply \                  # Root-level, since it's hardware
            --dest=org.freedesktop.NetworkManager \   # destination  (dest)
            /org/freedesktop/NetworkManager \         # path         (path)
            org.freedesktop.DBus.Properties.Set \     # message name (method)
            string:"org.freedesktop.NetworkManager" \ # message      (contents)
            string:"NetworkingEnabled" \              # message      (contents) 
            variant:boolean:true                      # message      (contents)

This multi-line command connected with backslashes (\) is just for readability, especially in scripts. When I really type them in, they look like this:

$ dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.DBus.Properties.Set string:"org.freedesktop.NetworkManager" string:"NetworkingEnabled" variant:boolean:true



Using Shell Variables

Simple grammar and syntax means that it's easy to use shell variables to improve readbility and reduce typos, especially in scripts.

dest="org.freedesktop.NetworkManager"
path="/org/freedesktop/NetworkManager"
method="org.freedesktop.DBus.Properties.Set"

# Enable Networking
dbus-send --system --print-reply --dest="$dest" "$path" "$method" \
          string:"$dest" string:"NetworkingEnabled" variant:boolean:true

And, of course, you can nest entire commands within variables:

dest="org.freedesktop.NetworkManager"
path="/org/freedesktop/NetworkManager"
method="org.freedesktop.DBus.Properties.Set"

network_command="dbus-send --system --print-reply --dest=$dest $path $method"
enable_network="string:$dest string:"NetworkingEnabled" variant:boolean:true"

# Enable Networking
$network_command $enable_network

Next, let's ligure out how to find all those weird dbus properties using introspection.