1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
8 **************************************************************************
9 * This file contains code of the D-Bus helpers
10 **************************************************************************
12 * Licensed under the Academic Free License version 2.1
14 * LADI Session Handler is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * LADI Session Handler is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
26 * or write to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <dbus/dbus.h>
37 #include "../assert.h"
39 DBusConnection
* g_dbus_connection
;
40 DBusError g_dbus_error
;
42 bool dbus_iter_get_dict_entry(DBusMessageIter
* iter
, const char ** key_ptr
, void * value_ptr
, int * type_ptr
, int * size_ptr
)
44 if (!iter
|| !key_ptr
|| !value_ptr
|| !type_ptr
) {
45 log_error("Invalid arguments");
49 DBusMessageIter dict_iter
, variant_iter
;
51 if (dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_DICT_ENTRY
) {
52 log_error("Iterator does not point to a dict entry container");
56 dbus_message_iter_recurse(iter
, &dict_iter
);
58 if (dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_STRING
) {
59 log_error("Cannot find key in dict entry container");
63 dbus_message_iter_get_basic(&dict_iter
, key_ptr
);
65 if (!dbus_message_iter_next(&dict_iter
)
66 || dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_VARIANT
) {
67 log_error("Cannot find variant container in dict entry");
71 dbus_message_iter_recurse(&dict_iter
, &variant_iter
);
73 *type_ptr
= dbus_message_iter_get_arg_type(&variant_iter
);
74 if (*type_ptr
== DBUS_TYPE_INVALID
) {
75 log_error("Cannot find value in variant container");
79 if (*type_ptr
== DBUS_TYPE_ARRAY
) {
80 DBusMessageIter array_iter
;
83 if (dbus_message_iter_get_element_type(&variant_iter
)
85 log_error("Dict entry value is a non-byte array");
90 dbus_message_iter_recurse(&variant_iter
, &array_iter
);
91 dbus_message_iter_get_fixed_array(&array_iter
, value_ptr
, &n
);
96 dbus_message_iter_get_basic(&variant_iter
, value_ptr
);
102 * Append a variant type to a D-Bus message.
103 * Return false if something fails, true otherwise.
105 bool dbus_iter_append_variant(DBusMessageIter
* iter
, int type
, const void * arg
)
107 DBusMessageIter sub_iter
;
113 /* Open a variant container. */
114 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, (const char *)s
, &sub_iter
))
117 /* Append the supplied value. */
118 if (!dbus_message_iter_append_basic(&sub_iter
, type
, arg
))
120 dbus_message_iter_close_container(iter
, &sub_iter
);
124 /* Close the container. */
125 if (!dbus_message_iter_close_container(iter
, &sub_iter
))
131 static __inline__
bool dbus_iter_append_variant_raw(DBusMessageIter
* iter
, const void * buf
, int len
)
133 DBusMessageIter variant_iter
, array_iter
;
135 /* Open a variant container. */
136 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
137 "ay", &variant_iter
))
140 /* Open an array container. */
141 if (!dbus_message_iter_open_container(&variant_iter
, DBUS_TYPE_ARRAY
,
145 /* Append the supplied data. */
146 if (!dbus_message_iter_append_fixed_array(&array_iter
, DBUS_TYPE_BYTE
, buf
, len
)) {
147 dbus_message_iter_close_container(&variant_iter
, &array_iter
);
151 /* Close the containers. */
152 if (!dbus_message_iter_close_container(&variant_iter
, &array_iter
))
154 else if (!dbus_message_iter_close_container(iter
, &variant_iter
))
160 dbus_message_iter_close_container(iter
, &variant_iter
);
164 bool dbus_iter_append_dict_entry(DBusMessageIter
* iter
, int type
, const char * key
, const void * value
, int length
)
166 DBusMessageIter dict_iter
;
168 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_iter
))
171 if (!dbus_message_iter_append_basic(&dict_iter
, DBUS_TYPE_STRING
, &key
))
176 if (!dbus_iter_append_variant_raw(&dict_iter
, value
, length
))
179 else if (!dbus_iter_append_variant(&dict_iter
, type
, value
))
184 if (!dbus_message_iter_close_container(iter
, &dict_iter
))
190 dbus_message_iter_close_container(iter
, &dict_iter
);
194 bool dbus_maybe_add_dict_entry_string(DBusMessageIter
*dict_iter_ptr
, const char * key
, const char * value
)
196 DBusMessageIter dict_entry_iter
;
203 if (!dbus_message_iter_open_container(dict_iter_ptr
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
))
208 if (!dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, (const void *) &key
))
210 dbus_message_iter_close_container(dict_iter_ptr
, &dict_entry_iter
);
214 dbus_iter_append_variant(&dict_entry_iter
, DBUS_TYPE_STRING
, &value
);
216 if (!dbus_message_iter_close_container(dict_iter_ptr
, &dict_entry_iter
))
224 bool dbus_add_dict_entry_uint32(DBusMessageIter
* dict_iter_ptr
, const char * key
, dbus_uint32_t value
)
226 DBusMessageIter dict_entry_iter
;
228 if (!dbus_message_iter_open_container(dict_iter_ptr
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
))
233 if (!dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, (const void *) &key
))
235 dbus_message_iter_close_container(dict_iter_ptr
, &dict_entry_iter
);
239 dbus_iter_append_variant(&dict_entry_iter
, DBUS_TYPE_UINT32
, &value
);
241 if (!dbus_message_iter_close_container(dict_iter_ptr
, &dict_entry_iter
))
249 bool dbus_add_dict_entry_bool(DBusMessageIter
* dict_iter_ptr
, const char * key
, dbus_bool_t value
)
251 DBusMessageIter dict_entry_iter
;
253 if (!dbus_message_iter_open_container(dict_iter_ptr
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
))
258 if (!dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, (const void *) &key
))
260 dbus_message_iter_close_container(dict_iter_ptr
, &dict_entry_iter
);
264 dbus_iter_append_variant(&dict_entry_iter
, DBUS_TYPE_BOOLEAN
, &value
);
266 if (!dbus_message_iter_close_container(dict_iter_ptr
, &dict_entry_iter
))
276 const char * service
,
280 const char * input_signature
,
283 DBusMessageIter iter
;
284 DBusMessage
* request_ptr
;
285 DBusMessage
* reply_ptr
;
286 const char * output_signature
;
287 const char * reply_signature
;
290 void * parameter_ptr
;
292 DBusSignatureIter sig_iter
;
294 //log_info("dbus_call('%s', '%s', '%s', '%s')", service, object, iface, method);
297 va_start(ap
, input_signature
);
299 if (input_signature
!= NULL
)
301 if (!dbus_signature_validate(input_signature
, NULL
))
303 log_error("input signature '%s' is invalid", input_signature
);
307 dbus_signature_iter_init(&sig_iter
, input_signature
);
309 request_ptr
= dbus_message_new_method_call(service
, object
, iface
, method
);
310 if (request_ptr
== NULL
)
312 log_error("dbus_message_new_method_call() failed.");
316 dbus_message_iter_init_append(request_ptr
, &iter
);
318 while (*input_signature
!= '\0')
320 type
= dbus_signature_iter_get_current_type(&sig_iter
);
321 if (!dbus_type_is_basic(type
))
323 log_error("non-basic input parameter '%c' (%d)", *input_signature
, type
);
327 parameter_ptr
= va_arg(ap
, void *);
329 if (!dbus_message_iter_append_basic(&iter
, type
, parameter_ptr
))
331 log_error("dbus_message_iter_append_basic() failed.");
335 dbus_signature_iter_next(&sig_iter
);
341 request_ptr
= va_arg(ap
, DBusMessage
*);
344 output_signature
= va_arg(ap
, const char *);
346 reply_ptr
= dbus_connection_send_with_reply_and_block(
349 DBUS_CALL_DEFAULT_TIMEOUT
,
352 if (input_signature
!= NULL
)
354 dbus_message_unref(request_ptr
);
357 if (reply_ptr
== NULL
)
359 log_error("calling method '%s' failed, error is '%s'", method
, g_dbus_error
.message
);
360 dbus_error_free(&g_dbus_error
);
364 if (output_signature
!= NULL
)
366 reply_signature
= dbus_message_get_signature(reply_ptr
);
368 if (strcmp(reply_signature
, output_signature
) != 0)
370 log_error("reply signature is '%s' but expected signature is '%s'", reply_signature
, output_signature
);
373 dbus_message_iter_init(reply_ptr
, &iter
);
375 while (*output_signature
++ != '\0')
377 ASSERT(dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_INVALID
); /* we've checked the signature, this should not happen */
378 parameter_ptr
= va_arg(ap
, void *);
379 dbus_message_iter_get_basic(&iter
, parameter_ptr
);
380 dbus_message_iter_next(&iter
);
383 ASSERT(dbus_message_iter_get_arg_type(&iter
) == DBUS_TYPE_INVALID
); /* we've checked the signature, this should not happen */
384 dbus_message_unref(reply_ptr
);
388 parameter_ptr
= va_arg(ap
, DBusMessage
**);
389 *(DBusMessage
**)parameter_ptr
= reply_ptr
;
401 compose_signal_match(
402 const char * service
,
407 static char rule
[1024];
408 snprintf(rule
, sizeof(rule
), "type='signal',sender='%s',path='%s',interface='%s',member='%s'", service
, object
, iface
, signal
);
413 dbus_register_object_signal_handler(
414 DBusConnection
* connection
,
415 const char * service
,
418 const char * const * signals
,
419 DBusHandleMessageFunction handler
,
422 const char * const * signal
;
424 for (signal
= signals
; *signal
!= NULL
; signal
++)
426 dbus_bus_add_match(connection
, compose_signal_match(service
, object
, iface
, *signal
), &g_dbus_error
);
427 if (dbus_error_is_set(&g_dbus_error
))
429 log_error("Failed to add D-Bus match rule: %s", g_dbus_error
.message
);
430 dbus_error_free(&g_dbus_error
);
435 dbus_connection_add_filter(g_dbus_connection
, handler
, handler_data
, NULL
);
441 dbus_unregister_object_signal_handler(
442 DBusConnection
* connection
,
443 const char * service
,
446 const char * const * signals
,
447 DBusHandleMessageFunction handler
,
450 const char * const * signal
;
452 for (signal
= signals
; *signal
!= NULL
; signal
++)
454 dbus_bus_remove_match(connection
, compose_signal_match(service
, object
, iface
, *signal
), &g_dbus_error
);
455 if (dbus_error_is_set(&g_dbus_error
))
457 log_error("Failed to add D-Bus match rule: %s", g_dbus_error
.message
);
458 dbus_error_free(&g_dbus_error
);
463 dbus_connection_remove_filter(g_dbus_connection
, handler
, handler_data
);