1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008 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"
35 * Construct a void method return.
37 * The operation can only fail due to lack of memory, in which case
38 * there's no sense in trying to construct an error return. Instead,
39 * call->reply will be set to NULL and handled in send_method_return().
42 method_return_new_void(method_call_t
*call
)
44 if (!(call
->reply
= dbus_message_new_method_return(call
->message
))) {
45 lash_error("Ran out of memory trying to construct method return");
50 * Construct a method return which holds a single argument or, if
51 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
54 * The operation can only fail due to lack of memory, in which case
55 * there's no sense in trying to construct an error return. Instead,
56 * call->reply will be set to NULL and handled in send_method_return().
59 method_return_new_single(method_call_t
*call
,
64 lash_error("Invalid arguments");
68 call
->reply
= dbus_message_new_method_return(call
->message
);
73 /* Void method return requested by caller. */
74 // TODO: do we really need this?
75 if (type
== DBUS_TYPE_INVALID
)
78 /* Prevent crash on NULL input string. */
79 if (type
== DBUS_TYPE_STRING
&& !(*((const char **) arg
)))
80 *((const char **) arg
) = "";
84 dbus_message_iter_init_append(call
->reply
, &iter
);
86 if (dbus_message_iter_append_basic(&iter
, type
, arg
))
89 dbus_message_unref(call
->reply
);
93 lash_error("Ran out of memory trying to construct method return");
97 method_return_new_valist(method_call_t
*call
,
102 lash_error("Call pointer is NULL");
106 if (type
== DBUS_TYPE_INVALID
) {
107 lash_error("No argument(s) supplied");
113 call
->reply
= dbus_message_new_method_return(call
->message
);
117 va_start(argp
, type
);
119 if (dbus_message_append_args_valist(call
->reply
, type
, argp
)) {
126 dbus_message_unref(call
->reply
);
130 lash_error("Ran out of memory trying to construct method return");
134 * Send a method call.
137 method_send(method_msg_t
*call
,
140 if (!call
->message
) {
141 lash_error("Cannot send method call: Message is NULL");
145 DBusPendingCall
*pending
= NULL
;
148 if (!dbus_connection_send_with_reply(call
->service
->connection
,
149 call
->message
, &pending
, -1)) {
150 lash_error("Ran out of memory trying to queue "
153 /* Never wait for a reply if sending failed */
157 dbus_pending_call_set_notify(pending
,
158 call
->return_handler
,
159 call
->context
, NULL
);
160 dbus_connection_flush(call
->service
->connection
);
164 dbus_message_unref(call
->message
);
165 call
->message
= NULL
;
167 if (will_block
&& pending
) {
168 lash_debug("Blocking until a return arrives");
169 dbus_pending_call_block(pending
);
176 * Send a method return.
178 * If call->reply is NULL, i.e. a previous attempt to construct
179 * a return has failed, attempt to send a void return.
182 method_return_send(method_call_t
*call
)
186 if (!dbus_connection_send(call
->connection
, call
->reply
, NULL
))
187 lash_error("Ran out of memory trying to queue "
190 dbus_connection_flush(call
->connection
);
192 dbus_message_unref(call
->reply
);
195 lash_debug("Message was NULL, trying to construct a void return");
197 if ((call
->reply
= dbus_message_new_method_return(call
->message
))) {
198 lash_debug("Constructed a void return, trying to queue it");
201 lash_error("Failed to construct method return!");
207 method_return_verify(DBusMessage
*msg
,
210 if (!msg
|| dbus_message_get_type(msg
) != DBUS_MESSAGE_TYPE_ERROR
)
216 dbus_error_init(&err
);
218 if (!dbus_message_get_args(msg
, &err
,
219 DBUS_TYPE_STRING
, &ptr
,
220 DBUS_TYPE_INVALID
)) {
221 lash_error("Cannot read description from D-Bus error message: %s ",
223 dbus_error_free(&err
);
234 * Append a variant type to a D-Bus message.
235 * Return false if something fails, true otherwise.
238 method_iter_append_variant(DBusMessageIter
*iter
,
242 DBusMessageIter sub_iter
;
248 /* Open a variant container. */
249 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
250 (const char *) s
, &sub_iter
))
253 /* Append the supplied value. */
254 if (!dbus_message_iter_append_basic(&sub_iter
, type
, arg
)) {
255 dbus_message_iter_close_container(iter
, &sub_iter
);
259 /* Close the container. */
260 if (!dbus_message_iter_close_container(iter
, &sub_iter
))
266 static __inline__
bool
267 method_iter_append_variant_raw(DBusMessageIter
*iter
,
271 DBusMessageIter variant_iter
, array_iter
;
273 /* Open a variant container. */
274 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
275 "ay", &variant_iter
))
278 /* Open an array container. */
279 if (!dbus_message_iter_open_container(&variant_iter
, DBUS_TYPE_ARRAY
,
283 /* Append the supplied data. */
284 if (!dbus_message_iter_append_fixed_array(&array_iter
, DBUS_TYPE_BYTE
, buf
, len
)) {
285 dbus_message_iter_close_container(&variant_iter
, &array_iter
);
289 /* Close the containers. */
290 if (!dbus_message_iter_close_container(&variant_iter
, &array_iter
))
292 else if (!dbus_message_iter_close_container(iter
, &variant_iter
))
298 dbus_message_iter_close_container(iter
, &variant_iter
);
303 method_iter_append_dict_entry(DBusMessageIter
*iter
,
309 DBusMessageIter dict_iter
;
311 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_DICT_ENTRY
,
315 if (!dbus_message_iter_append_basic(&dict_iter
, DBUS_TYPE_STRING
, &key
))
319 if (!method_iter_append_variant_raw(&dict_iter
, value
, length
))
321 } else if (!method_iter_append_variant(&dict_iter
, type
, value
))
324 if (!dbus_message_iter_close_container(iter
, &dict_iter
))
330 dbus_message_iter_close_container(iter
, &dict_iter
);
335 method_default_handler(DBusPendingCall
*pending
,
338 DBusMessage
*msg
= dbus_pending_call_steal_reply(pending
);
343 if (!method_return_verify(msg
, &err_str
))
344 lash_error("%s", err_str
);
346 dbus_message_unref(msg
);
348 lash_error("Cannot get method return from pending call");
350 dbus_pending_call_unref(pending
);
354 method_call_init(method_msg_t
*call
,
356 void *return_context
,
357 DBusPendingCallNotifyFunction return_handler
,
358 const char *destination
,
360 const char *interface
,
363 if (!call
|| !service
|| !service
->connection
364 || !destination
|| !path
|| !method
) {
365 lash_error("Invalid arguments");
372 call
->message
= dbus_message_new_method_call(destination
, path
,
374 if (!call
->message
) {
375 lash_error("Ran out of memory trying to create "
380 call
->service
= service
;
381 call
->context
= return_context
;
382 call
->return_handler
= return_handler
;
385 dbus_message_set_no_reply(call
->message
, true);
391 method_call_new_void(service_t
*service
,
392 void *return_context
,
393 DBusPendingCallNotifyFunction return_handler
,
395 const char *destination
,
397 const char *interface
,
402 if (method_call_init(&call
, service
, return_context
, return_handler
,
403 destination
, path
, interface
, method
))
404 return method_send(&call
, will_block
);
410 method_call_new_single(service_t
*service
,
411 void *return_context
,
412 DBusPendingCallNotifyFunction return_handler
,
414 const char *destination
,
416 const char *interface
,
421 if (type
== DBUS_TYPE_INVALID
|| !arg
) {
422 lash_error("No argument supplied");
427 DBusMessageIter iter
;
429 if (!method_call_init(&call
, service
, return_context
, return_handler
,
430 destination
, path
, interface
, method
))
433 dbus_message_iter_init_append(call
.message
, &iter
);
435 if (dbus_message_iter_append_basic(&iter
, type
, arg
)) {
436 return method_send(&call
, will_block
);
439 lash_error("Ran out of memory trying to append method call argument");
441 dbus_message_unref(call
.message
);
448 method_call_new_valist(service_t
*service
,
449 void *return_context
,
450 DBusPendingCallNotifyFunction return_handler
,
452 const char *destination
,
454 const char *interface
,
459 if (type
== DBUS_TYPE_INVALID
) {
460 lash_error("No argument(s) supplied");
467 if (!method_call_init(&call
, service
, return_context
, return_handler
,
468 destination
, path
, interface
, method
))
471 va_start(argp
, type
);
473 if (dbus_message_append_args_valist(call
.message
, type
, argp
)) {
475 return method_send(&call
, will_block
);
480 lash_error("Ran out of memory trying to append "
481 "method call argument(s)");
483 dbus_message_unref(call
.message
);
490 method_iter_get_args(DBusMessageIter
*iter
,
494 lash_error("Iterator pointer is NULL");
499 int expected_type
, type
, n
= 0;
502 va_start(argp
, iter
);
504 while ((expected_type
= va_arg(argp
, int)) != DBUS_TYPE_INVALID
) {
505 ptr
= va_arg(argp
, void *);
507 if ((type
= dbus_message_iter_get_arg_type(iter
))
508 == DBUS_TYPE_INVALID
) {
509 lash_error("Insufficient arguments");
514 if (type
!= expected_type
) {
515 lash_error("Invalid type for argument %i", n
);
521 dbus_message_iter_get_basic(iter
, ptr
);
523 dbus_message_iter_next(iter
);
534 method_iter_get_dict_entry(DBusMessageIter
*iter
,
535 const char **key_ptr
,
540 if (!iter
|| !key_ptr
|| !value_ptr
|| !type_ptr
) {
541 lash_error("Invalid arguments");
545 DBusMessageIter dict_iter
, variant_iter
;
547 if (dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_DICT_ENTRY
) {
548 lash_error("Iterator does not point to a dict entry container");
552 dbus_message_iter_recurse(iter
, &dict_iter
);
554 if (dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_STRING
) {
555 lash_error("Cannot find key in dict entry container");
559 dbus_message_iter_get_basic(&dict_iter
, key_ptr
);
561 if (!dbus_message_iter_next(&dict_iter
)
562 || dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_VARIANT
) {
563 lash_error("Cannot find variant container in dict entry");
567 dbus_message_iter_recurse(&dict_iter
, &variant_iter
);
569 *type_ptr
= dbus_message_iter_get_arg_type(&variant_iter
);
570 if (*type_ptr
== DBUS_TYPE_INVALID
) {
571 lash_error("Cannot find value in variant container");
575 if (*type_ptr
== DBUS_TYPE_ARRAY
) {
576 DBusMessageIter array_iter
;
579 if (dbus_message_iter_get_element_type(&variant_iter
)
581 lash_error("Dict entry value is a non-byte array");
586 dbus_message_iter_recurse(&variant_iter
, &array_iter
);
587 dbus_message_iter_get_fixed_array(&array_iter
, value_ptr
, &n
);
592 dbus_message_iter_get_basic(&variant_iter
, value_ptr
);