Commit 74b1b354 authored by Colin Walters's avatar Colin Walters

2005-03-09 Colin Walters <walters@verbum.org>

	* 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.
parent 2958e723
2005-03-09 Colin Walters <walters@verbum.org>
* 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.
2005-03-08 Joe Shaw <joeshaw@novell.com>
Fix a bunch of lifecycle and memory management problems
......
......@@ -174,6 +174,13 @@ void dbus_g_proxy_call_no_reply (DBusGProxy *proxy,
const char* dbus_g_proxy_get_bus_name (DBusGProxy *proxy);
gboolean dbus_g_proxy_invoke (DBusGProxy *proxy,
const char *method,
const char *insig,
const char *outsig,
GError **error,
...);
#undef DBUS_INSIDE_DBUS_GLIB_H
G_END_DECLS
......
......@@ -620,7 +620,7 @@ _dbus_marshal_read_fixed_multi (const DBusString *str,
int array_len;
int alignment;
_dbus_assert (_dbus_type_is_fixed (element_type));
_dbus_assert (dbus_type_is_fixed (element_type));
_dbus_assert (dbus_type_is_basic (element_type));
#if 0
......@@ -1054,7 +1054,7 @@ marshal_fixed_multi (DBusString *str,
/**
* Marshals a block of values of fixed-length type all at once, as an
* optimization. _dbus_type_is_fixed() returns #TRUE for fixed-length
* optimization. dbus_type_is_fixed() returns #TRUE for fixed-length
* types, which are the basic types minus the string-like types.
*
* The value argument should be the adddress of an
......@@ -1080,7 +1080,7 @@ _dbus_marshal_write_fixed_multi (DBusString *str,
{
const void* vp = *(const DBusBasicValue**)value;
_dbus_assert (_dbus_type_is_fixed (element_type));
_dbus_assert (dbus_type_is_fixed (element_type));
_dbus_assert (n_elements >= 0);
#if 0
......@@ -1298,34 +1298,6 @@ _dbus_type_is_valid (int typecode)
}
}
/**
* Tells you whether values of this type can change length if you set
* them to some other value. For this purpose, you assume that the
* first byte of the old and new value would be in the same location,
* so alignment padding is not a factor.
*
* @returns #FALSE if the type can occupy different lengths
*/
dbus_bool_t
_dbus_type_is_fixed (int typecode)
{
switch (typecode)
{
case DBUS_TYPE_BYTE:
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
return TRUE;
default:
return FALSE;
}
}
/**
* Returns a string describing the given type.
*
......
......@@ -23,6 +23,7 @@
#include "dbus-marshal-byteswap.h"
#include "dbus-marshal-basic.h"
#include "dbus-signature.h"
/**
* @addtogroup DBusMarshal
......@@ -103,7 +104,7 @@ byteswap_body_helper (DBusTypeReader *reader,
p = _DBUS_ALIGN_ADDRESS (p, alignment);
if (_dbus_type_is_fixed (elem_type))
if (dbus_type_is_fixed (elem_type))
{
if (alignment > 1)
_dbus_swap_array (p, array_len / alignment, alignment);
......
......@@ -3074,7 +3074,7 @@ array_write_value (TestTypeNode *node,
goto oom;
if (arrays_write_fixed_in_blocks &&
_dbus_type_is_fixed (element_type) &&
dbus_type_is_fixed (element_type) &&
child->klass->write_multi)
{
if (!node_write_multi (child, block, &sub, seed, n_copies))
......@@ -3138,7 +3138,7 @@ array_read_or_set_value (TestTypeNode *node,
_dbus_type_reader_recurse (reader, &sub);
if (realign_root == NULL && arrays_write_fixed_in_blocks &&
_dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) &&
dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) &&
child->klass->read_multi)
{
if (!node_read_multi (child, &sub, seed, n_copies))
......
......@@ -1018,7 +1018,7 @@ _dbus_type_reader_read_fixed_multi (const DBusTypeReader *reader,
reader->type_pos);
_dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
_dbus_assert (_dbus_type_is_fixed (element_type));
_dbus_assert (dbus_type_is_fixed (element_type));
alignment = _dbus_type_get_alignment (element_type);
......@@ -1464,7 +1464,7 @@ _dbus_type_reader_set_basic (DBusTypeReader *reader,
_dbus_assert (dbus_type_is_basic (current_type));
if (_dbus_type_is_fixed (current_type))
if (dbus_type_is_fixed (current_type))
{
reader_set_basic_fixed_length (reader, current_type, value);
return TRUE;
......@@ -2404,7 +2404,7 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer,
/**
* Writes a block of fixed-length basic values, i.e. those that are
* both _dbus_type_is_fixed() and _dbus_type_is_basic(). The block
* both dbus_type_is_fixed() and _dbus_type_is_basic(). The block
* must be written inside an array.
*
* The value parameter should be the address of said array of values,
......@@ -2423,7 +2423,7 @@ _dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer,
int n_elements)
{
_dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
_dbus_assert (_dbus_type_is_fixed (element_type));
_dbus_assert (dbus_type_is_fixed (element_type));
_dbus_assert (writer->type_pos_is_expectation);
_dbus_assert (n_elements >= 0);
......
......@@ -1270,7 +1270,7 @@ dbus_message_append_args_valist (DBusMessage *message,
&array))
goto failed;
if (_dbus_type_is_fixed (element_type))
if (dbus_type_is_fixed (element_type))
{
const DBusBasicValue **value;
int n_elements;
......@@ -1676,6 +1676,9 @@ dbus_message_iter_get_basic (DBusMessageIter *iter,
* such as integers, bool, double. The block read will be from the
* current position in the array until the end of the array.
*
* This function should only be used if #dbus_type_is_fixed returns
* #TRUE for the element type.
*
* The value argument should be the address of a location to store the
* returned array. So for int32 it should be a "const dbus_int32_t**"
* The returned value is by reference and should not be freed.
......@@ -1693,7 +1696,7 @@ dbus_message_iter_get_fixed_array (DBusMessageIter *iter,
_dbus_return_if_fail (_dbus_message_iter_check (real));
_dbus_return_if_fail (value != NULL);
_dbus_return_if_fail (_dbus_type_is_fixed (_dbus_type_reader_get_element_type (&real->u.reader)));
_dbus_return_if_fail (dbus_type_is_fixed (_dbus_type_reader_get_element_type (&real->u.reader)));
_dbus_type_reader_read_fixed_multi (&real->u.reader,
value, n_elements);
......@@ -1778,7 +1781,7 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
goto out;
}
if (_dbus_type_is_fixed (spec_element_type))
if (dbus_type_is_fixed (spec_element_type))
{
ptr = va_arg (var_args, const DBusBasicValue**);
n_elements_p = va_arg (var_args, int*);
......@@ -2138,7 +2141,7 @@ dbus_message_iter_append_fixed_array (DBusMessageIter *iter,
_dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE);
_dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE);
_dbus_return_val_if_fail (_dbus_type_is_fixed (element_type), FALSE);
_dbus_return_val_if_fail (dbus_type_is_fixed (element_type), FALSE);
_dbus_return_val_if_fail (real->u.writer.container_type == DBUS_TYPE_ARRAY, FALSE);
_dbus_return_val_if_fail (value != NULL, FALSE);
_dbus_return_val_if_fail (n_elements >= 0, FALSE);
......
......@@ -262,6 +262,36 @@ dbus_type_is_basic (int typecode)
return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode));
}
/**
* Tells you whether values of this type can change length if you set
* them to some other value. For this purpose, you assume that the
* first byte of the old and new value would be in the same location,
* so alignment padding is not a factor.
*
* This function is useful to determine whether #dbus_message_iter_get_fixed_array
* may be used.
*
* @returns #FALSE if the type can occupy different lengths
*/
dbus_bool_t
dbus_type_is_fixed (int typecode)
{
switch (typecode)
{
case DBUS_TYPE_BYTE:
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_INT16:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
return TRUE;
default:
return FALSE;
}
}
#ifdef DBUS_BUILD_TESTS
......
......@@ -65,6 +65,7 @@ dbus_bool_t dbus_signature_validate_single (const char *signatur
dbus_bool_t dbus_type_is_basic (int typecode);
dbus_bool_t dbus_type_is_container (int typecode);
dbus_bool_t dbus_type_is_fixed (int typecode);
DBUS_END_DECLS
......
......@@ -140,7 +140,7 @@ compute_marshaller_name (MethodInfo *method, GError **error)
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
_("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
_("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
type);
g_string_free (ret, TRUE);
return NULL;
......@@ -647,42 +647,54 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
}
static gboolean
write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
{
GSList *args;
WRITE_OR_LOSE ("\"");
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
const char *type_str;
arg = args->data;
if (direction != arg_info_get_direction (arg))
continue;
type_str = dbus_gvalue_binding_type_from_type (arg_info_get_type (arg));
if (!type_str)
{
g_set_error (error,
DBUS_BINDING_TOOL_ERROR,
DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
_("Unsupported conversion from D-BUS type %s"),
arg_info_get_type (arg));
return FALSE;
}
if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg)))
goto io_lose;
}
WRITE_OR_LOSE ("\", ");
return TRUE;
io_lose:
return FALSE;
}
static gboolean
write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
{
GSList *args;
for (args = method_info_get_args (method); args; args = args->next)
{
ArgInfo *arg;
arg = args->data;
if (direction != arg_info_get_direction (arg))
continue;
switch (direction)
{
case ARG_IN:
if (!write_printf_to_iochannel (" %s, &IN_%s,\n", channel, error,
type_str, arg_info_get_name (arg)))
if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_OUT:
if (!write_printf_to_iochannel (" %s, OUT_%s,\n", channel, error,
type_str, arg_info_get_name (arg)))
if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg)))
goto io_lose;
break;
case ARG_INVALID:
......@@ -746,7 +758,7 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error
method_name = compute_client_method_name (interface, method);
WRITE_OR_LOSE ("static gboolean\n");
WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
method_name))
goto io_lose;
......@@ -758,29 +770,26 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error
WRITE_OR_LOSE (", GError **error)\n\n");
WRITE_OR_LOSE ("{\n");
WRITE_OR_LOSE (" gboolean ret;\n\n");
WRITE_OR_LOSE (" DBusGPendingCall *call;\n\n");
if (!write_printf_to_iochannel (" call = dbus_g_proxy_begin_call (proxy, \"%s\",\n",
channel, error,
if (!write_printf_to_iochannel (" return dbus_g_proxy_invoke (proxy, \"%s\", ", channel, error,
method_info_get_name (method)))
goto io_lose;
if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error))
goto io_lose;
WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n");
WRITE_OR_LOSE (" ret = dbus_g_proxy_end_call (proxy, call, error,\n");
if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error))
goto io_lose;
WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n");
WRITE_OR_LOSE ("error, ");
WRITE_OR_LOSE (" dbus_g_pending_call_unref (call);\n");
WRITE_OR_LOSE (" return ret;\n");
if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
goto io_lose;
if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
goto io_lose;
WRITE_OR_LOSE ("}\n\n");
WRITE_OR_LOSE ("NULL);\n}\n\n");
}
}
return TRUE;
......
......@@ -22,11 +22,14 @@
*/
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <dbus/dbus-signature.h>
#include "dbus-gutils.h"
#include "dbus-gmarshal.h"
#include "dbus-gvalue.h"
#include "dbus-gobject.h"
#include <string.h>
#include <glib/gi18n.h>
#include <gobject/gvaluecollector.h>
/**
* @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;
}