Contents

Performing remote method invocations over the D-Bus is only one half of D-Bus capabilities. As was noted before, D-Bus also supports a broadcast method of communication, which is asynchronous. This mechanism is called a signal (in D-Bus terminology), and it is useful when several receivers must be notified about a state change that could affect them. Some examples where signals could be useful are notifying a lot of receivers, when the system is being shut down, network connectivity has been lost, and similar system-wide conditions. This way, the receivers do not need to poll for the status continuously.

However, signals are not the solution to all problems. If a recipient is not processing its D-Bus messages quickly enough (or there just are too many), a signal might get lost on its way to the recipient. Other complications can also occur, as with any RPC mechanism. For these reasons, if the application requires extra reliability, you need to think how to arrange it. One possibility is to occasionally check the state that the application is interested in, assuming it can be checked over the D-Bus. This, however, should not be done too often; the recommended interval is once a minute or less often than that, and only when the application is already active for other reasons. This model leads to a reduction in battery life, so its use should be carefully weighed.

Signals in D-Bus are able to carry information. Each signal has its own name (specified in the interface XML), as well as "arguments". In signal's case, the argument list is actually a list of information that is passed along the signal and should not be confused with method call parameters (although both are delivered in the same manner).

Signals do not "return", meaning that when a D-Bus signal is sent, no reply is received, nor is one expected. If the signal emitter wants to be sure that the signal was delivered, additional mechanisms need to be constructed for this (D-Bus does not include them directly). A D-Bus signal is very similar to most datagram-based network protocols, for example UDP. Sending a signal succeeds, even if there are no receivers interested in that specific signal.

Most D-Bus language bindings attempts to map D-Bus signals into something more natural in the target language. Since GLib already supports the notion of signals (as GLib signals), this mapping is quite natural. So in practice, the client registers for GLib signals, and then handles the signals in callback functions (a special wrapper function must be used to register for the wrapped signals: dbus_g_proxy_connect_signal).

<node><interfacename="org.maemo.Value"><!- ... Listing cut for brevity ... -><!- Signal (D-Bus) definitions -><!- NOTE: The current version of dbus-bindings-tool doesn't actually enforce the signal arguments _at_all_. Signals need to be declared in order to be passed through the bus itself, but otherwise no checks are done! For example, you could leave the signal arguments unspecified completely, and the code would still work. -><!- Signals to tell interested clients about state change. We send a string parameter with them. They never can have arguments with direction=in. -><signalname="changed_value1"><argtype="s"name="change_source_name"direction="out"/></signal><signalname="changed_value2"><argtype="s"name="change_source_name"direction="out"/></signal><!- Signals to tell interested clients that values are outside the internally configured range (thresholds). -><signalname="outofrange_value1"><argtype="s"name="outofrange_source_name"direction="out"/></signal><signalname="outofrange_value2"><argtype="s"name="outofrange_source_name"direction="out"/></signal></interface></node>

The signal definitions are required if the dbus-bindings-tool is used; however, the argument specification for each signal is not required by the tool. In fact, the tool ignores all argument specifications, and as can be seen below, a lot of "manual coding" has to be made in order to implement and use the signals (on both the client and server side).

The signal names are defined in a header file so that they can easily be changed later, and the header file is used in both the server and the client. The following is the section with the signal names: glib-dbus-signals/common-defs.h

/* Symbolic constants for the signal names to use with GLib.
These need to map into the D-Bus signal names. */#define SIGNAL_CHANGED_VALUE1 "changed_value1"#define SIGNAL_CHANGED_VALUE2 "changed_value2"#define SIGNAL_OUTOFRANGE_VALUE1 "outofrange_value1"#define SIGNAL_OUTOFRANGE_VALUE2 "outofrange_value2"

Before a GObject can emit a GLib signal, the signal itself needs to be defined and created. The best way to do this is to use the class constructor code (because the signal types need to be created only once): glib-dbus-signals/server.c

/**
* Define enumerations for the different signals that we can generate
* (so that we can refer to them within the signals-array [below]
* using symbolic names). These are not the same as the signal name
* strings.
*
* NOTE: E_SIGNAL_COUNT is NOT a signal enum. We use it as a
* convenient constant giving the number of signals defined so
* far. It needs to be listed last.
*/typedefenum{
E_SIGNAL_CHANGED_VALUE1,
E_SIGNAL_CHANGED_VALUE2,
E_SIGNAL_OUTOFRANGE_VALUE1,
E_SIGNAL_OUTOFRANGE_VALUE2,
E_SIGNAL_COUNT
} ValueSignalNumber;/*... Listing cut for brevity ...*/typedefstruct{/* The parent class state. */
GObjectClass parent;/* The minimum number under which values cause signals to be
emitted. */
gint thresholdMin;/* The maximum number over which values cause signals to be
emitted. */
gint thresholdMax;/* Signals created for this class. */
guint signals[E_SIGNAL_COUNT];} ValueObjectClass;/*... Listing cut for brevity ...*//**
* Per class initializer
*
* Sets up the thresholds (-100 .. 100), creates the signals that we
* can emit from any object of this class and finally registers the
* type into the GLib/D-Bus wrapper so that it may add its own magic.
*/staticvoid value_object_class_init(ValueObjectClass* klass){/* Because all signals have the same prototype (each gets one
string as a parameter), we create them in a loop below. The only
difference between them is the index into the klass->signals
array, and the signal name.
Because the index goes from 0 to E_SIGNAL_COUNT-1, we just specify
the signal names into an array and iterate over it.
Note that the order here must correspond to the order of the
enumerations before. */const gchar* signalNames[E_SIGNAL_COUNT]={
SIGNAL_CHANGED_VALUE1,
SIGNAL_CHANGED_VALUE2,
SIGNAL_OUTOFRANGE_VALUE1,
SIGNAL_OUTOFRANGE_VALUE2 };/* Loop variable */int i;
dbg("Called");
g_assert(klass != NULL);/* Setup sane minimums and maximums for the thresholds. There is no
way to change these afterwards (currently), so you can consider
them as constants. */
klass->thresholdMin =-100;
klass->thresholdMax =100;
dbg("Creating signals");/* Create the signals in one loop, because they all are similar
(except for the names). */for(i =0; i < E_SIGNAL_COUNT; i++){
guint signalId;/* Most of the time you encounter the following code without
comments. This is why all the parameters are documented
directly below. */
signalId =
g_signal_new(signalNames[i],/* str name of the signal *//* GType to which signal is bound to */
G_OBJECT_CLASS_TYPE(klass),/* Combination of GSignalFlags which tell the
signal dispatch machinery how and when to
dispatch this signal. The most common is the
G_SIGNAL_RUN_LAST specification. */
G_SIGNAL_RUN_LAST,/* Offset into the class structure for the type
function pointer. Because we are implementing a
simple class/type, we leave this at zero. */0,/* GSignalAccumulator to use. We do not need one. */
NULL,/* User-data to pass to the accumulator. */
NULL,/* Function to use to marshal the signal data into
the parameters of the signal call. Luckily for
us, GLib (GCClosure) already defines just the
function that we want for a signal handler that
we do not expect any return values (void) and
one that accepts one string as parameter
(besides the instance pointer and pointer to
user-data).
If no such function exists, you need
to create a new one (by using glib-genmarshal
tool). */
g_cclosure_marshal_VOID__STRING,/* Return GType of the return value. The handler
does not return anything, so we use G_TYPE_NONE
to mark that. */
G_TYPE_NONE,/* Number of parameter GTypes to follow. */1,/* GType(s) of the parameters. We only have one. */
G_TYPE_STRING);/* Store the signal Id into the class state, so that we can use
it later. */
klass->signals[i]= signalId;/* Proceed with the next signal creation. */}/* All signals created. */
dbg("Binding to GLib/D-Bus");/*... Listing cut for brevity ...*/}

The signal types are kept in the class structure, so that they can be referenced easily by the signal emitting utility. The class constructor code also sets up the threshold limits, which in this implementation are immutable (meaning that they cannot be changed). Experiment with the implementation and add more methods to adjust the thresholds as necessary.

Emitting the signals is quite easy, but in order to reduce code amount, a utility function is created to launch a given signal based on its enumeration: glib-dbus-signals/server.c

/**
* Utility helper to emit a signal given with internal enumeration and
* the passed string as the signal data.
*
* Used in the setter functions below.
*/staticvoid value_object_emitSignal(ValueObject* obj,
ValueSignalNumber num,const gchar* message){/* In order to access the signal identifiers, we need to get a hold
of the class structure first. */
ValueObjectClass* klass = VALUE_OBJECT_GET_CLASS(obj);/* Check that the given num is valid (abort if not).
Given that this file is the module actually using this utility,
you can consider this check superfluous (but useful for
development work). */
g_assert((num < E_SIGNAL_COUNT)&&(num >= 0));
dbg("Emitting signal id %d, with message '%s'", num, message);/* This is the simplest way of emitting signals. */
g_signal_emit(/* Instance of the object that is generating this
signal. This is passed as the first parameter
to the signal handler (eventually). But obviously
when speaking about D-Bus, a signal caught on the
other side of D-Bus is first processed by
the GLib-wrappers (the object proxy) and only then
processed by the signal handler. */
obj,/* Signal id for the signal to generate. These are
stored inside the class state structure. */
klass->signals[num],/* Detail of signal. Because we are not using detailed
signals, we leave this at zero (default). */0,/* Data to marshal into the signal. In our case it is
just one string. */
message);/* g_signal_emit returns void, so we cannot check for success. *//* Done emitting signal. */}

To avoid having to check the threshold values in multiple places in the source code, the threshold value is also implemented as a separate function. Emitting the "threshold exceeded" signal is still up to the caller. glib-dbus-signals/server.c

/**
* Utility to check the given integer against the thresholds.
* Returns TRUE if thresholds are not exceeded, FALSE otherwise.
*
* Used in the setter functions below.
*/static gboolean value_object_thresholdsOk(ValueObject* obj,
gint value){/* Thresholds are in class state data, get access to it */
ValueObjectClass* klass = VALUE_OBJECT_GET_CLASS(obj);return((value >= klass->thresholdMin)&&(value <= klass->thresholdMax));}

Both utility functions are then used from within the respective set functions, one of which is presented below: glib-dbus-signals/server.c

/**
* Function that gets called when someone tries to execute "setvalue1"
* over the D-Bus. (Actually the marshalling code from the stubs gets
* executed first, but eventually they execute this function.)
*/
gboolean value_object_setvalue1(ValueObject* obj, gint valueIn,
GError** error){
dbg("Called (valueIn=%d)", valueIn);
g_assert(obj != NULL);/* Compare the current value against old one. If they're the same,
we do not need to do anything (except return success). */if(obj->value1 != valueIn){/* Change the value. */
obj->value1 = valueIn;/* Emit the "changed_value1" signal. */
value_object_emitSignal(obj, E_SIGNAL_CHANGED_VALUE1,"value1");/* If new value falls outside the thresholds, emit
"outofrange_value1" signal as well. */if(!value_object_thresholdsOk(obj, valueIn)){
value_object_emitSignal(obj, E_SIGNAL_OUTOFRANGE_VALUE1,"value1");}}/* Return success to GLib/D-Bus wrappers. In this case we do not need
to touch the supplied error pointer-pointer. */return TRUE;}

The role of the value1 string parameter that is sent along both of the signals above can raise a question. Sending the signal origin name with the signal allows you to reuse the same callback function in the client. This kind of "source naming" is rarely useful but it allows for writing a slightly shorter client program.

The implementation of setvalue2 is almost identical, but deals with the gdouble parameter.

The getvalue functions are identical to the versions before as is the Makefile.

Next, the server is built and started on the background (in preparation for testing with dbus-send):

Because the threshold testing logic truncates the gdouble before testing against the (integer) thresholds, a value of 100.5 is detected as 100 and it still fits within the thresholds.

Instead of printing out the emitted signal names, the enumeration values of the emitted signals are printed. This could be rectified with a small enumeration to string table, but it was omitted from the program for simplicity.

Other than seeing the server messages about emitting the signals, there is no trace of them being sent or received. This is because dbus-send does not listen for signals. A separate tool (dbus-monitor) can be used for tracing signals.

In order to receive D-Bus signals in the client, you need to perform several tasks per signal. This is because dbus-bindings-tool does not generate any code for signals. The aim is to make the GLib wrappers emit GLib signals whenever an interesting D-Bus signal arrives. This also means that registering the interest for a particular D-Bus signal is necessary.

When implementing the callbacks for the signals, the prototype must be implemented correctly. Because the signals are sent with one attached string value, the callbacks receive at least the string parameter. Besides the signal attached arguments, the callback receives the proxy object, through which the signal was received, and optional user-specified data (which is not used in this example, so it is always NULL). glib-dbus-signals/client.c

/**
* Signal handler for the "changed" signals. These are sent by the
* Value-object whenever its contents change (whether within
* thresholds or not).
*
* Like before, we use strcmp to differentiate between the two
* values, and act accordingly (in this case by retrieving
* synchronously the values using getvalue1 or getvalue2).
*
* NOTE: Because we use synchronous getvalues, it is possible to get
* this code stuck if for some reason the server is stuck
* in an eternal loop.
*/staticvoid valueChangedSignalHandler(DBusGProxy* proxy,constchar* valueName,
gpointer userData){/* Because method calls over D-Bus can fail, we need to check
for failures. The server might be shut down in the middle of
things, or might act badly in other ways. */
GError* error = NULL;
g_print(PROGNAME ":value-changed (%s)\n", valueName);/* Find out which value changed and act accordingly. */if(strcmp(valueName,"value1")== 0){
gint v =0;/* Execute the RPC to get value1. */
org_maemo_Value_getvalue1(proxy,&v,&error);if(error == NULL){
g_print(PROGNAME ":value-changed Value1 now %d\n", v);}else{/* You could interrogate the GError further to find out exactly
what the error was, but in our case, we just ignore the
error with the hope that some day (preferably soon), the
RPC succeeds again (server comes back on the bus). */
handleError("Failed to retrieve value1", error->message, FALSE);}}else{
gdouble v =0.0;
org_maemo_Value_getvalue2(proxy,&v,&error);if(error == NULL){
g_print(PROGNAME ":value-changed Value2 now %.3f\n", v);}else{
handleError("Failed to retrieve value2", error->message, FALSE);}}/* Free up error object if one was allocated. */
g_clear_error(&error);}

The callback first determines what was the source value that caused the signal to be generated. For this, it uses the string argument of the signal. It then retrieves the current value using the respective RPC methods (getvalue1 or getvalue2) and prints out the value.

If any errors occur during the method calls, the errors are printed out, but the program continues to run. If an error does occur, the GError object needs to be freed (performed with g_clear_error). The program does not terminate on RPC errors, because the condition might be temporary (the Value object server might be restarted later).

The code for the outOfRangeSignalHandler callback has been omitted, because it does not contain anything beyond what valueChangedSignalHandler demonstrates.

Registering for the signals is a two-step process. First, it is necessary to register the interest in the D-Bus signals, and then install the callbacks for the respective GLib signals. This is done within main: glib-dbus-signals/client.c

/**
* The test program itself.
*
* 1) Setup GType/GSignal
* 2) Create GMainLoop object
* 3) Connect to the Session D-Bus
* 4) Create a proxy GObject for the remote Value object
* 5) Register signals that we're interested from the Value object
* 6) Register signal handlers for them
* 7) Start a timer that launches timerCallback once per second.
* 8) Run main-loop (forever)
*/int main(int argc,char** argv){/*... Listing cut for brevity ...*/
remoteValue =
dbus_g_proxy_new_for_name(bus,
VALUE_SERVICE_NAME,/* name */
VALUE_SERVICE_OBJECT_PATH,/* obj path */
VALUE_SERVICE_INTERFACE /* interface */);if(remoteValue == NULL){
handleError("Couldn't create the proxy object","Unknown(dbus_g_proxy_new_for_name)", TRUE);}/* Register the signatures for the signal handlers.
In our case, we have one string parameter passed to use along
the signal itself. The parameter list is terminated with
G_TYPE_INVALID (i.e., the GType for string objects. */
g_print(PROGNAME ":main Registering signal handler signatures.\n");/* Add the argument signatures for the signals (needs to be done
before connecting the signals). This may go away in the future,
when the GLib-bindings do automatic introspection over the
D-Bus, but for now we need the registration phase. */{/* Create a local scope for variables. */int i;const gchar* signalNames[]={ SIGNAL_CHANGED_VALUE1,
SIGNAL_CHANGED_VALUE2,
SIGNAL_OUTOFRANGE_VALUE1,
SIGNAL_OUTOFRANGE_VALUE2 };/* Iterate over all the entries in the above array.
The upper limit for i might seem strange at first glance,
but is quite common idiom to extract the number of elements
in a statically allocated arrays in C.
NOTE: The idiom does not work with dynamically allocated
arrays. (Or rather it works, but the result is probably
not what you expect.) */for(i =0; i <sizeof(signalNames)/sizeof(signalNames[0]); i++){/* Because the function does not return anything, we cannot check
for errors here. */
dbus_g_proxy_add_signal(/* Proxy to use */
remoteValue,/* Signal name */
signalNames[i],/* Receives one string argument */
G_TYPE_STRING,/* Termination of the argument list */
G_TYPE_INVALID);}}/* end of local scope */
g_print(PROGNAME ":main Registering D-Bus signal handlers.\n");/* We connect each of the following signals one at a time,
because we are using two different callbacks. *//* Again, no return values, cannot hence check for errors. */
dbus_g_proxy_connect_signal(/* Proxy object */
remoteValue,/* Signal name */
SIGNAL_CHANGED_VALUE1,/* Signal handler to use. Note that the
typecast is just to make the compiler
happy about the function, because the
prototype is not compatible with
regular signal handlers. */
G_CALLBACK(valueChangedSignalHandler),/* User-data (we don't use any). */
NULL,/* GClosureNotify function that is
responsible in freeing the passed
user-data (we have no data). */
NULL);
dbus_g_proxy_connect_signal(remoteValue, SIGNAL_CHANGED_VALUE2,
G_CALLBACK(valueChangedSignalHandler),
NULL, NULL);
dbus_g_proxy_connect_signal(remoteValue, SIGNAL_OUTOFRANGE_VALUE1,
G_CALLBACK(outOfRangeSignalHandler),
NULL, NULL);
dbus_g_proxy_connect_signal(remoteValue, SIGNAL_OUTOFRANGE_VALUE2,
G_CALLBACK(outOfRangeSignalHandler),
NULL, NULL);/* All signals are now registered and we're ready to handle them. */
g_print(PROGNAME ":main Starting main loop (first timer in 1s).\n");/* Register a timer callback that does RPC sets on the values.
The userdata pointer is used to pass the proxy object to the
callback so that it can launch modifications to the object. */
g_timeout_add(1000,(GSourceFunc)timerCallback, remoteValue);/* Run the program. */
g_main_loop_run(mainloop);/* Because the main loop is not stopped (by this code), we shouldn't
ever get here. The program might abort() for other reasons. *//* If it does, return failure as exit code. */return EXIT_FAILURE;}

When adding the argument signatures for the signals (with dbus_g_proxy_add_signal), one needs to be very careful with the parameter list. The signal argument types must be exactly the same as are sent from the server (irrespective of the argument specification in the interface XML). This is because the current version of dbus-bindings-tool does not generate any checks to enforce signal arguments based on the interface. In this simple case, only one string is received with each different signal, so this is not a big issue. The implementation for the callback function needs to match the argument specification given to the _add_signal-function, otherwise data layout on the stack is incorrect and can cause problems.

Building the client is done in the same manner as before (make client). Because the server is still (hopefully) running on the background, the client is now started in the same session:

The client starts with the timer callback being executed once per second (as before). Each iteration, it calls the setvalue1 and setvalue2 RPC methods with increasing values. The number for value2 is intentionally set below the minimum threshold, so that it causes an outofrange_value2 signal to be emitted. For each set, the changed_value signals are also emitted. Whenever the client receives either of the value change signals, it performs a getvalue RPC method call to retrieve the current value and print it out.

Sometimes seeing which signals are actually carried on the buses can be useful, especially when adding signal handlers for signals that are emitted from undocumented interfaces. The dbus-monitor tool attaches to the D-Bus daemon, and asks it to watch for signals and report them back to the tool, so that it can decode the signals automatically, as they appear on the bus.

While the server and client are still running, the next step is to start the dbus-monitor (in a separate session this time) to see whether the signals are transmitted correctly. It should be noted that signals appear on the bus even if there are no clients currently interested in them. In this case, signals are emitted by the server, based on client-issued RPC methods, so if the client is terminated, the signals cease.

The tool decodes the parameters automatically to the best of its ability (the string parameter for the signals above). It does not know the semantic meaning for the different signals, so sometimes additional testing has to be performed to decide what they actually mean. This is especially true when mapping out undocumented interfaces (for which the source code is not necessarily available).

Some examples of displaying signals on the system bus on a device follow:

It is also possible to send signals from the command line, which is useful when some feature of a device needs to be emulated inside the SDK. This (like RPC method calls) can be performed with the dbus-send tool. An example of this kind of simulation was given in the LibOSSO section.