4 * Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
5 * Copyright (C) 2008 Nedko Arnaudov
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "common/safety.h"
23 #include "common/debug.h"
25 #include "dbus/method.h"
26 #include "dbus/service.h"
29 * Construct a void method return.
31 * The operation can only fail due to lack of memory, in which case
32 * there's no sense in trying to construct an error return. Instead,
33 * call->reply will be set to NULL and handled in send_method_return().
36 method_return_new_void(method_call_t
*call
)
38 if (!(call
->reply
= dbus_message_new_method_return(call
->message
))) {
39 lash_error("Ran out of memory trying to construct method return");
44 * Construct a method return which holds a single argument or, if
45 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
48 * The operation can only fail due to lack of memory, in which case
49 * there's no sense in trying to construct an error return. Instead,
50 * call->reply will be set to NULL and handled in send_method_return().
53 method_return_new_single(method_call_t
*call
,
58 lash_error("Invalid arguments");
62 call
->reply
= dbus_message_new_method_return(call
->message
);
67 /* Void method return requested by caller. */
68 // TODO: do we really need this?
69 if (type
== DBUS_TYPE_INVALID
)
72 /* Prevent crash on NULL input string. */
73 if (type
== DBUS_TYPE_STRING
&& !(*((const char **) arg
)))
74 *((const char **) arg
) = "";
78 dbus_message_iter_init_append(call
->reply
, &iter
);
80 if (dbus_message_iter_append_basic(&iter
, type
, arg
))
83 dbus_message_unref(call
->reply
);
87 lash_error("Ran out of memory trying to construct method return");
91 method_return_new_valist(method_call_t
*call
,
96 lash_error("Call pointer is NULL");
100 if (type
== DBUS_TYPE_INVALID
) {
101 lash_error("No argument(s) supplied");
107 call
->reply
= dbus_message_new_method_return(call
->message
);
111 va_start(argp
, type
);
113 if (dbus_message_append_args_valist(call
->reply
, type
, argp
)) {
120 dbus_message_unref(call
->reply
);
124 lash_error("Ran out of memory trying to construct method return");
128 * Send a method call.
131 method_send(method_msg_t
*call
,
134 if (!call
->message
) {
135 lash_error("Cannot send method call: Message is NULL");
139 DBusPendingCall
*pending
= NULL
;
142 if (!dbus_connection_send_with_reply(call
->service
->connection
,
143 call
->message
, &pending
, -1)) {
144 lash_error("Ran out of memory trying to queue "
147 /* Never wait for a reply if sending failed */
151 dbus_pending_call_set_notify(pending
,
152 call
->return_handler
,
153 call
->context
, NULL
);
154 dbus_connection_flush(call
->service
->connection
);
158 dbus_message_unref(call
->message
);
159 call
->message
= NULL
;
161 if (will_block
&& pending
) {
162 lash_debug("Blocking until a return arrives");
163 dbus_pending_call_block(pending
);
170 * Send a method return.
172 * If call->reply is NULL, i.e. a previous attempt to construct
173 * a return has failed, attempt to send a void return.
176 method_return_send(method_call_t
*call
)
180 if (!dbus_connection_send(call
->connection
, call
->reply
, NULL
))
181 lash_error("Ran out of memory trying to queue "
184 dbus_connection_flush(call
->connection
);
186 dbus_message_unref(call
->reply
);
189 lash_debug("Message was NULL, trying to construct a void return");
191 if ((call
->reply
= dbus_message_new_method_return(call
->message
))) {
192 lash_debug("Constructed a void return, trying to queue it");
195 lash_error("Failed to construct method return!");
201 method_return_verify(DBusMessage
*msg
,
204 if (!msg
|| dbus_message_get_type(msg
) != DBUS_MESSAGE_TYPE_ERROR
)
210 dbus_error_init(&err
);
212 if (!dbus_message_get_args(msg
, &err
,
213 DBUS_TYPE_STRING
, &ptr
,
214 DBUS_TYPE_INVALID
)) {
215 lash_error("Cannot read description from D-Bus error message: %s ",
217 dbus_error_free(&err
);
228 * Append a variant type to a D-Bus message.
229 * Return false if something fails, true otherwise.
232 method_iter_append_variant(DBusMessageIter
*iter
,
236 DBusMessageIter sub_iter
;
242 /* Open a variant container. */
243 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
244 (const char *) s
, &sub_iter
))
247 /* Append the supplied value. */
248 if (!dbus_message_iter_append_basic(&sub_iter
, type
, arg
)) {
249 dbus_message_iter_close_container(iter
, &sub_iter
);
253 /* Close the container. */
254 if (!dbus_message_iter_close_container(iter
, &sub_iter
))
260 static __inline__
bool
261 method_iter_append_variant_raw(DBusMessageIter
*iter
,
265 DBusMessageIter variant_iter
, array_iter
;
267 /* Open a variant container. */
268 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
269 "ay", &variant_iter
))
272 /* Open an array container. */
273 if (!dbus_message_iter_open_container(&variant_iter
, DBUS_TYPE_ARRAY
,
277 /* Append the supplied data. */
278 if (!dbus_message_iter_append_fixed_array(&array_iter
, DBUS_TYPE_BYTE
, buf
, len
)) {
279 dbus_message_iter_close_container(&variant_iter
, &array_iter
);
283 /* Close the containers. */
284 if (!dbus_message_iter_close_container(&variant_iter
, &array_iter
))
286 else if (!dbus_message_iter_close_container(iter
, &variant_iter
))
292 dbus_message_iter_close_container(iter
, &variant_iter
);
297 method_iter_append_dict_entry(DBusMessageIter
*iter
,
303 DBusMessageIter dict_iter
;
305 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_DICT_ENTRY
,
309 if (!dbus_message_iter_append_basic(&dict_iter
, DBUS_TYPE_STRING
, &key
))
313 if (!method_iter_append_variant_raw(&dict_iter
, value
, length
))
315 } else if (!method_iter_append_variant(&dict_iter
, type
, value
))
318 if (!dbus_message_iter_close_container(iter
, &dict_iter
))
324 dbus_message_iter_close_container(iter
, &dict_iter
);
329 method_default_handler(DBusPendingCall
*pending
,
332 DBusMessage
*msg
= dbus_pending_call_steal_reply(pending
);
337 if (!method_return_verify(msg
, &err_str
))
338 lash_error("%s", err_str
);
340 dbus_message_unref(msg
);
342 lash_error("Cannot get method return from pending call");
344 dbus_pending_call_unref(pending
);
348 method_call_init(method_msg_t
*call
,
350 void *return_context
,
351 DBusPendingCallNotifyFunction return_handler
,
352 const char *destination
,
354 const char *interface
,
357 if (!call
|| !service
|| !service
->connection
358 || !destination
|| !path
|| !method
) {
359 lash_error("Invalid arguments");
366 call
->message
= dbus_message_new_method_call(destination
, path
,
368 if (!call
->message
) {
369 lash_error("Ran out of memory trying to create "
374 call
->service
= service
;
375 call
->context
= return_context
;
376 call
->return_handler
= return_handler
;
379 dbus_message_set_no_reply(call
->message
, true);
385 method_call_new_void(service_t
*service
,
386 void *return_context
,
387 DBusPendingCallNotifyFunction return_handler
,
389 const char *destination
,
391 const char *interface
,
396 if (method_call_init(&call
, service
, return_context
, return_handler
,
397 destination
, path
, interface
, method
))
398 return method_send(&call
, will_block
);
404 method_call_new_single(service_t
*service
,
405 void *return_context
,
406 DBusPendingCallNotifyFunction return_handler
,
408 const char *destination
,
410 const char *interface
,
415 if (type
== DBUS_TYPE_INVALID
|| !arg
) {
416 lash_error("No argument supplied");
421 DBusMessageIter iter
;
423 if (!method_call_init(&call
, service
, return_context
, return_handler
,
424 destination
, path
, interface
, method
))
427 dbus_message_iter_init_append(call
.message
, &iter
);
429 if (dbus_message_iter_append_basic(&iter
, type
, arg
)) {
430 return method_send(&call
, will_block
);
433 lash_error("Ran out of memory trying to append method call argument");
435 dbus_message_unref(call
.message
);
442 method_call_new_valist(service_t
*service
,
443 void *return_context
,
444 DBusPendingCallNotifyFunction return_handler
,
446 const char *destination
,
448 const char *interface
,
453 if (type
== DBUS_TYPE_INVALID
) {
454 lash_error("No argument(s) supplied");
461 if (!method_call_init(&call
, service
, return_context
, return_handler
,
462 destination
, path
, interface
, method
))
465 va_start(argp
, type
);
467 if (dbus_message_append_args_valist(call
.message
, type
, argp
)) {
469 return method_send(&call
, will_block
);
474 lash_error("Ran out of memory trying to append "
475 "method call argument(s)");
477 dbus_message_unref(call
.message
);
484 method_iter_get_args(DBusMessageIter
*iter
,
488 lash_error("Iterator pointer is NULL");
493 int expected_type
, type
, n
= 0;
496 va_start(argp
, iter
);
498 while ((expected_type
= va_arg(argp
, int)) != DBUS_TYPE_INVALID
) {
499 ptr
= va_arg(argp
, void *);
501 if ((type
= dbus_message_iter_get_arg_type(iter
))
502 == DBUS_TYPE_INVALID
) {
503 lash_error("Insufficient arguments");
508 if (type
!= expected_type
) {
509 lash_error("Invalid type for argument %i", n
);
515 dbus_message_iter_get_basic(iter
, ptr
);
517 dbus_message_iter_next(iter
);
528 method_iter_get_dict_entry(DBusMessageIter
*iter
,
529 const char **key_ptr
,
534 if (!iter
|| !key_ptr
|| !value_ptr
|| !type_ptr
) {
535 lash_error("Invalid arguments");
539 DBusMessageIter dict_iter
, variant_iter
;
541 if (dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_DICT_ENTRY
) {
542 lash_error("Iterator does not point to a dict entry container");
546 dbus_message_iter_recurse(iter
, &dict_iter
);
548 if (dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_STRING
) {
549 lash_error("Cannot find key in dict entry container");
553 dbus_message_iter_get_basic(&dict_iter
, key_ptr
);
555 if (!dbus_message_iter_next(&dict_iter
)
556 || dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_VARIANT
) {
557 lash_error("Cannot find variant container in dict entry");
561 dbus_message_iter_recurse(&dict_iter
, &variant_iter
);
563 *type_ptr
= dbus_message_iter_get_arg_type(&variant_iter
);
564 if (*type_ptr
== DBUS_TYPE_INVALID
) {
565 lash_error("Cannot find value in variant container");
569 if (*type_ptr
== DBUS_TYPE_ARRAY
) {
570 DBusMessageIter array_iter
;
573 if (dbus_message_iter_get_element_type(&variant_iter
)
575 lash_error("Dict entry value is a non-byte array");
580 dbus_message_iter_recurse(&variant_iter
, &array_iter
);
581 dbus_message_iter_get_fixed_array(&array_iter
, value_ptr
, &n
);
586 dbus_message_iter_get_basic(&variant_iter
, value_ptr
);