You are looking at historical revision 10268 of this page. It may differ significantly from its current revision.
dbus
Overview
This is a binding for libdbus 1.0 (and hopefully 1.2.x). DBus is a popular IPC (inter-process communication) protocol which is often used between system components (for example hald informs applications when new hardware becomes available, gpsd informs apps when the location has changed, or an application requests gsmd to place a phone call).
Goals & status
Goal | Achieved? |
---|---|
send signals | yes |
call methods in other processes, and get the return values | yes |
call methods in other processes asynchronously, and the return values come back to a callback later | |
register a procedure as a handler for a service/method | yes |
assign a path to a TinyClos object and map applicable generic functions as dbus methods | |
create proxy objects matching remote objects | |
discover services locally | |
discover services on nearby machines | |
user code to do any of the above should be minimal: abstract away the orthogonal extra steps (open a connection, start a polling thread, etc.) | yes |
Author
Requirements
libdbus and its headers
Download
License
libdbus has historically had a GPL license. The dbus homepage refers to an incomplete "planned X11/MIT license change due to a couple of license holders who have yet to respond. For the most part this license change is being pursued to simplify licensing issues and fix a couple of licensing corner cases. When this happens D-Bus will be released under the 1.2.0 version." So this egg is released under the MIT license, however if you link it with a version prior to 1.2.0, then you are probably bound by the terms of the GPL.
DBus in general
These are the definitions of the (confusing, redundant) terminology used in DBus, as the author understands them:
- bus
- The usual choices are system bus, session bus or an app-specific bus. This egg uses the session bus by default. It is the same bus used by desktop session services, like KDE components for example. Accessing the system bus requires special permission. An app-specific bus does not promote application interoperability. So that leaves the session bus as generally being the most appropriate.
- service
- looks like a reversed domain name. The destination of a message. Sometimes called the "bus name".
- path
- think of it like the path part of a URL. Perhaps a unique path maps to a unique object.
- interface
- a partitioned set of methods which is being offered, like a Java interface or an abstract class.
- member name
- also called method name, or the name of the signal or message.
Some of those would seem to be optional, because the total concatenated namespace ends up much deeper than e.g. a URL. However not enough testing has been done to confirm that if you leave out the service and the interface, for example, you won't miss them. Also it's not yet clear which of those ought to be "discoverable" in the sense that you can enumerate what is available on a particular bus.
Use dbus-monitor to see all the dbus traffic (on the session bus by default).
A many-to-many "bus" exists as a running dbus-daemon process. Each application which is interested in using that bus connects to it via Unix-domain sockets. So usually there are two running instances of dbus-daemon, for the system and session buses respectively (assuming only one user is logged in and running a desktop session). An application-specific bus can bypass the daemon: one app connects directly to the other. But this is not a flexible service-oriented approach to IPC, so it is not usually done, and this egg does not support it.
Examples
These are in the test subdirectory in svn. (Not included in the egg itself at this point)
Examples you can test with QT
QT includes a DBUS remote-controlled car example. E.g. it might be located in /usr/share/qt4/examples/qdbus/remotecontrolledcar/car depending on your distro. If you run the car, you can cause the wheels of the car to turn to the right by doing this:
(use dbus) (define rc-car-context (dbus:make-context service: 'com.trolltech.CarExample interface: 'com.trolltech.Examples.CarInterface path: '/Car)) (dbus:send rc-car-context "turnRight")
That example called a method but it did not expect any return values.
Now suppose you want to simulate the car, so you can use the above example to control your own car rather than the QT one:
(use dbus) (define (turn-right) (printf "car is turning to the right~%")) (define (turn-left) (printf "car is turning to the left~%")) (define rc-car-context (dbus:make-context service: 'com.trolltech.CarExample path: '/Car interface: 'com.trolltech.Examples.CarInterface )) (dbus:register-method rc-car-context "turnRight" turn-right) (dbus:register-method rc-car-context "turnLeft" turn-left)
dbus:register-method starts a polling loop. So you can then run the program above which does dbus:send, and you will see the appropriate printf statement execute asynchronously when the message is received. However the polling thread is subject to the usual limitations of Chicken threads: if there is any blocking I/O, which is waiting for something, then all threads are blocked. That means you should not use the readline egg for example, because the polling thread will be blocked between each time that you type something and hit Enter.
If the threads are causing problems and you would prefer to poll manually, the dbus:poll-for-message procedure is exported for that purpose, however there needs to be some mechanism to prevent the creation of the polling thread; that is not done yet.
Examples based on the DBus Tutorial
The next example, taken from the tutorial, shows how to deal with return values. First the "listener" program which will answer the query:
(use dbus) (define (query . params) (printf "got a query; params: ~s~%" params) ;; the response to the query: `(#t 42)) (define ctxt (dbus:make-context service: 'test.method.server interface: 'test.method.Type path: '/test/method/Object)) (dbus:register-method ctxt "Method" query)
And now the program which sends a query and prints out the response:
(use dbus) (define ctxt (dbus:make-context service: 'test.method.server interface: 'test.method.Type path: '/test/method/Object)) (let ([response (dbus:send-and-await-reply ctxt "Method" "query" "What is the meaning of life, the universe and everything?") ]) (printf "sent a very important query with a known answer; got flippant response ~s~%" response) (if (and (list? response) (eq? 42 (cadr response))) (printf "bingo!~%") (printf "and the answer is wrong too! Bad supercomputer, bad!~%")))