From 74b1b35402f6b9bbc09999a6224dfc04bc48b2a9 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 9 Mar 2005 17:09:11 +0000 Subject: 2005-03-09 Colin Walters * glib/dbus-gproxy.c (dbus_g_proxy_invoke): New method; calls to this are generated for client-side wrappers. Invokes a D-BUS method and returns reply values. * glib/dbus-binding-tool-glib.c (write_args_sig_for_direction): New function; writes signature string for argument direction. (write_args_for_direction): Change to pass input values directly instead of via address, and fix indentation. (generate_client_glue): Change to invoke dbus_g_proxy_invoke. Also make generated wrappers inlineable. * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Add note about using dbus_type_is_fixed. * dbus/dbus-marshal-basic.c (_dbus_type_is_fixed): Moved to dbus/dbus-signature.c as dbus_type_is_fixed. All callers updated. * dbus/dbus-signature.c (dbus_type_is_fixed): Moved here from dbus/dbus-marshal-basic.c:_dbus_type_is_fixed. * dbus/dbus-signature.h: Prototype. * glib/dbus-binding-tool-glib.c (compute_marshaller_name): Fix error printf code. * test/glib/test-dbus-glib.c (main): Be sure to clear error as appropriate instead of just freeing it. (main): Free returned strings using g_free. * test/glib/Makefile.am (test-service-glib-glue.h) (test-service-glib-bindings.h): Add dependency on dbus-binding-tool. * glib/dbus-gvalue.c (MAP_BASIC): Refactored from MAP_BASIC_INIT; simply maps a simple D-BUS type to GType. (dbus_dbus_type_to_gtype): Function which maps D-BUS type to GType. (dbus_gvalue_init): Just invoke dbus_dbus_type_to_gtype and initialize the value with it. (dbus_gvalue_binding_type_from_type): Unused, delete. (dbus_gvalue_demarshal): Switch to hardcoding demarshalling for various types instead of unmarshalling to value data directly. Remove can_convert boolean. (dbus_gvalue_marshal): Remove duplicate initialization; switch to returning directly instead of using can_convert boolean. (dbus_gvalue_store): New function; not related to D-BUS per-se. Stores a GValue in a pointer to a value of its corresponding C type. * glib/dbus-gvalue.h: Remove dbus_gvalue_binding_type_from_type, add dbus_gvalue_store. --- glib/dbus-gproxy.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) (limited to 'glib/dbus-gproxy.c') diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 65f14e12..b5e977a4 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -22,11 +22,14 @@ */ #include #include +#include #include "dbus-gutils.h" #include "dbus-gmarshal.h" #include "dbus-gvalue.h" #include "dbus-gobject.h" #include +#include +#include /** * @addtogroup DBusGLibInternals @@ -1396,6 +1399,208 @@ dbus_g_proxy_end_call (DBusGProxy *proxy, return FALSE; } +/** + * Function for invoking a method and receiving reply values. + * Normally this is not used directly - calls to it are generated + * from client-side wrappers (see dbus-binding-tool). + * + * This function takes two type signatures, one for method arguments, + * and one for return values. The remaining arguments after the + * error parameter should be values of the input arguments, + * followed by pointer values to storage for return values. + * + * @param proxy a proxy for a remote interface + * @param method method to invoke + * @param insig signature of input values + * @param outsig signature of output values + * @param error return location for an error + * @returns #FALSE if an error is set, TRUE otherwise + */ +gboolean +dbus_g_proxy_invoke (DBusGProxy *proxy, + const char *method, + const char *insig, + const char *outsig, + GError **error, + ...) +{ + DBusPendingCall *pending; + DBusMessage *message; + DBusMessage *reply; + va_list args; + va_list args_unwind; + int n_retvals_processed; + DBusMessageIter msgiter; + DBusSignatureIter sigiter; + int expected_type; + gboolean ret; + DBusError derror; + + g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE); + g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE); + + va_start (args, error); + /* Keep around a copy of output arguments so we + * can free on error. */ + G_VA_COPY (args_unwind, args); + + ret = FALSE; + pending = NULL; + reply = NULL; + n_retvals_processed = 0; + message = dbus_message_new_method_call (proxy->name, + proxy->path, + proxy->interface, + method); + if (message == NULL) + goto oom; + + dbus_signature_iter_init (&sigiter, insig); + dbus_message_iter_init_append (message, &msgiter); + while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID) + { + GValue gvalue = {0, }; + char *collect_err; + + if (!dbus_gvalue_init (expected_type, &gvalue)) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Unsupported type '%c'"), expected_type); + goto out; + } + + G_VALUE_COLLECT (&gvalue, args, G_VALUE_NOCOPY_CONTENTS, &collect_err); + + if (collect_err) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + collect_err); + goto out; + } + + /* Anything we can init must be marshallable */ + if (!dbus_gvalue_marshal (&msgiter, &gvalue)) + g_assert_not_reached (); + g_value_unset (&gvalue); + + dbus_signature_iter_next (&sigiter); + } + + if (!dbus_connection_send_with_reply (proxy->manager->connection, + message, + &pending, + -1)) + goto oom; + + dbus_pending_call_block (pending); + reply = dbus_pending_call_steal_reply (pending); + + g_assert (reply != NULL); + + dbus_error_init (&derror); + + switch (dbus_message_get_type (reply)) + { + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + + dbus_signature_iter_init (&sigiter, outsig); + dbus_message_iter_init (reply, &msgiter); + while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID) + { + int arg_type; + gpointer *value_ret; + GValue gvalue = { 0, }; + + value_ret = va_arg (args, gpointer *); + + arg_type = dbus_message_iter_get_arg_type (&msgiter); + if (expected_type != arg_type) + { + if (arg_type == DBUS_TYPE_INVALID) + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Too few arguments in reply")); + else + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Reply argument was \"%c\", expected \"%c\""), + arg_type, expected_type); + goto out; + } + + if (!dbus_gvalue_demarshal (&msgiter, &gvalue)) + { + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Couldn't convert argument type \"%c\""), expected_type); + goto out; + } + /* Anything that can be demarshaled must be storable */ + if (!dbus_gvalue_store (&gvalue, value_ret)) + g_assert_not_reached (); + g_value_unset (&gvalue); + + n_retvals_processed++; + dbus_signature_iter_next (&sigiter); + dbus_message_iter_next (&msgiter); + } + if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID) + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Too many arguments")); + goto out; + } + break; + case DBUS_MESSAGE_TYPE_ERROR: + dbus_set_error_from_message (&derror, reply); + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + goto out; + break; + default: + dbus_set_error (&derror, DBUS_ERROR_FAILED, + "Reply was neither a method return nor an exception"); + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + goto out; + break; + } + + ret = TRUE; + out: + va_end (args); + + if (ret == FALSE) + { + int i; + for (i = 0; i < n_retvals_processed; i++) + { + gpointer retval; + + retval = va_arg (args_unwind, gpointer); + + g_free (retval); + } + } + va_end (args_unwind); + + if (pending) + dbus_pending_call_unref (pending); + if (message) + dbus_message_unref (message); + if (reply) + dbus_message_unref (reply); + return ret; + oom: + g_error ("Out of memory"); + ret = FALSE; + goto out; +} + /** * Sends a method call message as with dbus_g_proxy_begin_call(), but * does not ask for a reply or allow you to receive one. -- cgit