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 D-Bus methods helpers
10 **************************************************************************
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "../common/safety.h"
29 #include "../common/debug.h"
36 * Construct a void method return.
38 * The operation can only fail due to lack of memory, in which case
39 * there's no sense in trying to construct an error return. Instead,
40 * call->reply will be set to NULL and handled in send_method_return().
43 method_return_new_void(method_call_t
*call
)
45 if (!(call
->reply
= dbus_message_new_method_return(call
->message
))) {
46 lash_error("Ran out of memory trying to construct method return");
51 * Construct a method return which holds a single argument or, if
52 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
55 * The operation can only fail due to lack of memory, in which case
56 * there's no sense in trying to construct an error return. Instead,
57 * call->reply will be set to NULL and handled in send_method_return().
60 method_return_new_single(method_call_t
*call
,
65 lash_error("Invalid arguments");
69 call
->reply
= dbus_message_new_method_return(call
->message
);
74 /* Void method return requested by caller. */
75 // TODO: do we really need this?
76 if (type
== DBUS_TYPE_INVALID
)
79 /* Prevent crash on NULL input string. */
80 if (type
== DBUS_TYPE_STRING
&& !(*((const char **) arg
)))
81 *((const char **) arg
) = "";
85 dbus_message_iter_init_append(call
->reply
, &iter
);
87 if (dbus_message_iter_append_basic(&iter
, type
, arg
))
90 dbus_message_unref(call
->reply
);
94 lash_error("Ran out of memory trying to construct method return");
98 method_return_new_valist(method_call_t
*call
,
103 lash_error("Call pointer is NULL");
107 if (type
== DBUS_TYPE_INVALID
) {
108 lash_error("No argument(s) supplied");
114 call
->reply
= dbus_message_new_method_return(call
->message
);
118 va_start(argp
, type
);
120 if (dbus_message_append_args_valist(call
->reply
, type
, argp
)) {
127 dbus_message_unref(call
->reply
);
131 lash_error("Ran out of memory trying to construct method return");
135 * Send a method call.
138 method_send(method_msg_t
*call
,
141 if (!call
->message
) {
142 lash_error("Cannot send method call: Message is NULL");
146 DBusPendingCall
*pending
= NULL
;
149 if (!dbus_connection_send_with_reply(call
->service
->connection
,
150 call
->message
, &pending
, -1)) {
151 lash_error("Ran out of memory trying to queue "
154 /* Never wait for a reply if sending failed */
158 dbus_pending_call_set_notify(pending
,
159 call
->return_handler
,
160 call
->context
, NULL
);
161 dbus_connection_flush(call
->service
->connection
);
165 dbus_message_unref(call
->message
);
166 call
->message
= NULL
;
168 if (will_block
&& pending
) {
169 lash_debug("Blocking until a return arrives");
170 dbus_pending_call_block(pending
);
177 * Send a method return.
179 * If call->reply is NULL, i.e. a previous attempt to construct
180 * a return has failed, attempt to send a void return.
183 method_return_send(method_call_t
*call
)
187 if (!dbus_connection_send(call
->connection
, call
->reply
, NULL
))
188 lash_error("Ran out of memory trying to queue "
191 dbus_connection_flush(call
->connection
);
193 dbus_message_unref(call
->reply
);
196 lash_debug("Message was NULL, trying to construct a void return");
198 if ((call
->reply
= dbus_message_new_method_return(call
->message
))) {
199 lash_debug("Constructed a void return, trying to queue it");
202 lash_error("Failed to construct method return!");
208 method_return_verify(DBusMessage
*msg
,
211 if (!msg
|| dbus_message_get_type(msg
) != DBUS_MESSAGE_TYPE_ERROR
)
216 if (!dbus_message_get_args(msg
, &g_dbus_error
,
217 DBUS_TYPE_STRING
, &ptr
,
218 DBUS_TYPE_INVALID
)) {
219 lash_error("Cannot read description from D-Bus error message: %s ",
220 g_dbus_error
.message
);
221 dbus_error_free(&g_dbus_error
);
232 * Append a variant type to a D-Bus message.
233 * Return false if something fails, true otherwise.
236 method_iter_append_variant(DBusMessageIter
*iter
,
240 DBusMessageIter sub_iter
;
246 /* Open a variant container. */
247 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
248 (const char *) s
, &sub_iter
))
251 /* Append the supplied value. */
252 if (!dbus_message_iter_append_basic(&sub_iter
, type
, arg
)) {
253 dbus_message_iter_close_container(iter
, &sub_iter
);
257 /* Close the container. */
258 if (!dbus_message_iter_close_container(iter
, &sub_iter
))
264 static __inline__
bool
265 method_iter_append_variant_raw(DBusMessageIter
*iter
,
269 DBusMessageIter variant_iter
, array_iter
;
271 /* Open a variant container. */
272 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
273 "ay", &variant_iter
))
276 /* Open an array container. */
277 if (!dbus_message_iter_open_container(&variant_iter
, DBUS_TYPE_ARRAY
,
281 /* Append the supplied data. */
282 if (!dbus_message_iter_append_fixed_array(&array_iter
, DBUS_TYPE_BYTE
, buf
, len
)) {
283 dbus_message_iter_close_container(&variant_iter
, &array_iter
);
287 /* Close the containers. */
288 if (!dbus_message_iter_close_container(&variant_iter
, &array_iter
))
290 else if (!dbus_message_iter_close_container(iter
, &variant_iter
))
296 dbus_message_iter_close_container(iter
, &variant_iter
);
301 method_iter_append_dict_entry(DBusMessageIter
*iter
,
307 DBusMessageIter dict_iter
;
309 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_DICT_ENTRY
,
313 if (!dbus_message_iter_append_basic(&dict_iter
, DBUS_TYPE_STRING
, &key
))
317 if (!method_iter_append_variant_raw(&dict_iter
, value
, length
))
319 } else if (!method_iter_append_variant(&dict_iter
, type
, value
))
322 if (!dbus_message_iter_close_container(iter
, &dict_iter
))
328 dbus_message_iter_close_container(iter
, &dict_iter
);
333 method_default_handler(DBusPendingCall
*pending
,
336 DBusMessage
*msg
= dbus_pending_call_steal_reply(pending
);
341 if (!method_return_verify(msg
, &err_str
))
342 lash_error("%s", err_str
);
344 dbus_message_unref(msg
);
346 lash_error("Cannot get method return from pending call");
348 dbus_pending_call_unref(pending
);
352 method_call_init(method_msg_t
*call
,
354 void *return_context
,
355 DBusPendingCallNotifyFunction return_handler
,
356 const char *destination
,
358 const char *interface
,
361 if (!call
|| !service
|| !service
->connection
362 || !destination
|| !path
|| !method
) {
363 lash_error("Invalid arguments");
370 call
->message
= dbus_message_new_method_call(destination
, path
,
372 if (!call
->message
) {
373 lash_error("Ran out of memory trying to create "
378 call
->service
= service
;
379 call
->context
= return_context
;
380 call
->return_handler
= return_handler
;
383 dbus_message_set_no_reply(call
->message
, true);
389 method_call_new_void(service_t
*service
,
390 void *return_context
,
391 DBusPendingCallNotifyFunction return_handler
,
393 const char *destination
,
395 const char *interface
,
400 if (method_call_init(&call
, service
, return_context
, return_handler
,
401 destination
, path
, interface
, method
))
402 return method_send(&call
, will_block
);
408 method_call_new_single(service_t
*service
,
409 void *return_context
,
410 DBusPendingCallNotifyFunction return_handler
,
412 const char *destination
,
414 const char *interface
,
419 if (type
== DBUS_TYPE_INVALID
|| !arg
) {
420 lash_error("No argument supplied");
425 DBusMessageIter iter
;
427 if (!method_call_init(&call
, service
, return_context
, return_handler
,
428 destination
, path
, interface
, method
))
431 dbus_message_iter_init_append(call
.message
, &iter
);
433 if (dbus_message_iter_append_basic(&iter
, type
, arg
)) {
434 return method_send(&call
, will_block
);
437 lash_error("Ran out of memory trying to append method call argument");
439 dbus_message_unref(call
.message
);
446 method_call_new_valist(service_t
*service
,
447 void *return_context
,
448 DBusPendingCallNotifyFunction return_handler
,
450 const char *destination
,
452 const char *interface
,
457 if (type
== DBUS_TYPE_INVALID
) {
458 lash_error("No argument(s) supplied");
465 if (!method_call_init(&call
, service
, return_context
, return_handler
,
466 destination
, path
, interface
, method
))
469 va_start(argp
, type
);
471 if (dbus_message_append_args_valist(call
.message
, type
, argp
)) {
473 return method_send(&call
, will_block
);
478 lash_error("Ran out of memory trying to append "
479 "method call argument(s)");
481 dbus_message_unref(call
.message
);
488 method_iter_get_args(DBusMessageIter
*iter
,
492 lash_error("Iterator pointer is NULL");
497 int expected_type
, type
, n
= 0;
500 va_start(argp
, iter
);
502 while ((expected_type
= va_arg(argp
, int)) != DBUS_TYPE_INVALID
) {
503 ptr
= va_arg(argp
, void *);
505 if ((type
= dbus_message_iter_get_arg_type(iter
))
506 == DBUS_TYPE_INVALID
) {
507 lash_error("Insufficient arguments");
512 if (type
!= expected_type
) {
513 lash_error("Invalid type for argument %i", n
);
519 dbus_message_iter_get_basic(iter
, ptr
);
521 dbus_message_iter_next(iter
);
532 method_iter_get_dict_entry(DBusMessageIter
*iter
,
533 const char **key_ptr
,
538 if (!iter
|| !key_ptr
|| !value_ptr
|| !type_ptr
) {
539 lash_error("Invalid arguments");
543 DBusMessageIter dict_iter
, variant_iter
;
545 if (dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_DICT_ENTRY
) {
546 lash_error("Iterator does not point to a dict entry container");
550 dbus_message_iter_recurse(iter
, &dict_iter
);
552 if (dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_STRING
) {
553 lash_error("Cannot find key in dict entry container");
557 dbus_message_iter_get_basic(&dict_iter
, key_ptr
);
559 if (!dbus_message_iter_next(&dict_iter
)
560 || dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_VARIANT
) {
561 lash_error("Cannot find variant container in dict entry");
565 dbus_message_iter_recurse(&dict_iter
, &variant_iter
);
567 *type_ptr
= dbus_message_iter_get_arg_type(&variant_iter
);
568 if (*type_ptr
== DBUS_TYPE_INVALID
) {
569 lash_error("Cannot find value in variant container");
573 if (*type_ptr
== DBUS_TYPE_ARRAY
) {
574 DBusMessageIter array_iter
;
577 if (dbus_message_iter_get_element_type(&variant_iter
)
579 lash_error("Dict entry value is a non-byte array");
584 dbus_message_iter_recurse(&variant_iter
, &array_iter
);
585 dbus_message_iter_get_fixed_array(&array_iter
, value_ptr
, &n
);
590 dbus_message_iter_get_basic(&variant_iter
, value_ptr
);