source: project/wiki/dbus @ 10325

Last change on this file since 10325 was 10325, checked in by svnwiki, 12 years ago

Changes applied for ecloud (72.208.150.200) through svnwiki:

dbus:enable-polling-thread! etc.

File size: 11.5 KB
Line 
1[[tags: egg]]
2
3== dbus
4
5[[toc:]]
6
7=== Overview
8
9This 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).
10
11=== Goals & status
12
13<table>
14<tr><th>Goal</th><th>Achieved?</th></tr>
15<tr><td>send signals</td><td>yes</td></tr>
16<tr><td>call methods in other processes, and get the return values</td><td>yes</td></tr>
17<tr><td>call methods in other processes asynchronously, and the return values come back to a callback later</td><td></td></tr>
18<tr><td>register a procedure as a handler for a service/method</td><td>yes</td></tr>
19<tr><td>assign a path to a TinyClos object and map applicable generic functions as dbus methods</td><td></td></tr>
20<tr><td>create proxy objects matching remote objects</td><td></td></tr>
21<tr><td>discover services locally</td><td></td></tr>
22<tr><td>discover services on nearby machines</td><td></td></tr>
23<tr><td>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.)</td><td>yes</td></tr>
24<tr><td>support all DBus data types for method parameters and return values</td><td></td></tr>
25</table>
26
27=== Author
28
29[[Shawn Rutledge]]
30
31=== Requirements
32
33libdbus and its headers
34
35=== Download
36
37[[http://www.call-with-current-continuation.org/eggs/dbus.egg|dbus.egg]]
38
39=== License
40
41libdbus has historically had a GPL license.  The [[http://www.freedesktop.org/wiki/Software/dbus|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.
42
43=== Version
44
45As of version 0.8, it seems to be working for the limited use cases of sending and receiving method calls, but the interface should not be considered "frozen" yet. 
46
47=== DBus in general
48
49These are the definitions of the (confusing, redundant) terminology used in DBus, as the author understands them:
50
51; bus : The aggregator and dispatcher of messages between processes.  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.
52
53; service : looks like a reversed domain name.  The destination of a message.  Sometimes called the "bus name".
54
55; path : think of it like the path part of a URL.  Perhaps a unique path maps to a unique object.
56
57; interface : a partitioned set of methods which is being offered, like a Java interface or an abstract class.
58
59; member name : also called method name, or the name of the signal or message.
60
61; method : a piece of code to be invoked when a particular message is received.  (This is typical object-oriented terminology.)
62
63And this egg introduces one more:
64
65; context : a combination of bus, service, interface and path.  That and a method name will get you a unique identifier for a callback (AKA method or message handler).
66
67Some of those would seem to be optional, because the total 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.
68
69Use dbus-monitor to see all the dbus traffic (on the session bus by default).
70
71A many-to-many "bus" exists as a running dbus-daemon process.  Each application which is interested in using that bus connects to the daemon via Unix-domain sockets.  The daemon collects incoming messages and dispatches them to the connected processes which have expressed interest in receiving particular categories of messages.  Usually there is one running instance of dbus-daemon for the system bus, and one running instance for each session bus: each user who is logged in and running a desktop session is typically running one instance of the daemon.
72
73A one-to-one 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.
74
75=== Data types
76
77DBus protocol (unlike XML, for example) allows sending real native datatypes across the connection.  In fact it provides more data types than does Chicken.  So when you pass some parameters along with a method call, these are the default conversions:
78
79<table>
80<tr><th>Chicken data type</th><th>DBus data type</th></tr>
81<tr><td>fixnum</td><td>DBUS_TYPE_INT32</td></tr>
82<tr><td>flonum</td><td>DBUS_TYPE_DOUBLE</td></tr>
83<tr><td>boolean</td><td>DBUS_TYPE_BOOLEAN</td></tr>
84<tr><td>anything else</td><td>DBUS_TYPE_STRING (as with XML, sigh)</td></tr>
85</table>
86
87When a DBus message is received, the parameters are converted similarly, but unsupported DBus types will be converted to #f.
88
89Watch out for cases when Chicken converts an integer to a flonum, because it was too large to fit in a fixnum.  It will go across the DBus connection as a double, which might not be what you wanted.
90
91It is planned to support requests for conversion to other DBUS types, in case you need to interface with an existing service that requires datatypes other than the typical ones above.  DBus supports arrays, too.  They should be converted to Chicken vectors, of course.  There are also variants and structs.  None of these conversions are done yet. 
92
93=== Exported functions
94
95dbus:make-context : glom together a bus, service, interface and path into an object that you can conveniently hold for later use.  The choices for bus are dbus:session-bus (which is the default if you don't specify it), dbus:system-bus and dbus:starter-bus.  The service, interface and path can be given as strings or symbols.  Symbols would be preferred; if you provide strings, dbus:make-context will convert them to symbols.  The default for path is "/" so if you don't need a hierarchical organization of "objects", you don't need to specify it.
96
97dbus:send : send a message, and don't bother waiting for the response.
98
99dbus:send-and-await-reply : call a remote method, wait for the reply, and receive the return values from the remote method, as a list.
100
101dbus:register-method : provide a handler to be called when the given method-name is received and matches the given context.
102
103dbus:enable-polling-thread! : enable or disable the polling thread, and set the polling interval in seconds
104
105dbus:poll-for-message : check once whether any incoming DBus message is waiting, and if so, dispatch it to the appropriate callback (which you have previously registered using dbus:register-method).  Returns #t if it received a message, #f if not.
106
107=== Examples
108
109These are in the test subdirectory in svn.  (Not included in the egg itself at this point)
110
111==== Examples you can test with QT
112
113QT 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:
114
115<enscript highlight=scheme>
116(use dbus)
117(define rc-car-context (dbus:make-context
118        service: 'com.trolltech.CarExample
119        interface: 'com.trolltech.Examples.CarInterface
120        path: '/Car))
121(dbus:send rc-car-context "turnRight")
122</enscript>
123
124That example called a method but it did not expect any return values.
125
126Now suppose you want to simulate the car, so you can use the above example to control your own car rather than the QT one.  And suppose you want to poll for messages manually rather than via the default SRFI-18 polling thread:
127
128<enscript highlight=scheme>
129(use dbus)
130
131(define (turn-right) (printf "car is turning to the right~%"))
132(define (turn-left) (printf "car is turning to the left~%"))
133
134(define rc-car-context (dbus:make-context
135        service: 'com.trolltech.CarExample
136        path: '/Car
137        interface: 'com.trolltech.Examples.CarInterface ))
138
139(dbus:enable-polling-thread enable: #f)
140
141(dbus:register-method rc-car-context "turnRight" turn-right)
142(dbus:register-method rc-car-context "turnLeft" turn-left)
143
144(let loop ()
145        (dbus:poll-for-message)
146        (loop))
147</enscript>
148
149dbus:register-method starts a polling loop the first time that it is called.  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.
150
151If the polling thread doesn't work, and you would prefer to poll manually, you can call (dbus:enable-polling-thread! enable: #f) to stop the thread (or to prevent it from being started when you register a new method), and then call dbus:poll-for-message periodically.  Both of those functions can take an optional bus: parameter (which defaults to dbus:session-bus, naturally).  dbus:poll-for-message can also take an optional timeout: parameter (which is 0 by default, so that it is a non-blocking call).
152
153==== Examples based on the DBus Tutorial
154
155The next example, taken from the [[http://dbus.freedesktop.org/doc/dbus/libdbus-tutorial.html|DBus tutorial]], shows how to deal with return values.  First the "listener" program which will answer the query:
156
157<enscript highlight=scheme>
158(use dbus)
159(define (query . params)
160        (printf "got a query; params: ~s~%" params)
161        ;; the response to the query:
162        `(#t 42))
163(define ctxt (dbus:make-context
164        service: 'test.method.server
165        interface: 'test.method.Type
166        path: '/test/method/Object))
167(dbus:register-method ctxt "Method" query)
168</enscript>
169
170And now the program which sends a query and prints out the response:
171
172<enscript highlight=scheme>
173(use dbus)
174(define ctxt (dbus:make-context
175        service: 'test.method.server
176        interface: 'test.method.Type
177        path: '/test/method/Object))
178(let ([response (dbus:send-and-await-reply ctxt "Method" "query"
179                "What is the meaning of life, the universe and everything?") ])
180(printf "sent a very important query with a known answer; got flippant response ~s~%" response)
181        (if (and (list? response) (eq? 42 (cadr response)))
182                (printf "bingo!~%")
183                (printf "and the answer is wrong too!  Bad supercomputer, bad!~%")))
184</enscript>
185
186What do you get if you combine a remote-controlled mobile thingy with a supercomputer capable of deep thought?  A paranoid android of course!  This example in the test directory handles both kinds of methods from the two examples above (the query and the turnLeft/turnRight commands) and proves that one polling thread is enough to handle multiple, completely different contexts.  So registering more than one method is low-cost compared to registering the first one.
Note: See TracBrowser for help on using the repository browser.