*
* Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc.
* Copyright (C) 2002, 2003 CodeFactory AB
+ * Copyright (C) 2015 Samsung Electronics
*
* Licensed under the Academic Free License version 2.1
*
#include "dbus-list.h"
#include "dbus-threads-internal.h"
#ifdef HAVE_UNIX_FD_PASSING
+#include "dbus-sysdeps.h"
#include "dbus-sysdeps-unix.h"
#endif
+#include "dbus-marshal-gvariant.h"
+#include "dbus-protocol-gvariant.h"
#include <string.h>
+#define _DBUS_TYPE_IS_STRINGLIKE(type) \
+ (type == DBUS_TYPE_STRING || type == DBUS_TYPE_SIGNATURE || \
+ type == DBUS_TYPE_OBJECT_PATH)
+
+unsigned char _dbus_default_protocol_version = DBUS_MAJOR_PROTOCOL_VERSION; /* DBUS_PROTOCOL_VERSION_GVARIANT; */
+
static void dbus_message_finalize (DBusMessage *message);
/**
* @{
*/
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
+static dbus_bool_t
+_dbus_enable_message_cache (void)
+{
+ static int enabled = -1;
+
+ if (enabled < 0)
+ {
+ const char *s = _dbus_getenv ("DBUS_MESSAGE_CACHE");
+
+ enabled = TRUE;
+
+ if (s && *s)
+ {
+ if (*s == '0')
+ enabled = FALSE;
+ else if (*s == '1')
+ enabled = TRUE;
+ else
+ _dbus_warn ("DBUS_MESSAGE_CACHE should be 0 or 1 if set, not '%s'",
+ s);
+ }
+ }
+
+ return enabled;
+}
+#else
+ /* constant expression, should be optimized away */
+# define _dbus_enable_message_cache() (TRUE)
+#endif
+
+#ifndef _dbus_message_trace_ref
+void
+_dbus_message_trace_ref (DBusMessage *message,
+ int old_refcount,
+ int new_refcount,
+ const char *why)
+{
+ static int enabled = -1;
+
+ _dbus_trace_ref ("DBusMessage", message, old_refcount, new_refcount, why,
+ "DBUS_MESSAGE_TRACE", &enabled);
+}
+#endif
+
/* Not thread locked, but strictly const/read-only so should be OK
*/
/** An static string representing an empty signature */
/** typedef for internals of message iterator */
typedef struct DBusMessageRealIter DBusMessageRealIter;
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+
/**
* @brief Internals of DBusMessageIter
*
} u; /**< the type writer or reader that does all the work */
};
+static dbus_bool_t
+_dbus_header_is_gvariant (const DBusHeader *header)
+{
+ return (header->protocol_version == DBUS_PROTOCOL_VERSION_GVARIANT);
+}
+
+static dbus_bool_t
+_dbus_message_is_gvariant (const DBusMessage *message)
+{
+ return _dbus_header_is_gvariant (&message->header);
+}
+
+static void
+_dbus_message_toggle_gvariant (DBusMessage *message, dbus_bool_t gvariant)
+{
+ message->header.protocol_version = gvariant ? DBUS_PROTOCOL_VERSION_GVARIANT : DBUS_MAJOR_PROTOCOL_VERSION;
+}
+
static void
-get_const_signature (DBusHeader *header,
+get_const_signature (DBusMessage *message,
const DBusString **type_str_p,
int *type_pos_p)
{
- if (_dbus_header_get_field_raw (header,
- DBUS_HEADER_FIELD_SIGNATURE,
- type_str_p,
- type_pos_p))
+ dbus_bool_t got_signature = FALSE;
+ if (_dbus_message_is_gvariant (message) && message->locked)
{
- *type_pos_p += 1; /* skip the signature length which is 1 byte */
+ /* only locked GVariant messages have signatures in the body */
+ /*
+ * in case of received GVariant message, there may be no signature field in a header,
+ * but in the body. However, it is not nul-terminated.
+ * So, we need to allocate space and put it into message.
+ * It could also happen before, so check message->signature for already existing.
+ * FIXME: That may kinda break oom-safety.
+ * For now - if oom, then return empty signature.
+ */
+ if (message->signature == NULL)
+ {
+ int type_str_len;
+ got_signature = _dbus_message_gvariant_get_signature (message,
+ type_str_p,
+ type_pos_p,
+ &type_str_len);
+ if (got_signature && type_str_len > 1)
+ {
+ message->signature = dbus_new (DBusString, 1);
+ got_signature = got_signature &&
+ _dbus_string_init_preallocated (message->signature, type_str_len - 1);
+
+ /* we need to copy the signature, but to ensure backward compatibility
+ * it must be stripped off outer parentheses - they are always there */
+ got_signature = got_signature &&
+ _dbus_string_copy_len (*type_str_p, *type_pos_p + 1, type_str_len - 2,
+ message->signature, 0);
+ got_signature = got_signature &&
+ _dbus_string_append_byte (message->signature, 0);
+ }
+ }
+ else
+ got_signature = TRUE;
+
+ if (got_signature)
+ {
+ *type_str_p = message->signature;
+ *type_pos_p = 0;
+ }
}
- else
+ else if (_dbus_header_get_field_raw (&message->header,
+ DBUS_HEADER_FIELD_SIGNATURE,
+ type_str_p,
+ type_pos_p))
+ {
+ if (!_dbus_message_is_gvariant (message))
+ *type_pos_p += 1; /* skip the signature length which is 1 byte */
+ got_signature = TRUE;
+ }
+ if (!got_signature)
{
*type_str_p = &_dbus_empty_signature_str;
*type_pos_p = 0;
_dbus_verbose ("Swapping message into compiler byte order\n");
- get_const_signature (&message->header, &type_str, &type_pos);
+ get_const_signature (message, &type_str, &type_pos);
_dbus_marshal_byteswap (type_str, type_pos,
byte_order,
{
if (!message->locked)
{
- _dbus_header_update_lengths (&message->header,
- _dbus_string_get_length (&message->body));
+ if (!_dbus_message_is_gvariant (message))
+ _dbus_header_update_lengths (&message->header,
+ _dbus_string_get_length (&message->body));
+ else
+ _dbus_message_finalize_gvariant (message, TRUE);
/* must have a signature if you have a body */
_dbus_assert (_dbus_string_get_length (&message->body) == 0 ||
/** Avoid caching too many messages */
#define MAX_MESSAGE_CACHE_SIZE 5
-_DBUS_DEFINE_GLOBAL_LOCK (message_cache);
+/* Protected by _DBUS_LOCK (message_cache) */
static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE];
static int message_cache_count = 0;
static dbus_bool_t message_cache_shutdown_registered = FALSE;
{
int i;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ _dbus_assert_not_reached ("we would have initialized global locks "
+ "before registering a shutdown function");
i = 0;
while (i < MAX_MESSAGE_CACHE_SIZE)
message = NULL;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ {
+ /* we'd have initialized global locks before caching anything,
+ * so there can't be anything in the cache */
+ return NULL;
+ }
_dbus_assert (message_cache_count >= 0);
close_unix_fds(int *fds, unsigned *n_fds)
{
DBusError e;
- int i;
+ unsigned int i;
if (*n_fds <= 0)
return;
close_unix_fds(message->unix_fds, &message->n_unix_fds);
#endif
+ if (NULL != message->signature)
+ {
+ _dbus_string_free (message->signature);
+ dbus_free (message->signature);
+ message->signature = NULL;
+ }
+
+ if (NULL != message->unique_sender)
+ {
+ _dbus_string_free (message->unique_sender);
+ dbus_free (message->unique_sender);
+ message->unique_sender = NULL;
+ }
+
was_cached = FALSE;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ {
+ /* The only way to get a non-null message goes through
+ * dbus_message_get_cached() which takes the lock. */
+ _dbus_assert_not_reached ("we would have initialized global locks "
+ "the first time we constructed a message");
+ }
if (!message_cache_shutdown_registered)
{
_dbus_assert (message_cache_count >= 0);
+ if (!_dbus_enable_message_cache ())
+ goto out;
+
if ((_dbus_string_get_length (&message->header.data) +
_dbus_string_get_length (&message->body)) >
MAX_MESSAGE_SIZE_TO_CACHE)
dbus_message_finalize (message);
}
-#ifndef DBUS_DISABLE_CHECKS
+#if defined(DBUS_ENABLE_CHECKS) || defined(DBUS_ENABLE_ASSERT)
static dbus_bool_t
_dbus_message_iter_check (DBusMessageRealIter *iter)
{
return TRUE;
}
-#endif /* DBUS_DISABLE_CHECKS */
+#endif /* DBUS_ENABLE_CHECKS || DBUS_ENABLE_ASSERT */
/**
* Implementation of the varargs arg-getting functions.
* dbus_message_get_args() is the place to go for complete
* documentation.
*
- * @todo This may leak memory and file descriptors if parsing fails. See #21259
- *
* @see dbus_message_get_args
* @param iter the message iter
* @param error error to be filled in
va_list var_args)
{
DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
- int spec_type, msg_type, i;
+ int spec_type, msg_type, i, j;
dbus_bool_t retval;
+ va_list copy_args;
_dbus_assert (_dbus_message_iter_check (real));
spec_type = first_arg_type;
i = 0;
+ /* copy var_args first, then we can do another iteration over it to
+ * free memory and close unix fds if parse failed at some point.
+ */
+ DBUS_VA_COPY (copy_args, var_args);
+
while (spec_type != DBUS_TYPE_INVALID)
{
msg_type = dbus_message_iter_get_arg_type (iter);
if (msg_type != spec_type)
- {
+ {
dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
"Argument %d is specified to be of type \"%s\", but "
"is actually of type \"%s\"\n", i,
_dbus_type_to_string (msg_type));
goto out;
- }
+ }
if (spec_type == DBUS_TYPE_UNIX_FD)
{
_dbus_type_reader_read_fixed_multi (&array,
(void *) ptr, n_elements_p);
}
- else if (spec_element_type == DBUS_TYPE_STRING ||
- spec_element_type == DBUS_TYPE_SIGNATURE ||
- spec_element_type == DBUS_TYPE_OBJECT_PATH)
+ else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type))
{
char ***str_array_p;
int n_elements;
/* Now go through and dup each string */
_dbus_type_reader_recurse (&real->u.reader, &array);
- i = 0;
- while (i < n_elements)
+ j = 0;
+ while (j < n_elements)
{
const char *s;
_dbus_type_reader_read_basic (&array,
(void *) &s);
- str_array[i] = _dbus_strdup (s);
- if (str_array[i] == NULL)
+ str_array[j] = _dbus_strdup (s);
+ if (str_array[j] == NULL)
{
dbus_free_string_array (str_array);
_DBUS_SET_OOM (error);
goto out;
}
- ++i;
+ ++j;
if (!_dbus_type_reader_next (&array))
- _dbus_assert (i == n_elements);
+ _dbus_assert (j == n_elements);
}
_dbus_assert (_dbus_type_reader_get_current_type (&array) == DBUS_TYPE_INVALID);
- _dbus_assert (i == n_elements);
- _dbus_assert (str_array[i] == NULL);
+ _dbus_assert (j == n_elements);
+ _dbus_assert (str_array[j] == NULL);
*str_array_p = str_array;
*n_elements_p = n_elements;
}
#endif
+ /* how many arguments already handled */
+ i++;
+
spec_type = va_arg (var_args, int);
if (!_dbus_type_reader_next (&real->u.reader) && spec_type != DBUS_TYPE_INVALID)
{
"Message has only %d arguments, but more were expected", i);
goto out;
}
-
- i++;
}
retval = TRUE;
out:
+ /* there may memory or unix fd leak in the above iteration if parse failed.
+ * so we have another iteration over copy_args to free memory and close
+ * unix fds.
+ */
+ if (!retval)
+ {
+ spec_type = first_arg_type;
+ j = 0;
+
+ while (j < i)
+ {
+ if (spec_type == DBUS_TYPE_UNIX_FD)
+ {
+#ifdef HAVE_UNIX_FD_PASSING
+ int *pfd;
+ pfd = va_arg (copy_args, int *);
+ _dbus_assert(pfd);
+ if (*pfd >= 0)
+ {
+ _dbus_close (*pfd, NULL);
+ *pfd = -1;
+ }
+#endif
+ }
+ else if (dbus_type_is_basic (spec_type))
+ {
+ /* move the index forward */
+ va_arg (copy_args, DBusBasicValue *);
+ }
+ else if (spec_type == DBUS_TYPE_ARRAY)
+ {
+ int spec_element_type;
+
+ spec_element_type = va_arg (copy_args, int);
+ if (dbus_type_is_fixed (spec_element_type))
+ {
+ /* move the index forward */
+ va_arg (copy_args, const DBusBasicValue **);
+ va_arg (copy_args, int *);
+ }
+ else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type))
+ {
+ char ***str_array_p;
+
+ str_array_p = va_arg (copy_args, char ***);
+ /* move the index forward */
+ va_arg (copy_args, int *);
+ _dbus_assert (str_array_p != NULL);
+ dbus_free_string_array (*str_array_p);
+ *str_array_p = NULL;
+ }
+ }
+
+ spec_type = va_arg (copy_args, int);
+ j++;
+ }
+ }
+
+ va_end (copy_args);
return retval;
}
dbus_message_set_reply_serial (DBusMessage *message,
dbus_uint32_t reply_serial)
{
+ int type = DBUS_TYPE_UINT32;
+
_dbus_return_val_if_fail (message != NULL, FALSE);
_dbus_return_val_if_fail (!message->locked, FALSE);
_dbus_return_val_if_fail (reply_serial != 0, FALSE); /* 0 is invalid */
+ if (_dbus_message_is_gvariant (message))
+ {
+ dbus_uint64_t reply_serial_uint64 = reply_serial;
+ type = DBUS_TYPE_UINT64;
+ return _dbus_header_set_field_basic (&message->header,
+ DBUS_HEADER_FIELD_REPLY_SERIAL,
+ type,
+ &reply_serial_uint64);
+ }
+
return _dbus_header_set_field_basic (&message->header,
DBUS_HEADER_FIELD_REPLY_SERIAL,
- DBUS_TYPE_UINT32,
+ type,
&reply_serial);
}
dbus_message_get_reply_serial (DBusMessage *message)
{
dbus_uint32_t v_UINT32;
+ dbus_uint64_t v_UINT64;
+ int type = DBUS_TYPE_UINT32;
+ void *value = &v_UINT32;
_dbus_return_val_if_fail (message != NULL, 0);
+ if (_dbus_message_is_gvariant (message))
+ {
+ type = DBUS_TYPE_UINT64;
+ value = &v_UINT64;
+ }
+
if (_dbus_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_REPLY_SERIAL,
- DBUS_TYPE_UINT32,
- &v_UINT32))
- return v_UINT32;
+ type,
+ value))
+ {
+ if (_dbus_message_is_gvariant (message))
+ return v_UINT64;
+ else
+ return v_UINT32;
+ }
else
return 0;
}
}
static DBusMessage*
-dbus_message_new_empty_header (void)
+dbus_message_new_empty_header (dbus_bool_t gvariant)
{
DBusMessage *message;
dbus_bool_t from_cache;
_dbus_atomic_inc (&message->refcount);
+ _dbus_message_trace_ref (message, 0, 1, "new_empty_header");
+
message->locked = FALSE;
#ifndef DBUS_DISABLE_CHECKS
message->in_cache = FALSE;
message->unix_fd_counter_delta = 0;
#endif
+ _dbus_message_toggle_gvariant (message, gvariant); /* this works only if kdbus is enabled */
+
if (!from_cache)
_dbus_data_slot_list_init (&message->slot_list);
}
}
+ message->signature = NULL;
+ message->unique_sender = NULL;
+ message->gvariant_body_last_offset = 0;
+ message->gvariant_body_last_pos = 0;
+
return message;
}
-/**
- * Constructs a new message of the given message type.
- * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL,
- * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth.
- *
- * Usually you want to use dbus_message_new_method_call(),
- * dbus_message_new_method_return(), dbus_message_new_signal(),
- * or dbus_message_new_error() instead.
- *
- * @param message_type type of message
- * @returns new message or #NULL if no memory
- */
-DBusMessage*
-dbus_message_new (int message_type)
+static DBusMessage*
+_dbus_message_create_protocol_version (int message_type,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ dbus_bool_t gvariant)
{
DBusMessage *message;
- _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL);
+ _dbus_assert (message_type != DBUS_MESSAGE_TYPE_INVALID);
- message = dbus_message_new_empty_header ();
+ message = dbus_message_new_empty_header (gvariant);
if (message == NULL)
return NULL;
- if (!_dbus_header_create (&message->header,
+ if (!(_dbus_message_is_gvariant(message) ? _dbus_header_gvariant_create : _dbus_header_create) (&message->header,
DBUS_COMPILER_BYTE_ORDER,
message_type,
- NULL, NULL, NULL, NULL, NULL))
+ destination, path, interface, member, error_name))
{
dbus_message_unref (message);
return NULL;
return message;
}
+static DBusMessage*
+_dbus_message_create (int message_type,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *error_name)
+{
+ return _dbus_message_create_protocol_version(message_type,
+ destination,
+ path,
+ interface,
+ member,
+ error_name,
+ _dbus_default_protocol_version == DBUS_PROTOCOL_VERSION_GVARIANT);
+}
+
+/**
+ * Constructs a new message of the given message type.
+ * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL,
+ * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth.
+ *
+ * Usually you want to use dbus_message_new_method_call(),
+ * dbus_message_new_method_return(), dbus_message_new_signal(),
+ * or dbus_message_new_error() instead.
+ *
+ * @param message_type type of message
+ * @returns new message or #NULL if no memory
+ */
+DBusMessage*
+dbus_message_new (int message_type)
+{
+ return _dbus_message_create(message_type,
+ NULL, NULL, NULL, NULL, NULL);
+}
+
/**
* Constructs a new message to invoke a method on a remote
* object. Returns #NULL if memory can't be allocated for the
*
* @param destination name that the message should be sent to or #NULL
* @param path object path the message should be sent to
- * @param interface interface to invoke method on, or #NULL
+ * @param iface interface to invoke method on, or #NULL
* @param method method to invoke
*
* @returns a new DBusMessage, free with dbus_message_unref()
DBusMessage*
dbus_message_new_method_call (const char *destination,
const char *path,
- const char *interface,
+ const char *iface,
const char *method)
{
- DBusMessage *message;
-
_dbus_return_val_if_fail (path != NULL, NULL);
_dbus_return_val_if_fail (method != NULL, NULL);
_dbus_return_val_if_fail (destination == NULL ||
_dbus_check_is_valid_bus_name (destination), NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL);
- _dbus_return_val_if_fail (interface == NULL ||
- _dbus_check_is_valid_interface (interface), NULL);
+ _dbus_return_val_if_fail (iface == NULL ||
+ _dbus_check_is_valid_interface (iface), NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_member (method), NULL);
- message = dbus_message_new_empty_header ();
- if (message == NULL)
- return NULL;
-
- if (!_dbus_header_create (&message->header,
- DBUS_COMPILER_BYTE_ORDER,
- DBUS_MESSAGE_TYPE_METHOD_CALL,
- destination, path, interface, method, NULL))
- {
- dbus_message_unref (message);
- return NULL;
- }
-
- return message;
+ return _dbus_message_create(DBUS_MESSAGE_TYPE_METHOD_CALL,
+ destination, path, iface, method, NULL);
}
/**
/* sender is allowed to be null here in peer-to-peer case */
- message = dbus_message_new_empty_header ();
+ message = _dbus_message_create (DBUS_MESSAGE_TYPE_METHOD_RETURN,
+ sender, NULL, NULL, NULL, NULL);
if (message == NULL)
return NULL;
- if (!_dbus_header_create (&message->header,
- DBUS_COMPILER_BYTE_ORDER,
- DBUS_MESSAGE_TYPE_METHOD_RETURN,
- sender, NULL, NULL, NULL, NULL))
- {
- dbus_message_unref (message);
- return NULL;
- }
-
dbus_message_set_no_reply (message, TRUE);
if (!dbus_message_set_reply_serial (message,
* specification defines the syntax of these fields).
*
* @param path the path to the object emitting the signal
- * @param interface the interface the signal is emitted from
+ * @param iface the interface the signal is emitted from
* @param name name of the signal
* @returns a new DBusMessage, free with dbus_message_unref()
*/
DBusMessage*
dbus_message_new_signal (const char *path,
- const char *interface,
+ const char *iface,
const char *name)
{
DBusMessage *message;
_dbus_return_val_if_fail (path != NULL, NULL);
- _dbus_return_val_if_fail (interface != NULL, NULL);
+ _dbus_return_val_if_fail (iface != NULL, NULL);
_dbus_return_val_if_fail (name != NULL, NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL);
- _dbus_return_val_if_fail (_dbus_check_is_valid_interface (interface), NULL);
+ _dbus_return_val_if_fail (_dbus_check_is_valid_interface (iface), NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_member (name), NULL);
- message = dbus_message_new_empty_header ();
+ message = _dbus_message_create (DBUS_MESSAGE_TYPE_SIGNAL,
+ NULL, path, iface, name, NULL);
if (message == NULL)
return NULL;
- if (!_dbus_header_create (&message->header,
- DBUS_COMPILER_BYTE_ORDER,
- DBUS_MESSAGE_TYPE_SIGNAL,
- NULL, path, interface, name, NULL))
- {
- dbus_message_unref (message);
- return NULL;
- }
-
dbus_message_set_no_reply (message, TRUE);
return message;
* when the message bus is dealing with an unregistered
* connection.
*/
- message = dbus_message_new_empty_header ();
+ message = _dbus_message_create (DBUS_MESSAGE_TYPE_ERROR,
+ sender, NULL, NULL, NULL, error_name);
if (message == NULL)
return NULL;
- if (!_dbus_header_create (&message->header,
- DBUS_COMPILER_BYTE_ORDER,
- DBUS_MESSAGE_TYPE_ERROR,
- sender, NULL, NULL, NULL, error_name))
- {
- dbus_message_unref (message);
- return NULL;
- }
-
dbus_message_set_no_reply (message, TRUE);
if (!dbus_message_set_reply_serial (message,
#ifndef DBUS_DISABLE_CHECKS
retval->generation = message->generation;
#endif
+ _dbus_message_toggle_gvariant (retval, _dbus_message_is_gvariant (message));
if (!_dbus_header_copy (&message->header, &retval->header))
{
#endif
+ _dbus_message_trace_ref (retval, 0, 1, "copy");
return retval;
failed_copy:
DBusMessage *
dbus_message_ref (DBusMessage *message)
{
-#ifndef DBUS_DISABLE_ASSERT
dbus_int32_t old_refcount;
-#endif
_dbus_return_val_if_fail (message != NULL, NULL);
_dbus_return_val_if_fail (message->generation == _dbus_current_generation, NULL);
_dbus_return_val_if_fail (!message->in_cache, NULL);
-#ifdef DBUS_DISABLE_ASSERT
- _dbus_atomic_inc (&message->refcount);
-#else
old_refcount = _dbus_atomic_inc (&message->refcount);
_dbus_assert (old_refcount >= 1);
-#endif
+ _dbus_message_trace_ref (message, old_refcount, old_refcount + 1, "ref");
return message;
}
_dbus_assert (old_refcount >= 1);
+ _dbus_message_trace_ref (message, old_refcount, old_refcount - 1, "unref");
+
if (old_refcount == 1)
{
/* Calls application callbacks! */
goto failed;
}
}
- else if (element_type == DBUS_TYPE_STRING ||
- element_type == DBUS_TYPE_SIGNATURE ||
- element_type == DBUS_TYPE_OBJECT_PATH)
+ else if (_DBUS_TYPE_IS_STRINGLIKE (element_type))
{
const char ***value_p;
const char **value;
DBusMessageRealIter *real,
int iter_type)
{
- _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
+ _DBUS_STATIC_ASSERT (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
/* Since the iterator will read or write who-knows-what from the
* message, we need to get in the right byte order
const DBusString *type_str;
int type_pos;
+ BUILD_BUG_ON (sizeof(DBusMessageIter) != sizeof(DBusMessageRealIter));
+
_dbus_return_val_if_fail (message != NULL, FALSE);
_dbus_return_val_if_fail (iter != NULL, FALSE);
- get_const_signature (&message->header, &type_str, &type_pos);
+ get_const_signature (message, &type_str, &type_pos);
_dbus_message_iter_init_common (message, real,
DBUS_MESSAGE_ITER_TYPE_READER);
_dbus_type_reader_init (&real->u.reader,
- _dbus_header_get_byte_order (&message->header),
- type_str, type_pos,
- &message->body,
- 0);
+ _dbus_header_get_byte_order (&message->header),
+ type_str, type_pos,
+ &message->body,
+ 0);
+
+ if (_dbus_message_is_gvariant (message))
+ _dbus_type_reader_gvariant_init (&real->u.reader, message);
return _dbus_type_reader_get_current_type (&real->u.reader) != DBUS_TYPE_INVALID;
}
* descriptors), you can get all the array elements at once with
* dbus_message_iter_get_fixed_array(). Otherwise, you have to iterate
* over the container's contents one value at a time.
- *
- * All basic-typed values are guaranteed to fit in 8 bytes. So you can
- * write code like this:
+ *
+ * All basic-typed values are guaranteed to fit in a #DBusBasicValue,
+ * so in versions of libdbus that have that type, you can write code like this:
*
* @code
- * dbus_uint64_t value;
+ * DBusBasicValue value;
* int type;
* dbus_message_iter_get_basic (&read_iter, &value);
* type = dbus_message_iter_get_arg_type (&read_iter);
* dbus_message_iter_append_basic (&write_iter, type, &value);
* @endcode
*
- * On some really obscure platforms dbus_uint64_t might not exist, if
- * you need to worry about this you will know. dbus_uint64_t is just
- * one example of a type that's large enough to hold any possible
- * value, you could use a struct or char[8] instead if you like.
+ * (All D-Bus basic types are either numeric and 8 bytes or smaller, or
+ * behave like a string; so in older versions of libdbus, DBusBasicValue
+ * can be replaced with union { char *string; unsigned char bytes[8]; },
+ * for instance.)
*
* @param iter the iterator
* @param value location to store the value
}
/**
+ * Returns the number of elements in the array-typed value pointed
+ * to by the iterator.
+ * Note that this function is O(1) for arrays of fixed-size types
+ * but O(n) for arrays of variable-length types such as strings,
+ * so it may be a bad idea to use it.
+ *
+ * @param iter the iterator
+ * @returns the number of elements in the array
+ */
+int
+dbus_message_iter_get_element_count (DBusMessageIter *iter)
+{
+ DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+ DBusTypeReader array;
+ int element_type;
+ int n_elements = 0;
+
+ _dbus_return_val_if_fail (_dbus_message_iter_check (real), 0);
+ _dbus_return_val_if_fail (_dbus_type_reader_get_current_type (&real->u.reader)
+ == DBUS_TYPE_ARRAY, 0);
+
+ element_type = _dbus_type_reader_get_element_type (&real->u.reader);
+ _dbus_type_reader_recurse (&real->u.reader, &array);
+ if (dbus_type_is_fixed (element_type))
+ {
+ int alignment = _dbus_type_get_alignment (element_type);
+ int total_len = _dbus_type_reader_get_array_length (&array);
+ n_elements = total_len / alignment;
+ }
+ else
+ {
+ while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID)
+ {
+ ++n_elements;
+ _dbus_type_reader_next (&array);
+ }
+ }
+
+ return n_elements;
+}
+
+/**
* Returns the number of bytes in the array as marshaled in the wire
* protocol. The iterator must currently be inside an array-typed
* value.
*
* This function is deprecated on the grounds that it is stupid. Why
* would you want to know how many bytes are in the array as marshaled
- * in the wire protocol? For now, use the n_elements returned from
- * dbus_message_iter_get_fixed_array() instead, or iterate over the
- * array values and count them.
+ * in the wire protocol? Use dbus_message_iter_get_element_count() instead.
*
- * @todo introduce a variant of this get_n_elements that returns
- * the number of elements, though with a non-fixed array it will not
- * be very efficient, so maybe it's not good.
- *
* @param iter the iterator
* @returns the number of bytes in the array
*/
* when a value is actually appended. That means that init() never fails
* due to OOM.
*/
- _dbus_type_writer_init_types_delayed (&real->u.writer,
- _dbus_header_get_byte_order (&message->header),
- &message->body,
- _dbus_string_get_length (&message->body));
+ _dbus_type_writer_gvariant_init_types_delayed (
+ &real->u.writer,
+ _dbus_header_get_byte_order (&message->header),
+ &message->body,
+ _dbus_string_get_length (&message->body),
+ _dbus_message_is_gvariant (message),
+ &message->gvariant_body_last_offset,
+ &message->gvariant_body_last_pos);
}
/**
if (current_sig)
{
int current_len;
+ int additional_size_for_len = 0;
- current_len = _dbus_string_get_byte (current_sig, current_sig_pos);
- current_sig_pos += 1; /* move on to sig data */
+ if (!real->u.writer.gvariant)
+ {
+ current_len = _dbus_string_get_byte (current_sig, current_sig_pos);
+ current_sig_pos += 1; /* move on to sig data */
+ additional_size_for_len = 4;
+ }
+ else
+ {
+ /* GVariant has no length field, simply string */
+ current_len = strlen (_dbus_string_get_const_data (current_sig) + current_sig_pos);
+ }
- if (!_dbus_string_init_preallocated (str, current_len + 4))
+ if (!_dbus_string_init_preallocated (str, current_len + additional_size_for_len))
{
dbus_free (str);
return FALSE;
* in the D-Bus specification.
*
* @param message the message
- * @param interface the interface or #NULL to unset
+ * @param iface the interface or #NULL to unset
* @returns #FALSE if not enough memory
*/
dbus_bool_t
dbus_message_set_interface (DBusMessage *message,
- const char *interface)
+ const char *iface)
{
_dbus_return_val_if_fail (message != NULL, FALSE);
_dbus_return_val_if_fail (!message->locked, FALSE);
- _dbus_return_val_if_fail (interface == NULL ||
- _dbus_check_is_valid_interface (interface),
+ _dbus_return_val_if_fail (iface == NULL ||
+ _dbus_check_is_valid_interface (iface),
FALSE);
return set_or_delete_string_field (message,
DBUS_HEADER_FIELD_INTERFACE,
DBUS_TYPE_STRING,
- interface);
+ iface);
}
/**
* Checks if the message has an interface
*
* @param message the message
- * @param interface the interface name
+ * @param iface the interface name
* @returns #TRUE if the interface field in the header matches
*/
dbus_bool_t
dbus_message_has_interface (DBusMessage *message,
- const char *interface)
+ const char *iface)
{
const char *msg_interface;
msg_interface = dbus_message_get_interface (message);
if (msg_interface == NULL)
{
- if (interface == NULL)
+ if (iface == NULL)
return TRUE;
else
return FALSE;
}
- if (interface == NULL)
+ if (iface == NULL)
return FALSE;
- if (strcmp (msg_interface, interface) == 0)
+ if (strcmp (msg_interface, iface) == 0)
return TRUE;
return FALSE;
_dbus_return_val_if_fail (message != NULL, NULL);
+ if (NULL != message->unique_sender)
+ return _dbus_string_get_const_data (message->unique_sender);
+
v = NULL; /* in case field doesn't exist */
_dbus_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_SENDER,
_dbus_return_val_if_fail (message != NULL, NULL);
- get_const_signature (&message->header, &type_str, &type_pos);
+ get_const_signature (message, &type_str, &type_pos);
return _dbus_string_get_const_data_len (type_str, type_pos, 0);
}
static dbus_bool_t
_dbus_message_has_type_interface_member (DBusMessage *message,
int type,
- const char *interface,
+ const char *iface,
const char *member)
{
const char *n;
_dbus_assert (message != NULL);
- _dbus_assert (interface != NULL);
+ _dbus_assert (iface != NULL);
_dbus_assert (member != NULL);
if (dbus_message_get_type (message) != type)
{
n = dbus_message_get_interface (message);
- if (n == NULL || strcmp (n, interface) == 0)
+ if (n == NULL || strcmp (n, iface) == 0)
return TRUE;
}
* protocol allows method callers to leave out the interface name.
*
* @param message the message
- * @param interface the name to check (must not be #NULL)
+ * @param iface the name to check (must not be #NULL)
* @param method the name to check (must not be #NULL)
*
* @returns #TRUE if the message is the specified method call
*/
dbus_bool_t
dbus_message_is_method_call (DBusMessage *message,
- const char *interface,
+ const char *iface,
const char *method)
{
_dbus_return_val_if_fail (message != NULL, FALSE);
- _dbus_return_val_if_fail (interface != NULL, FALSE);
+ _dbus_return_val_if_fail (iface != NULL, FALSE);
_dbus_return_val_if_fail (method != NULL, FALSE);
/* don't check that interface/method are valid since it would be
* expensive, and not catch many common errors
return _dbus_message_has_type_interface_member (message,
DBUS_MESSAGE_TYPE_METHOD_CALL,
- interface, method);
+ iface, method);
}
/**
* has a different interface or member field, returns #FALSE.
*
* @param message the message
- * @param interface the name to check (must not be #NULL)
+ * @param iface the name to check (must not be #NULL)
* @param signal_name the name to check (must not be #NULL)
*
* @returns #TRUE if the message is the specified signal
*/
dbus_bool_t
dbus_message_is_signal (DBusMessage *message,
- const char *interface,
+ const char *iface,
const char *signal_name)
{
_dbus_return_val_if_fail (message != NULL, FALSE);
- _dbus_return_val_if_fail (interface != NULL, FALSE);
+ _dbus_return_val_if_fail (iface != NULL, FALSE);
_dbus_return_val_if_fail (signal_name != NULL, FALSE);
/* don't check that interface/name are valid since it would be
* expensive, and not catch many common errors
return _dbus_message_has_type_interface_member (message,
DBUS_MESSAGE_TYPE_SIGNAL,
- interface, signal_name);
+ iface, signal_name);
}
/**
SCM_RIGHTS works we need to preallocate an fd array of the maximum
number of unix fds we want to receive in advance. A
try-and-reallocate loop is not possible. */
- loader->max_message_unix_fds = 1024;
+ loader->max_message_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS;
if (!_dbus_string_init (&loader->data))
{
*
* @param loader the loader.
* @param buffer the buffer.
- * @param bytes_read number of bytes that were read into the buffer.
*/
void
_dbus_message_loader_return_buffer (DBusMessageLoader *loader,
- DBusString *buffer,
- int bytes_read)
+ DBusString *buffer)
{
_dbus_assert (loader->buffer_outstanding);
_dbus_assert (buffer == &loader->data);
*
* @param loader the message loader.
* @param fds the array fds were read into
- * @param max_n_fds how many fds were read
+ * @param n_fds how many fds were read
*/
void
loader->n_unix_fds += n_fds;
loader->unix_fds_outstanding = FALSE;
+
+ if (n_fds && loader->unix_fds_change)
+ loader->unix_fds_change (loader->unix_fds_change_data);
#else
_dbus_assert_not_reached("Platform doesn't support unix fd passing");
#endif
/* 2. VALIDATE BODY */
if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
{
- get_const_signature (&message->header, &type_str, &type_pos);
-
- /* Because the bytes_remaining arg is NULL, this validates that the
- * body is the right length
- */
- validity = _dbus_validate_body_with_reason (type_str,
- type_pos,
- byte_order,
- NULL,
- &loader->data,
- header_len,
- body_len);
+ if (_dbus_message_is_gvariant (message))
+ {
+ validity = _dbus_validate_gvariant_body_with_reason (type_str,
+ type_pos,
+ byte_order,
+ NULL,
+ &loader->data,
+ header_len,
+ body_len);
+ }
+ else
+ {
+
+ get_const_signature (message, &type_str, &type_pos);
+
+ /* Because the bytes_remaining arg is NULL, this validates that the
+ * body is the right length
+ */
+
+ validity = _dbus_validate_body_with_reason (type_str,
+ type_pos,
+ byte_order,
+ NULL,
+ &loader->data,
+ header_len,
+ body_len);
+ }
if (validity != DBUS_VALID)
{
_dbus_verbose ("Failed to validate message body code %d\n", validity);
message->n_unix_fds_allocated = message->n_unix_fds = n_unix_fds;
loader->n_unix_fds -= n_unix_fds;
- memmove(loader->unix_fds + n_unix_fds, loader->unix_fds, loader->n_unix_fds);
+ memmove (loader->unix_fds, loader->unix_fds + n_unix_fds, loader->n_unix_fds * sizeof (loader->unix_fds[0]));
+
+ if (loader->unix_fds_change)
+ loader->unix_fds_change (loader->unix_fds_change_data);
}
else
message->unix_fds = NULL;
return FALSE;
}
+static dbus_bool_t
+set_unique_sender (DBusMessage *message, uint64_t unique_sender_id)
+{
+ if (NULL == message->unique_sender)
+ {
+ message->unique_sender = dbus_new (DBusString, 1);
+ if (NULL == message->unique_sender)
+ return FALSE;
+
+ if (!_dbus_string_init (message->unique_sender))
+ return FALSE;
+ }
+
+ _dbus_string_set_length (message->unique_sender, 0);
+
+ if (!_dbus_string_append_printf (message->unique_sender, ":1.%llu", (unsigned long long)unique_sender_id))
+ {
+ _dbus_string_free (message->unique_sender);
+ dbus_free (message->unique_sender);
+ message->unique_sender = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/**
* Converts buffered data into messages, if we have enough data. If
* we don't have enough data, does nothing.
{
DBusValidity validity;
int byte_order, fields_array_len, header_len, body_len;
+ dbus_bool_t is_gvariant;
if (_dbus_header_have_message_untrusted (loader->max_message_size,
&validity,
&header_len,
&body_len,
&loader->data, 0,
- _dbus_string_get_length (&loader->data)))
+ _dbus_string_get_length (&loader->data),
+ &is_gvariant))
{
DBusMessage *message;
_dbus_assert (validity == DBUS_VALID);
- message = dbus_message_new_empty_header ();
+ message = dbus_message_new_empty_header (is_gvariant);
if (message == NULL)
return FALSE;
return loader->corrupted;
}
+ if (_dbus_message_is_gvariant (message))
+ {
+ set_unique_sender (message, _dbus_message_loader_get_unique_sender_id (loader));
+ message->locked = TRUE;
+ }
+
_dbus_assert (loader->messages != NULL);
_dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL);
}
* Sets the maximum unix fds per message we allow.
*
* @param loader the loader
- * @param size the max number of unix fds in a message
+ * @param n the max number of unix fds in a message
*/
void
_dbus_message_loader_set_max_message_unix_fds (DBusMessageLoader *loader,
return loader->max_message_unix_fds;
}
-static DBusDataSlotAllocator slot_allocator;
-_DBUS_DEFINE_GLOBAL_LOCK (message_slots);
+/**
+ * Return how many file descriptors are pending in the loader
+ *
+ * @param loader the loader
+ */
+int
+_dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ return loader->n_unix_fds;
+#else
+ return 0;
+#endif
+}
+
+/**
+ * Register a function to be called whenever the number of pending file
+ * descriptors in the loader change.
+ *
+ * @param loader the loader
+ * @param callback the callback
+ * @param data the data for the callback
+ */
+void
+_dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader,
+ void (* callback) (void *),
+ void *data)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ loader->unix_fds_change = callback;
+ loader->unix_fds_change_data = data;
+#endif
+}
+
+void
+_dbus_message_loader_set_unique_sender_id (DBusMessageLoader *loader,
+ uint64_t id)
+{
+ loader->unique_sender_id = id;
+}
+
+uint64_t
+_dbus_message_loader_get_unique_sender_id (DBusMessageLoader *loader)
+{
+ return loader->unique_sender_id;
+}
+
+static DBusDataSlotAllocator slot_allocator =
+ _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (message_slots));
/**
* Allocates an integer ID to be used for storing application-specific
dbus_message_allocate_data_slot (dbus_int32_t *slot_p)
{
return _dbus_data_slot_allocator_alloc (&slot_allocator,
- &_DBUS_LOCK_NAME (message_slots),
slot_p);
}
return NULL;
_dbus_message_loader_get_buffer (loader, &buffer);
- _dbus_string_append_len (buffer, str, len);
- _dbus_message_loader_return_buffer (loader, buffer, len);
+
+ if (!_dbus_string_append_len (buffer, str, len))
+ goto fail_oom;
+
+ _dbus_message_loader_return_buffer (loader, buffer);
if (!_dbus_message_loader_queue_messages (loader))
goto fail_oom;
* Generally, this function is only useful for encapsulating D-Bus messages in
* a different protocol.
*
- * @param str data to be marshalled
- * @param len the length of str
- * @param error the location to save errors to
+ * @param buf data to be marshalled
+ * @param len the length of @p buf
* @returns -1 if there was no valid data to be demarshalled, 0 if there wasn't enough data to determine how much should be demarshalled. Otherwise returns the number of bytes to be demarshalled
*
*/
int byte_order, fields_array_len, header_len, body_len;
DBusValidity validity = DBUS_VALID;
int have_message;
+ dbus_bool_t is_gvariant;
if (!buf || len < DBUS_MINIMUM_HEADER_SIZE)
return 0;
&header_len,
&body_len,
&str, 0,
- len);
+ len,
+ &is_gvariant);
_dbus_string_free (&str);
if (validity == DBUS_VALID)
}
}
+static dbus_bool_t
+_dbus_message_copy_recursive(DBusMessageIter *iter, DBusMessageIter *dest)
+{
+ dbus_bool_t res = TRUE;
+ int current_type;
+
+ while ((current_type = dbus_message_iter_get_arg_type (iter)) != DBUS_TYPE_INVALID) {
+ if (dbus_type_is_basic(current_type)) {
+ DBusBasicValue value;
+ dbus_message_iter_get_basic (iter, &value);
+ dbus_message_iter_append_basic (dest, current_type, &value);
+ }
+ else {
+ DBusMessageIter sub;
+ DBusMessageIter dest_sub;
+ char *sig = NULL;
+
+ dbus_message_iter_recurse (iter, &sub);
+ if (DBUS_TYPE_VARIANT == current_type)
+ sig = dbus_message_iter_get_signature (&sub);
+ else if (DBUS_TYPE_ARRAY == current_type)
+ sig = dbus_message_iter_get_signature (&sub);
+
+ res = res && dbus_message_iter_open_container (dest, current_type, sig, &dest_sub);
+ dbus_free(sig);
+ res = res && _dbus_message_copy_recursive (&sub, &dest_sub);
+ res = res && dbus_message_iter_close_container (dest, &dest_sub);
+
+ if (!res) {
+ return FALSE;
+ }
+ }
+
+ dbus_message_iter_next (iter);
+ }
+
+ return TRUE;
+}
+
+DBusMessage *
+_dbus_message_remarshal (DBusMessage *message, dbus_bool_t gvariant)
+{
+ DBusMessage *ret;
+ DBusMessageIter iter, ret_iter;
+ int i;
+ dbus_uint32_t serial;
+ const char *sender;
+
+ _dbus_assert (message->locked);
+
+ ret = _dbus_message_create_protocol_version (dbus_message_get_type(message),
+ dbus_message_get_destination(message),
+ dbus_message_get_path(message),
+ dbus_message_get_interface(message),
+ dbus_message_get_member(message),
+ dbus_message_get_error_name(message),
+ gvariant);
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_init_append (ret, &ret_iter);
+ if (!_dbus_message_copy_recursive(&iter, &ret_iter))
+ return NULL;
+
+#ifdef HAVE_UNIX_FD_PASSING
+ ret->unix_fds = dbus_new(int, message->n_unix_fds);
+ if (ret->unix_fds == NULL && message->n_unix_fds > 0)
+ goto err;
+
+ ret->n_unix_fds_allocated = message->n_unix_fds;
+
+ for (i = 0; i < message->n_unix_fds; ++i) {
+ ret->unix_fds[i] = _dbus_dup(message->unix_fds[i], NULL);
+
+ if (ret->unix_fds[i] < 0)
+ goto err;
+ }
+
+ ret->n_unix_fds = message->n_unix_fds;
+#endif
+
+ /* Remarshal data in header:
+ byte order (already set)
+ type (already set)
+ flags - only those we understand
+ version (already set)
+ body length
+ serial
+ fields array (length)
+ fields:
+ path (already set)
+ interface (already set)
+ member (already set)
+ error name (already set)
+ reply serial
+ destination (already set)
+ sender
+ signature (set during copy, but an action needed for conversion to GVariant)
+ unix fds
+ */
+
+ /* FLAGS */
+ _dbus_header_toggle_flag (&ret->header, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED,
+ _dbus_header_get_flag (&message->header, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED));
+
+ _dbus_header_toggle_flag (&ret->header, DBUS_HEADER_FLAG_NO_AUTO_START,
+ _dbus_header_get_flag (&message->header, DBUS_HEADER_FLAG_NO_AUTO_START));
+
+ /* SERIAL / COOKIE */
+ serial = dbus_message_get_serial (message);
+
+ if (0 != serial)
+ dbus_message_set_serial (ret, serial);
+
+ /* Field: REPLY_SERIAL */
+ serial = dbus_message_get_reply_serial (message);
+
+ if (0 != serial && !dbus_message_set_reply_serial (ret, serial))
+ goto err;
+
+ /* Field: SENDER */
+ sender = dbus_message_get_sender (message);
+
+ if (NULL != sender && !dbus_message_set_sender (ret, sender))
+ goto err;
+
+ /* BODY LENGTH */
+ if (!gvariant)
+ _dbus_header_update_lengths (&ret->header,
+ _dbus_string_get_length (&ret->body));
+ /* For GVariant: */
+ /* Field: SIGNATURE to body; add body offset - this is done with dbus_message_lock() */
+ else
+ dbus_message_lock (ret);
+
+ return ret;
+
+err:
+ _dbus_header_free (&ret->header);
+ _dbus_string_free (&ret->body);
+
+#ifdef HAVE_UNIX_FD_PASSING
+ close_unix_fds(ret->unix_fds, &ret->n_unix_fds);
+ dbus_free(ret->unix_fds);
+#endif
+
+ return NULL;
+}
+
+void
+dbus_set_protocol_version (unsigned char version)
+{
+ _dbus_default_protocol_version = version;
+}
+
+DBusMessage *
+_dbus_generate_local_error_message (dbus_uint32_t serial,
+ char *error_name,
+ char *error_msg)
+{
+ DBusMessage *message;
+ message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
+ if (!message)
+ goto out;
+
+ if (!dbus_message_set_error_name (message, error_name))
+ {
+ dbus_message_unref (message);
+ message = NULL;
+ goto out;
+ }
+
+ dbus_message_set_no_reply (message, TRUE);
+
+ if (!dbus_message_set_reply_serial (message,
+ serial))
+ {
+ dbus_message_unref (message);
+ message = NULL;
+ goto out;
+ }
+
+ if (error_msg != NULL)
+ {
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append (message, &iter);
+ if (!dbus_message_iter_append_basic (&iter,
+ DBUS_TYPE_STRING,
+ &error_msg))
+ {
+ dbus_message_unref (message);
+ message = NULL;
+ goto out;
+ }
+ }
+
+ out:
+ return message;
+}
+
+dbus_bool_t
+_dbus_message_assure_dbus1 (DBusMessage **message)
+{
+ if ((*message)->header.protocol_version != DBUS_MAJOR_PROTOCOL_VERSION)
+ {
+ *message = _dbus_message_remarshal (*message, FALSE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+dbus_bool_t
+_dbus_message_assure_gvariant (DBusMessage **message)
+{
+ if ((*message)->header.protocol_version != DBUS_PROTOCOL_VERSION_GVARIANT)
+ {
+ *message = _dbus_message_remarshal (*message, TRUE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
/** @} */
/* tests in dbus-message-util.c */