Net::DBus Binding Tutorial
AN!Wiki :: Net::DBus Binding Tutorial
Introduction to the Perl DBus Binding 'Net::DBus'.
Note: This section needs updating. Since writing this I have written a more concise introduction to Net::DBus with working examples. Please see: TPM Talk: An Introduction to 'D-Bus' in Perl
Freedesktop.org's DBus is a relatively new, but well established method of interprocess communication. It is designed to be a very low latency messaging system and is designed to be implemented on many languages and operating systems.
Most languages, including Perl, simply access to DBus buses via "Bindings". A binding is simple an intermediary program designed to make access to DBus methods simple and formatted in a way familiar to the programmer. In perl, the official DBus binding is a set of modules collectively known as 'Net::DBus', written by Daniel Berrange and made available on the CPAN network.
For the rest of this document, the term DBus will collectively refer to the underlying DBus system and the 'Net::DBus' implementation.
Why Would I Want To Use DBus?
DBus offers a very intelligent and very flexible method of communication between programs running on a given system. It is technically capable of network communication, though this was not it's design goal. Think of DBus as a way to allow fast, open communication between your program(s) and third party programs.
Purpose and Target Audiance of this Document
This document is targeted at people who are familiar with Perl programming but are otherwise completely new to DBus and it's concepts. It will provide step by step instructions and provide sample, executable code to shows you how to do each of the base tasks provided by DBus via the Net::DBus bindings.
If you are already familiar with DBus and Perl, and simply want to see how DBus is implemented on Perl, you will be best served by reviewing "Net::DBus::Tutorial" on the CPAN.
Overview of Methods Provided by DBus
From a programming point of view, there are three main ways that you may want to use the DBus. Each of these three methods will be shown using a small, fully functioning program that you will be able to copy, run and edit.
Using Services on an Existing Message Bus
A client program simply connects to an existing message bus. Once connected, it can listen for signals from other applications on the bus. It can also call methods on objects that have been published on the bus.
Publish a Service on an Existing Bus
In this example, we will create a new service on the well-known 'system' bus. Once created, we will create methods on this bus to provide a way of communicating with child processes. Last, we will create a small sample program that will connect to this bus, check if a method for a given client exists and, if so, request information from the child process via the DBus.
Create a Dedicated Server
Lastly, we will reproduce what we did in the second step, but this time we will create our own dedicated service that clients will connect to via a UNIX socket.
First, Some Key Definitions
There are a few terms you will need to become familiar with. These terms are frequently found in DBus documentation.
Note: Many of the below definitions are still being developed and contain contributions from others, as noted. Please do not rely on any of these definitions or take them as accurate until this notice has been removed.
If you are unfamiliar with Object Oriented concepts and terms, you may be well served by reading perltoot. Read it either on the web or, if you have 'perldoc' installed, by running:
An address is simply the point at which it watches for connections from clients on. This could be a UNIX socket, a TCP address, a memory address or some future address that may be added to DBus in the future.
- unix:path=/path/to/socket Server listens on the defined UNIX socket file.
A binding is simply a programming language's library used to simplify access to the low-level DBus API calls.
'Net::DBus' and it's associated modules are Perl's DBus bindings. They allow for "perl-like" access to the DBus and hide a lot of the low-level work that needs to be done, simplifying application development.
A 'bus' is an program whose job it is to route messages between applications who have connected to it. In DBus, the 'dbus-daemon' program provides this method. Part of the job of routing is handling security and determining who is allowed to do what.
DBus offers two buses; the 'system' bus and the 'session' bus.
- The 'system' bus is accessible by all users and programs on a system, including the root user, and thus has tighter restrictions. For example; HAL uses the 'system' bus to announce changes in the underlying hardware.
- The 'session' bus is a per-user bus that various applications a given user is using can connect to. For example, the popular instant messenger 'Pidgin' uses the session bus.
The bus daemon can also start applications on demand. When needed, the dbus-daemon will look in a special directory for service files. These files are very simple, and simply contain the name of the given interface and a full path to a program. When it finds a match, it will start the associated program.
There are a few restrictions on bus names:
- Interface names must never exceed 255 characters.
- Valid Bus Names must contain at least two elements.
- Elements are separated by a period ('.'), no double-period.
- Periods must not be at the beginning of the interface name.
- Elements must only use the ASCII alphanumeric, hyphen or underscore characters ('[a-z][A-Z][0-9][-][_]').
- Note: Hyphens are allowed.
When your program listens for connections directly, for example by listening to a UNIX socket, then the bus is not needed. It is use primarily when programs use the dbus-daemon to tell various programs on the bus appart.
In DBus, the concept of a client is simply to describe a program that connects to a message bus. Once the connection is established, messages are symetrical with neither program acting in a particular server role, from the message bus point of view.
An interface is like a named group of methods in a perl module. In perl, you might choose to create a named group of methods that need to be explicitely exported by a client. An example of this is how you need to specify 'use Net::DBus (:typing);' if you want access to the explicit typing method. In this example, 'typing' would be like a DBus interface which references the 'dbus_int16', 'dbus_uint16', 'dbus_int32', etc. methods.
Interface names are generally, but not necessarily, based on the domain name of the author or project that created that interface. For example, the DBus interface itself is based on the name of the parent project's web address, Freedesktop.org. So the interface for talking to the bus server itself is 'org.freedesktop.DBus'. Note the reverse order, relative to a domain URL.
There are a few rules when creating an interface name.
- Interface names must never exceed 255 characters.
- Valid interface names must contain at least two elements.
- Elements are separated by a period ('.'), no double-period.
- Periods must not be at the beginning or end of the interface name.
- Interface elements must be UTF-8 encoded.
- Elements must only use the ASCII alphanumeric or underscore characters ('[a-z][A-Z][0-9][_]').
- Note: Hyphens are not allowed.
- 'org.freedesktop.DBus.Local' is reserved.
A method is a function or block of code that does something, like a Perl subroutine.
You call a method and can (optionally) pass arguments to it. The method can (optionally) return arguments.
- General convention suggests naming your methods using "Windows Style Capitalization", for example, "GetClientStatus".
- Methods can not contain a period, as the interface is examined and the last element, determined by the period separators, is taken as the method name. For example, the object "org.tle-bu.GetClientStatus" is split on the last period, so "org.tle-bu" is taken to be the interface and "GetClientStatus" is taken to be the method name.
This is used to prevent different programs from step on one and others toes. Generally this is made up of the domain of the company or group developing a program. For example, DBus itself, developed by Freedesktop.org, uses the name space 'org.freedesktop'. Likewise, the TLE-BU backup program uses the 'org.tle-bu' namespace.
In this way, two different applications could share a common method, ie: 'CheckClientStatus', and other programs would easily be able to identify which parent owns that given method. To continue the example, if DBus and TLE-BU both were to use a method with this name, it would easy to be able to tell them apart because their respective interfaces would be 'org.freedesktop.someapp.CheckClientStatus' and 'org.tle-bu.CheckClientStatus'. Note that the name space refers to just the root portion of the name.
This is not so much a programmatic term as it is a concept.
An object is a collection of methods, signals and properties.
An object provides zero or more methods and emits zero or more signals (but at least one of either). In DBus, objects are expressed as path which look very similar to a UNIX filesystem. Unlike a file system though, an object can, at the same time, be a method or signal and have child objects.
For example, you may have an object with two methods and a signal and a parameter published under it. Let's say the methods are 'ClientConnect' and 'ClientDisconnect', the signal is called 'ClientAnnounce' and a writable property called 'ClientOnlineSince'. Lets then say that we use the object path '/org/tle-bu' to publish them under. Thus, we can access these objects at:
/org/tle-bu/ClientConnect /org/tle-bu/ClientDisconnect /org/tle-bu/ClientAnnounce /org/tle-bu/ClientOnlineSince
A real-world example would be HAL's 'Manager' object which is found at the path:
Please note that the object's path does not need to match the program's namespace, or even be human-readable. It is simply "best practice", and may well not make sense for your application.
There are a few rules when creating an object path names.
A path is the actual address that an object can be found at which looks like a UNIX file system. Please see the 'Object' definition for more information.
To publish a method or an object is to simply make it available on the bus to other programs.
A server is an application that provides a service via a message bus. Often, a server will provide "introspection data" to allow remote programs to query the server application for a list of methods and objects a server provides.
In DBus, the concept of a server is simply to describe a program that listens for connections from clients. Once the connection is established, messages are symetrical with neither program acting in a particular server role, from the message bus point of view.
A service is the well known name of a server. It is the root of the program and thus must be unique on a bus. In this way, it acts as the root portion in interface names.
To use HAL as an example, and to tie all the components together, the interface 'org.freedesktop.Hal.Manager.GetAllDevices' can be broken up like this:
org.freedesktop.Hal.Manager.GetAllDevices | | | | \-----------/ <= The name of the method. |-------------+---+------/ <================ The full interface. |-------------+--/ <======================== Service, name of the HAL server. \------------/ <============================ Name space used by 'Freedesktop.org'.
As an exercise in showing a full interface using Perl terminology, you might say:
\/=================================== The namespace used by Freedesktop.org. /-------------\ org.freedesktop.Hal.Manager.GetAllDevices \-----------------/ \-----/ \-----------/ ^ ^ ^ | | \======== The specific method provided by a perl module. | \==================== The name of the perl module you are using. \================================== The program itself.
Unique Connection Name
This is often shortened to UCN. When a client connects to a message bus, the dbus daemon assigns it a unique name known as the UCN. This name starts with a colon (':') followed by a string, for example ':34-907'. This UCN is never re-used for as long as the daemon process itself runs. Thanks to this, you to be sure that if you see a UCN that you have seen before, you can be certain it is the same client. The string following the ':' has no meaning itself, it is simply guaranteed to be unique.
Well Known Name
Well known names in DBus are similar to domain names on the Internet; They simply map to a UCN. This way, a program could be written that will always look for a particular server, method or object and not need to worry about where it actually is. To continue the network analogy; This allows you to say "I want to connect to https://alteeve.ca" and not need to worry about what the underlying IP address is, even if it changes.
Often times a program will (arbitrarily) define that a given program, say "org.freedesktop.TextEditor" must publish an object at "/org/freedesktop/TextFileManager" and support the interface "org.freedesktop.FileHandler". These conventions are not enforced by DBus however.
When a program maps a well known name to a UCN, it is said to "own" the name. Other programs can then use the message bus to monitor the lifecycle of the owning application. If the owning program crashes or is closed, a signal is out indicating that the given name(s) has lost it's owner.
Putting it All Together
Now that we have a common language, lets start with a high-level overview of how a method call might work.
In order to use a method published on a message bus, we need some information on how to find it. In order, that is;
# Address; how and where clients connect to the server. # Bus Name; Where on the bus is the program we are or want to connect to. Not needed directly connecting to a server. Needed when using the dbus-daemon. # Path; This is the path to the object you are interested in. # Interface; This is what publishes the method we are using. This is also optional in many cases and is primarily used for historical reasons. # Method; This is the actually method we what to use.
High-Level Overview of the Low Level DBus API
Below are the complete, executable Perl programs containing all of the code snippets discussed in this tutorial. You can download and play with these as you wish. They are all released under the GPL version 2, same as the TLE-BU program itself.
This shows simple how to connect to a bus, connect to a service on that bus, get a handle to an interface and one of it's methods and add a few handles. It uses HAL to show these methods.
List of modules in the Net::DBus Perl bindings
This is a list of all the people who have contributed to this document. My heartfelt thanks!
- Daniel Berrange, author of the Net::DBus Bindings.
- David Belser, author of (what program(s)?)
This section will be removed before the final draft is completed. It is here as a scratch pad for my notes while writing the initial version of this tutorial.
|Any questions, feedback, advice, complaints or meanderings are welcome.|
#clusterlabs on Libera Chat
|© Alteeve's Niche! Inc. 1997-2023||Anvil! "Intelligent Availability®" Platform|
|legal stuff: All info is provided "As-Is". Do not use anything here unless you are willing and able to take responsibility for your own actions.|