*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
+#include <config.h>
#include "dbus-internals.h"
#include "dbus-marshal-recursive.h"
#include "dbus-marshal-validate.h"
#include "dbus-memory.h"
#include "dbus-list.h"
#include "dbus-threads-internal.h"
+
#ifdef HAVE_UNIX_FD_PASSING
#include "dbus-sysdeps-unix.h"
#endif
#include <string.h>
+#define _DBUS_TYPE_IS_STRINGLIKE(type) \
+ (type == DBUS_TYPE_STRING || type == DBUS_TYPE_SIGNATURE || \
+ type == DBUS_TYPE_OBJECT_PATH)
+
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 */
{
const DBusString *type_str;
int type_pos;
-
- if (message->byte_order == DBUS_COMPILER_BYTE_ORDER)
+ char byte_order;
+
+ byte_order = _dbus_header_get_byte_order (&message->header);
+
+ if (byte_order == DBUS_COMPILER_BYTE_ORDER)
return;
_dbus_verbose ("Swapping message into compiler byte order\n");
get_const_signature (&message->header, &type_str, &type_pos);
_dbus_marshal_byteswap (type_str, type_pos,
- message->byte_order,
+ byte_order,
DBUS_COMPILER_BYTE_ORDER,
&message->body, 0);
- message->byte_order = DBUS_COMPILER_BYTE_ORDER;
-
_dbus_header_byteswap (&message->header, DBUS_COMPILER_BYTE_ORDER);
+ _dbus_assert (_dbus_header_get_byte_order (&message->header) ==
+ DBUS_COMPILER_BYTE_ORDER);
}
/** byte-swap the message if it doesn't match our byte order.
* Otherwise should not be called since it would do needless
* work.
*/
-#define ensure_byte_order(message) \
- if (message->byte_order != DBUS_COMPILER_BYTE_ORDER) \
- _dbus_message_byteswap (message)
+#define ensure_byte_order(message) _dbus_message_byteswap (message)
/**
* Gets the data to be sent over the network for this message.
* itself not incremented. Ownership of link and counter refcount is
* passed to the message.
*
+ * This function may be called with locks held. As a result, the counter's
+ * notify function is not called; the caller is expected to either call
+ * _dbus_counter_notify() on the counter when they are no longer holding
+ * locks, or take the same action that would be taken by the notify function.
+ *
* @param message the message
* @param link link with counter as data
*/
* of this message, and decremented by the size/unix fds of this
* message when this message if finalized.
*
+ * This function may be called with locks held. As a result, the counter's
+ * notify function is not called; the caller is expected to either call
+ * _dbus_counter_notify() on the counter when they are no longer holding
+ * locks, or take the same action that would be taken by the notify function.
+ *
* @param message the message
* @param counter the counter
* @returns #FALSE if no memory
* decrements the counter by the size/unix fds of this message.
*
* @param message the message
- * @param link_return return the link used
* @param counter the counter
*/
void
_dbus_message_remove_counter (DBusMessage *message,
- DBusCounter *counter,
- DBusList **link_return)
+ DBusCounter *counter)
{
DBusList *link;
counter);
_dbus_assert (link != NULL);
- _dbus_list_unlink (&message->counters,
- link);
- if (link_return)
- *link_return = link;
- else
- _dbus_list_free_link (link);
+ _dbus_list_remove_link (&message->counters, link);
_dbus_counter_adjust_size (counter, - message->size_counter_delta);
_dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
#endif
+ _dbus_counter_notify (counter);
_dbus_counter_unref (counter);
}
}
}
+#ifdef ENABLE_KDBUS_TRANSPORT
+void
+dbus_message_unlock (DBusMessage *message)
+{
+ message->locked = FALSE;
+}
+#endif
+
static dbus_bool_t
set_or_delete_string_field (DBusMessage *message,
int field,
/** 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);
_dbus_assert (i < MAX_MESSAGE_CACHE_SIZE);
_dbus_assert (message != NULL);
- _dbus_assert (message->refcount.value == 0);
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
_dbus_assert (message->counters == NULL);
_DBUS_UNLOCK (message_cache);
_dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
#endif
+ _dbus_counter_notify (counter);
_dbus_counter_unref (counter);
}
{
dbus_bool_t was_cached;
int i;
-
- _dbus_assert (message->refcount.value == 0);
+
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
/* This calls application code and has to be done first thing
* without holding the lock
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)
#endif
out:
- _dbus_assert (message->refcount.value == 0);
-
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
_DBUS_UNLOCK (message_cache);
if (!was_cached)
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)
{
+ char byte_order;
+
if (iter == NULL)
{
_dbus_warn_check_failed ("dbus message iterator is NULL\n");
return FALSE;
}
+ byte_order = _dbus_header_get_byte_order (&iter->message->header);
+
if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_READER)
{
- if (iter->u.reader.byte_order != iter->message->byte_order)
+ if (iter->u.reader.byte_order != byte_order)
{
_dbus_warn_check_failed ("dbus message changed byte order since iterator was created\n");
return FALSE;
}
else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER)
{
- if (iter->u.writer.byte_order != iter->message->byte_order)
+ if (iter->u.writer.byte_order != byte_order)
{
_dbus_warn_check_failed ("dbus message changed byte order since append iterator was created\n");
return FALSE;
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.
*
- * Unix file descriptors that are read with this function will have
- * the FD_CLOEXEC flag set. If you need them without this flag set,
- * make sure to unset it with fcntl().
- *
* @todo This may leak memory and file descriptors if parsing fails. See #21259
*
* @see dbus_message_get_args
_dbus_type_reader_recurse (&real->u.reader, &array);
_dbus_type_reader_read_fixed_multi (&array,
- ptr, n_elements_p);
+ (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;
{
const char *s;
_dbus_type_reader_read_basic (&array,
- &s);
+ (void *) &s);
str_array[i] = _dbus_strdup (s);
if (str_array[i] == NULL)
static void
dbus_message_finalize (DBusMessage *message)
{
- _dbus_assert (message->refcount.value == 0);
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
/* This calls application callbacks! */
_dbus_data_slot_list_free (&message->slot_list);
dbus_free(message->unix_fds);
#endif
- _dbus_assert (message->refcount.value == 0);
-
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
dbus_free (message);
}
else
{
from_cache = FALSE;
- message = dbus_new (DBusMessage, 1);
+ message = dbus_new0 (DBusMessage, 1);
if (message == NULL)
return NULL;
#ifndef DBUS_DISABLE_CHECKS
message->n_unix_fds_allocated = 0;
#endif
}
-
- message->refcount.value = 1;
- message->byte_order = DBUS_COMPILER_BYTE_ORDER;
+
+ _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;
#ifdef HAVE_UNIX_FD_PASSING
message->n_unix_fds = 0;
+ message->n_unix_fds_allocated = 0;
message->unix_fd_counter_delta = 0;
#endif
if (from_cache)
{
- _dbus_header_reinit (&message->header, message->byte_order);
+ _dbus_header_reinit (&message->header);
_dbus_string_set_length (&message->body, 0);
}
else
{
- if (!_dbus_header_init (&message->header, message->byte_order))
+ if (!_dbus_header_init (&message->header))
{
dbus_free (message);
return NULL;
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
message_type,
NULL, NULL, NULL, NULL, NULL))
{
*
* @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 (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 ();
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_METHOD_CALL,
- destination, path, interface, method, NULL))
+ destination, path, iface, method, NULL))
{
dbus_message_unref (message);
return NULL;
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_METHOD_RETURN,
sender, NULL, NULL, NULL, NULL))
{
* 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 ();
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_SIGNAL,
- NULL, path, interface, name, NULL))
+ NULL, path, iface, name, NULL))
{
dbus_message_unref (message);
return NULL;
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_ERROR,
sender, NULL, NULL, NULL, error_name))
{
if (retval == NULL)
return NULL;
- retval->refcount.value = 1;
- retval->byte_order = message->byte_order;
+ _dbus_atomic_inc (&retval->refcount);
+
retval->locked = FALSE;
#ifndef DBUS_DISABLE_CHECKS
retval->generation = message->generation;
#endif
+ _dbus_message_trace_ref (retval, 0, 1, "copy");
return retval;
failed_copy:
_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);
-
+
old_refcount = _dbus_atomic_inc (&message->refcount);
_dbus_assert (old_refcount >= 1);
+ _dbus_message_trace_ref (message, old_refcount, old_refcount + 1, "ref");
return message;
}
old_refcount = _dbus_atomic_dec (&message->refcount);
- _dbus_assert (old_refcount >= 0);
+ _dbus_assert (old_refcount >= 1);
+
+ _dbus_message_trace_ref (message, old_refcount, old_refcount - 1, "unref");
if (old_refcount == 1)
{
* Appends fields to a message given a variable argument list. The
* variable argument list should contain the type of each argument
* followed by the value to append. Appendable types are basic types,
- * and arrays of fixed-length basic types. To append variable-length
- * basic types, or any more complex value, you have to use an iterator
- * rather than this function.
+ * and arrays of fixed-length basic types (except arrays of Unix file
+ * descriptors). To append variable-length basic types, or any more
+ * complex value, you have to use an iterator rather than this
+ * function.
*
* To append a basic type, specify its type code followed by the
* address of the value. For example:
* DBUS_TYPE_INVALID);
* @endcode
*
- * To append an array of fixed-length basic types, pass in the
- * DBUS_TYPE_ARRAY typecode, the element typecode, the address of
- * the array pointer, and a 32-bit integer giving the number of
- * elements in the array. So for example:
- * @code
- * const dbus_int32_t array[] = { 1, 2, 3 };
- * const dbus_int32_t *v_ARRAY = array;
- * dbus_message_append_args (message,
- * DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3,
- * DBUS_TYPE_INVALID);
+ * To append an array of fixed-length basic types (except Unix file
+ * descriptors), pass in the DBUS_TYPE_ARRAY typecode, the element
+ * typecode, the address of the array pointer, and a 32-bit integer
+ * giving the number of elements in the array. So for example: @code
+ * const dbus_int32_t array[] = { 1, 2, 3 }; const dbus_int32_t
+ * *v_ARRAY = array; dbus_message_append_args (message,
+ * DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3, DBUS_TYPE_INVALID);
* @endcode
*
+ * This function does not support arrays of Unix file descriptors. If
+ * you need those you need to manually recurse into the array.
+ *
+ * For Unix file descriptors this function will internally duplicate
+ * the descriptor you passed in. Hence you may close the descriptor
+ * immediately after this call.
+ *
* @warning in C, given "int array[]", "&array == array" (the
* comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree).
* So if you're using an array instead of a pointer you have to create
if (!dbus_message_iter_append_fixed_array (&array,
element_type,
value,
- n_elements))
+ n_elements)) {
+ dbus_message_iter_abandon_container (&iter, &array);
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;
{
if (!dbus_message_iter_append_basic (&array,
element_type,
- &value[i]))
+ &value[i])) {
+ dbus_message_iter_abandon_container (&iter, &array);
goto failed;
+ }
++i;
}
}
* signature are supported; but these are returned as allocated memory
* and must be freed with dbus_free_string_array(), while the other
* types are returned as const references. To get a string array
- * pass in "char ***array_location" and "int *n_elements"
+ * pass in "char ***array_location" and "int *n_elements".
+ *
+ * Similar to dbus_message_get_fixed_array() this function does not
+ * support arrays of type DBUS_TYPE_UNIX_FD. If you need to parse
+ * messages with arrays of Unix file descriptors you need to recurse
+ * into the array manually.
+ *
+ * Unix file descriptors that are read with this function will have
+ * the FD_CLOEXEC flag set. If you need them without this flag set,
+ * make sure to unset it with fcntl().
*
* The variable argument list should contain the type of the argument
* followed by a pointer to where the value should be stored. The list
DBUS_MESSAGE_ITER_TYPE_READER);
_dbus_type_reader_init (&real->u.reader,
- message->byte_order,
+ _dbus_header_get_byte_order (&message->header),
type_str, type_pos,
&message->body,
0);
* #DBUS_TYPE_INVALID. You can thus write a loop as follows:
*
* @code
- * dbus_message_iter_init (&iter);
+ * dbus_message_iter_init (message, &iter);
* while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
* dbus_message_iter_next (&iter);
* @endcode
* you won't be able to recurse further. There's no array of int32 to
* recurse into.
*
- * If a container is an array of fixed-length types, it is much more
- * efficient to use dbus_message_iter_get_fixed_array() to get the
- * whole array in one shot, rather than individually walking over the
- * array elements.
+ * If a container is an array of fixed-length types (except Unix file
+ * descriptors), it is much more efficient to use
+ * dbus_message_iter_get_fixed_array() to get the whole array in one
+ * shot, rather than individually walking over the array elements.
*
* Be sure you have somehow checked that
* dbus_message_iter_get_arg_type() matches the type you are expecting
* and for string a "const char**". The returned value is
* by reference and should not be freed.
*
+ * This call duplicates Unix file descriptors when reading them. It is
+ * your job to close them when you don't need them anymore.
+ *
+ * Unix file descriptors that are read with this function will have
+ * the FD_CLOEXEC flag set. If you need them without this flag set,
+ * make sure to unset it with fcntl().
+ *
* Be sure you have somehow checked that
* dbus_message_iter_get_arg_type() matches the type you are
* expecting, or you'll crash when you try to use an integer as a
* string or something.
*
- * To read any container type (array, struct, dict) you will need
- * to recurse into the container with dbus_message_iter_recurse().
- * If the container is an array of fixed-length values, 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:
+ * To read any container type (array, struct, dict) you will need to
+ * recurse into the container with dbus_message_iter_recurse(). If
+ * the container is an array of fixed-length values (except Unix file
+ * 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 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
* such as integers, bool, double. The returned block will be from the
* current position in the array until the end of the array.
*
+ * There is one exception here: although DBUS_TYPE_UNIX_FD is
+ * considered a 'fixed' type arrays of this type may not be read with
+ * this function.
+ *
* The message iter should be "in" the array (that is, you recurse into the
* array, and then you call dbus_message_iter_get_fixed_array() on the
* "sub-iterator" created by dbus_message_iter_recurse()).
int *n_elements)
{
DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+#ifndef DBUS_DISABLE_CHECKS
int subtype = _dbus_type_reader_get_current_type(&real->u.reader);
_dbus_return_if_fail (_dbus_message_iter_check (real));
_dbus_return_if_fail (value != NULL);
_dbus_return_if_fail ((subtype == DBUS_TYPE_INVALID) ||
(dbus_type_is_fixed (subtype) && subtype != DBUS_TYPE_UNIX_FD));
+#endif
_dbus_type_reader_read_fixed_multi (&real->u.reader,
value, n_elements);
* due to OOM.
*/
_dbus_type_writer_init_types_delayed (&real->u.writer,
- message->byte_order,
+ _dbus_header_get_byte_order (&message->header),
&message->body,
_dbus_string_get_length (&message->body));
}
return retval;
}
+/**
+ * Frees the signature string and marks the iterator as not having a
+ * type_str anymore. Since the new signature is not set, the message
+ * will generally be hosed after this is called.
+ *
+ * @param real an iterator without a type_str
+ */
+static void
+_dbus_message_iter_abandon_signature (DBusMessageRealIter *real)
+{
+ DBusString *str;
+
+ _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+ _dbus_assert (real->u.writer.type_str != NULL);
+ _dbus_assert (real->sig_refcount > 0);
+
+ real->sig_refcount -= 1;
+
+ if (real->sig_refcount > 0)
+ return;
+ _dbus_assert (real->sig_refcount == 0);
+
+ str = real->u.writer.type_str;
+
+ _dbus_type_writer_remove_types (&real->u.writer);
+ _dbus_string_free (str);
+ dbus_free (str);
+}
+
#ifndef DBUS_DISABLE_CHECKS
static dbus_bool_t
_dbus_message_iter_append_check (DBusMessageRealIter *iter)
* The "value" argument should be the address of a basic-typed value.
* So for string, const char**. For integer, dbus_int32_t*.
*
+ * For Unix file descriptors this function will internally duplicate
+ * the descriptor you passed in. Hence you may close the descriptor
+ * immediately after this call.
+ *
* @todo If this fails due to lack of memory, the message is hosed and
* you have to start over building the whole message.
*
_dbus_return_val_if_fail (dbus_type_is_basic (type), FALSE);
_dbus_return_val_if_fail (value != NULL, FALSE);
+#ifndef DBUS_DISABLE_CHECKS
+ switch (type)
+ {
+ const char * const *string_p;
+ const dbus_bool_t *bool_p;
+
+ case DBUS_TYPE_STRING:
+ string_p = value;
+ _dbus_return_val_if_fail (_dbus_check_is_valid_utf8 (*string_p), FALSE);
+ break;
+
+ case DBUS_TYPE_OBJECT_PATH:
+ string_p = value;
+ _dbus_return_val_if_fail (_dbus_check_is_valid_path (*string_p), FALSE);
+ break;
+
+ case DBUS_TYPE_SIGNATURE:
+ string_p = value;
+ _dbus_return_val_if_fail (_dbus_check_is_valid_signature (*string_p), FALSE);
+ break;
+
+ case DBUS_TYPE_BOOLEAN:
+ bool_p = value;
+ _dbus_return_val_if_fail (*bool_p == 0 || *bool_p == 1, FALSE);
+ break;
+
+ default:
+ {
+ /* nothing to check, all possible values are allowed */
+ }
+ }
+#endif
+
if (!_dbus_message_iter_open_signature (real))
return FALSE;
/**
* Appends a block of fixed-length values to an array. The
* fixed-length types are all basic types that are not string-like. So
- * int32, double, bool, etc. You must call
- * dbus_message_iter_open_container() to open an array of values
- * before calling this function. You may call this function multiple
- * times (and intermixed with calls to
+ * int32, double, bool, etc. (Unix file descriptors however are not
+ * supported.) You must call dbus_message_iter_open_container() to
+ * open an array of values before calling this function. You may call
+ * this function multiple times (and intermixed with calls to
* dbus_message_iter_append_basic()) for the same array.
*
* The "value" argument should be the address of the array. So for
DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type),
FALSE);
+#ifndef DBUS_DISABLE_CHECKS
+ if (element_type == DBUS_TYPE_BOOLEAN)
+ {
+ const dbus_bool_t * const *bools = value;
+ int i;
+
+ for (i = 0; i < n_elements; i++)
+ {
+ _dbus_return_val_if_fail ((*bools)[i] == 0 || (*bools)[i] == 1, FALSE);
+ }
+ }
+#endif
+
ret = _dbus_type_writer_write_fixed_multi (&real->u.writer, element_type, value, n_elements);
return ret;
}
/**
+ * Abandons creation of a contained-typed value and frees resources created
+ * by dbus_message_iter_open_container(). Once this returns, the message
+ * is hosed and you have to start over building the whole message.
+ *
+ * This should only be used to abandon creation of a message when you have
+ * open containers.
+ *
+ * @param iter the append iterator
+ * @param sub sub-iterator to close
+ */
+void
+dbus_message_iter_abandon_container (DBusMessageIter *iter,
+ DBusMessageIter *sub)
+{
+ DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+#ifndef DBUS_DISABLE_CHECKS
+ DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub;
+
+ _dbus_return_if_fail (_dbus_message_iter_append_check (real));
+ _dbus_return_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+ _dbus_return_if_fail (_dbus_message_iter_append_check (real_sub));
+ _dbus_return_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+#endif
+
+ _dbus_message_iter_abandon_signature (real);
+}
+
+/**
* Sets a flag indicating that the message does not want a reply; if
* this flag is set, the other end of the connection may (but is not
* required to) optimize by not sending method return or error
_dbus_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_PATH,
DBUS_TYPE_OBJECT_PATH,
- &v);
+ (void *) &v);
return v;
}
* 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);
}
/**
_dbus_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_INTERFACE,
DBUS_TYPE_STRING,
- &v);
+ (void *) &v);
return v;
}
* 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_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_MEMBER,
DBUS_TYPE_STRING,
- &v);
+ (void *) &v);
return v;
}
_dbus_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_ERROR_NAME,
DBUS_TYPE_STRING,
- &v);
+ (void *) &v);
return v;
}
_dbus_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_DESTINATION,
DBUS_TYPE_STRING,
- &v);
+ (void *) &v);
return v;
}
_dbus_header_get_field_basic (&message->header,
DBUS_HEADER_FIELD_SENDER,
DBUS_TYPE_STRING,
- &v);
+ (void *) &v);
return v;
}
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);
}
/**
return TRUE;
}
+/**
+ * Checks whether a message contains unix fds
+ *
+ * @param message the message
+ * @returns #TRUE if the message contains unix fds
+ */
+dbus_bool_t
+dbus_message_contains_unix_fds(DBusMessage *message)
+{
+#ifdef HAVE_UNIX_FD_PASSING
+ _dbus_assert(message);
+
+ return message->n_unix_fds > 0;
+#else
+ return FALSE;
+#endif
+}
+
/** @} */
/**
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))
{
return TRUE;
#else
_dbus_assert_not_reached("Platform doesn't support unix fd passing");
+ return FALSE;
#endif
}
*
* @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
_dbus_assert (validity == DBUS_VALID);
- message->byte_order = byte_order;
-
/* 2. VALIDATE BODY */
if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
{
}
/**
+ * Checks what kind of bad data confused the loader.
+ *
+ * @param loader the loader
+ * @returns why the loader is hosed, or DBUS_VALID if it isn't.
+ */
+DBusValidity
+_dbus_message_loader_get_corruption_reason (DBusMessageLoader *loader)
+{
+ _dbus_assert ((loader->corrupted && loader->corruption_reason != DBUS_VALID) ||
+ (!loader->corrupted && loader->corruption_reason == DBUS_VALID));
+
+ return loader->corruption_reason;
+}
+
+/**
* Sets the maximum size message we allow.
*
* @param loader the loader
* 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);
+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);
}
int *len_p)
{
DBusString tmp;
+ dbus_bool_t was_locked;
_dbus_return_val_if_fail (msg != NULL, FALSE);
_dbus_return_val_if_fail (marshalled_data_p != NULL, FALSE);
if (!_dbus_string_init (&tmp))
return FALSE;
+ /* Ensure the message is locked, to ensure the length header is filled in. */
+ was_locked = msg->locked;
+
+ if (!was_locked)
+ dbus_message_lock (msg);
+
if (!_dbus_string_copy (&(msg->header.data), 0, &tmp, 0))
goto fail;
goto fail;
_dbus_string_free (&tmp);
+
+ if (!was_locked)
+ msg->locked = FALSE;
+
return TRUE;
fail:
_dbus_string_free (&tmp);
+
+ if (!was_locked)
+ msg->locked = FALSE;
+
return FALSE;
}
return msg;
fail_corrupt:
- dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Message is corrupted");
+ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Message is corrupted (%s)",
+ _dbus_validity_to_error_message (loader->corruption_reason));
_dbus_message_loader_unref (loader);
return NULL;
* 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
*
*/
if (validity == DBUS_VALID)
{
- _dbus_assert(have_message);
+ _dbus_assert (have_message || (header_len + body_len) > len);
+ (void) have_message; /* unused unless asserting */
return header_len + body_len;
}
else