#include "dbus-internals.h"
#include "dbus-marshal-recursive.h"
#include "dbus-marshal-validate.h"
+#include "dbus-marshal-byteswap.h"
#include "dbus-marshal-header.h"
+#include "dbus-signature.h"
#include "dbus-message-private.h"
#include "dbus-object-tree.h"
#include "dbus-memory.h"
#include "dbus-list.h"
+#include "dbus-threads-internal.h"
#include <string.h>
/**
} u; /**< the type writer or reader that does all the work */
};
+static void
+get_const_signature (DBusHeader *header,
+ 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))
+ {
+ *type_pos_p += 1; /* skip the signature length which is 1 byte */
+ }
+ else
+ {
+ *type_str_p = &_dbus_empty_signature_str;
+ *type_pos_p = 0;
+ }
+}
+
+/**
+ * Swaps the message to compiler byte order if required
+ *
+ * @param message the message
+ */
+static void
+_dbus_message_byteswap (DBusMessage *message)
+{
+ const DBusString *type_str;
+ int type_pos;
+
+ if (message->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,
+ DBUS_COMPILER_BYTE_ORDER,
+ &message->body, 0);
+
+ message->byte_order = DBUS_COMPILER_BYTE_ORDER;
+
+ _dbus_header_byteswap (&message->header, DBUS_COMPILER_BYTE_ORDER);
+}
+
+#define ensure_byte_order(message) \
+ if (message->byte_order != DBUS_COMPILER_BYTE_ORDER) \
+ _dbus_message_byteswap (message)
+
/**
* Gets the data to be sent over the network for this message.
* The header and then the body should be written out.
&value);
}
-static void
-get_const_signature (DBusHeader *header,
- 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))
- {
- *type_pos_p += 1; /* skip the signature length which is 1 byte */
- }
- else
- {
- *type_str_p = &_dbus_empty_signature_str;
- *type_pos_p = 0;
- }
-}
-
#if 0
/* Probably we don't need to use this */
/**
_dbus_header_free (&message->header);
_dbus_string_free (&message->body);
+ _dbus_assert (message->refcount.value == 0);
+
dbus_free (message);
}
*/
/** Avoid caching huge messages */
-#define MAX_MESSAGE_SIZE_TO_CACHE _DBUS_ONE_MEGABYTE
+#define MAX_MESSAGE_SIZE_TO_CACHE 10 * _DBUS_ONE_KILOBYTE
/** Avoid caching too many messages */
#define MAX_MESSAGE_CACHE_SIZE 5
{
dbus_bool_t was_cached;
int i;
-
+
_dbus_assert (message->refcount.value == 0);
/* This calls application code and has to be done first thing
message_cache[i] = message;
message_cache_count += 1;
was_cached = TRUE;
+#ifndef DBUS_DISABLE_CHECKS
+ message->in_cache = TRUE;
+#endif
out:
_DBUS_UNLOCK (message_cache);
+ _dbus_assert (message->refcount.value == 0);
+
if (!was_cached)
dbus_message_finalize (message);
}
message->generation = _dbus_current_generation;
#endif
}
-
+
message->refcount.value = 1;
message->byte_order = DBUS_COMPILER_BYTE_ORDER;
message->locked = FALSE;
+#ifndef DBUS_DISABLE_CHECKS
+ message->in_cache = FALSE;
+#endif
message->size_counters = NULL;
message->size_counter_delta = 0;
message->changed_stamp = 0;
* that if multiple methods with the given name exist it is undefined
* which one will be invoked.
*
- * @param destination service that the message should be sent to or #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
* @param method method to invoke
_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_service (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 (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_return_if_fail (message != NULL);
_dbus_return_if_fail (message->generation == _dbus_current_generation);
+ _dbus_return_if_fail (!message->in_cache);
old_refcount = _dbus_atomic_dec (&message->refcount);
* rather than this function.
*
* To append a basic type, specify its type code followed by the
- * value. For example:
+ * address of the value. For example:
*
* @code
- * DBUS_TYPE_INT32, 42,
- * DBUS_TYPE_STRING, "Hello World"
- * @endcode
- * or
- * @code
- * dbus_int32_t val = 42;
- * DBUS_TYPE_INT32, val
- * @endcode
*
- * Be sure that your provided value is the right size. For example, this
- * won't work:
- * @code
- * DBUS_TYPE_INT64, 42
+ * dbus_int32_t v_INT32 = 42;
+ * const char *v_STRING = "Hello World";
+ * DBUS_TYPE_INT32, &v_INT32,
+ * DBUS_TYPE_STRING, &v_STRING,
* @endcode
- * Because the "42" will be a 32-bit integer. You need to cast to
- * 64-bit.
*
* To append an array of fixed-length basic types, pass in the
* DBUS_TYPE_ARRAY typecode, the element typecode, the address of
* The last argument to this function must be #DBUS_TYPE_INVALID,
* marking the end of the argument list.
*
+ * String/signature/path arrays should be passed in as "const char***
+ * address_of_array" and "int n_elements"
+ *
* @todo support DBUS_TYPE_STRUCT and DBUS_TYPE_VARIANT and complex arrays
*
* @todo If this fails due to lack of memory, the message is hosed and
while (type != DBUS_TYPE_INVALID)
{
- if (_dbus_type_is_basic (type))
+ if (dbus_type_is_basic (type))
{
const DBusBasicValue *value;
value = va_arg (var_args, const DBusBasicValue*);
else if (type == DBUS_TYPE_ARRAY)
{
int element_type;
- const DBusBasicValue **value;
- int n_elements;
DBusMessageIter array;
char buf[2];
element_type = va_arg (var_args, int);
-
-#ifndef DBUS_DISABLE_CHECKS
- if (!_dbus_type_is_fixed (element_type))
- {
- _dbus_warn ("arrays of %s can't be appended with %s for now\n",
- _dbus_type_to_string (element_type),
- _DBUS_FUNCTION_NAME);
- goto failed;
- }
-#endif
-
- value = va_arg (var_args, const DBusBasicValue**);
- n_elements = va_arg (var_args, int);
-
+
buf[0] = element_type;
buf[1] = '\0';
if (!dbus_message_iter_open_container (&iter,
buf,
&array))
goto failed;
+
+ if (dbus_type_is_fixed (element_type))
+ {
+ const DBusBasicValue **value;
+ int n_elements;
+
+ value = va_arg (var_args, const DBusBasicValue**);
+ n_elements = va_arg (var_args, int);
+
+ if (!dbus_message_iter_append_fixed_array (&array,
+ element_type,
+ value,
+ n_elements))
+ goto failed;
+ }
+ else if (element_type == DBUS_TYPE_STRING ||
+ element_type == DBUS_TYPE_SIGNATURE ||
+ element_type == DBUS_TYPE_OBJECT_PATH)
+ {
+ const char ***value_p;
+ const char **value;
+ int n_elements;
+ int i;
+
+ value_p = va_arg (var_args, const char***);
+ n_elements = va_arg (var_args, int);
- if (!dbus_message_iter_append_fixed_array (&array,
- element_type,
- value,
- n_elements))
- goto failed;
+ value = *value_p;
+
+ i = 0;
+ while (i < n_elements)
+ {
+ if (!dbus_message_iter_append_basic (&array,
+ element_type,
+ &value[i]))
+ goto failed;
+ ++i;
+ }
+ }
+ else
+ {
+ _dbus_warn ("arrays of %s can't be appended with %s for now\n",
+ _dbus_type_to_string (element_type),
+ _DBUS_FUNCTION_NAME);
+ goto failed;
+ }
if (!dbus_message_iter_close_container (&iter, &array))
goto failed;
* In addition to those types, arrays of string, object path, and
* 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.
+ * types are returned as const references. To get a string array
+ * pass in "char ***array_location" and "int *n_elements"
*
* 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_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
+ */
+ ensure_byte_order (message);
+
real->message = message;
real->changed_stamp = message->changed_stamp;
real->iter_type = iter_type;
&message->body,
0);
- return _dbus_type_reader_has_next (&real->u.reader);
+ return _dbus_type_reader_get_current_type (&real->u.reader) != DBUS_TYPE_INVALID;
}
#ifndef DBUS_DISABLE_CHECKS
_dbus_warn ("dbus message changed byte order since iterator was created\n");
return FALSE;
}
+ /* because we swap the message into compiler order when you init an iter */
+ _dbus_assert (iter->u.reader.byte_order == DBUS_COMPILER_BYTE_ORDER);
}
else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER)
{
_dbus_warn ("dbus message changed byte order since append iterator was created\n");
return FALSE;
}
+ /* because we swap the message into compiler order when you init an iter */
+ _dbus_assert (iter->u.writer.byte_order == DBUS_COMPILER_BYTE_ORDER);
}
else
{
}
/**
+ * Returns the current signature of a message iterator. This
+ * is useful primarily for dealing with variants; one can
+ * recurse into a variant and determine the signature of
+ * the variant's value.
+ *
+ * @param iter the message iterator
+ * @returns the contained signature, or NULL if out of memory
+ */
+char *
+dbus_message_iter_get_signature (DBusMessageIter *iter)
+{
+ const DBusString *sig;
+ DBusString retstr;
+ char *ret;
+ int start, len;
+ DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+
+ _dbus_return_val_if_fail (_dbus_message_iter_check (real), NULL);
+
+ if (!_dbus_string_init (&retstr))
+ return NULL;
+
+ _dbus_type_reader_get_signature (&real->u.reader, &sig,
+ &start, &len);
+ if (!_dbus_string_append_len (&retstr,
+ _dbus_string_get_const_data (sig) + start,
+ len))
+ return NULL;
+ if (!_dbus_string_steal_data (&retstr, &ret))
+ return NULL;
+ _dbus_string_free (&retstr);
+ return ret;
+}
+
+/**
* Reads a basic-typed value from the message iterator.
* Basic types are the non-containers such as integer and string.
*
}
/**
+ * Returns the number of elements in the array;
+ *
+ * @param iter the iterator
+ * @returns the number of elements in the array
+ */
+int
+dbus_message_iter_get_array_len (DBusMessageIter *iter)
+{
+ DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+
+ _dbus_return_val_if_fail (_dbus_message_iter_check (real), 0);
+
+ return _dbus_type_reader_get_array_length (&real->u.reader);
+}
+
+/**
* Reads a block of fixed-length values from the message iterator.
* Fixed-length values are those basic types that are not string-like,
* 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.
_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_current_type (&real->u.reader)));
_dbus_type_reader_read_fixed_multi (&real->u.reader,
value, n_elements);
goto out;
}
- if (_dbus_type_is_basic (spec_type))
+ if (dbus_type_is_basic (spec_type))
{
DBusBasicValue *ptr;
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*);
spec_element_type == DBUS_TYPE_OBJECT_PATH)
{
char ***str_array_p;
- int i;
+ int n_elements;
char **str_array;
str_array_p = va_arg (var_args, char***);
/* Count elements in the array */
_dbus_type_reader_recurse (&real->u.reader, &array);
- i = 0;
- if (_dbus_type_reader_has_next (&array))
+ n_elements = 0;
+ while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID)
{
- while (_dbus_type_reader_next (&array))
- ++i;
+ ++n_elements;
+ _dbus_type_reader_next (&array);
}
- str_array = dbus_new0 (char*, i + 1);
+ str_array = dbus_new0 (char*, n_elements + 1);
if (str_array == NULL)
{
_DBUS_SET_OOM (error);
_dbus_type_reader_recurse (&real->u.reader, &array);
i = 0;
- if (_dbus_type_reader_has_next (&array))
+ while (i < n_elements)
{
- do
+ const char *s;
+ _dbus_type_reader_read_basic (&array,
+ &s);
+
+ str_array[i] = _dbus_strdup (s);
+ if (str_array[i] == NULL)
{
- const char *s;
- _dbus_type_reader_read_basic (&array,
- &s);
-
- str_array[i] = _dbus_strdup (s);
- if (str_array[i] == NULL)
- {
- dbus_free_string_array (str_array);
- _DBUS_SET_OOM (error);
- goto out;
- }
-
- ++i;
+ dbus_free_string_array (str_array);
+ _DBUS_SET_OOM (error);
+ goto out;
}
- while (_dbus_type_reader_next (&array));
+
+ ++i;
+
+ if (!_dbus_type_reader_next (&array))
+ _dbus_assert (i == 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);
+
*str_array_p = str_array;
- *n_elements_p = i;
+ *n_elements_p = n_elements;
}
#ifndef DBUS_DISABLE_CHECKS
else
_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_basic (type), FALSE);
+ _dbus_return_val_if_fail (dbus_type_is_basic (type), FALSE);
_dbus_return_val_if_fail (value != NULL, FALSE);
if (!_dbus_message_iter_open_signature (real))
_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);
* dbus_message_iter_close_container(). Container types are for
* example struct, variant, and array. For variants, the
* contained_signature should be the type of the single value inside
- * the variant. For structs, contained_signature should be #NULL; it
- * will be set to whatever types you write into the struct. For
- * arrays, contained_signature should be the type of the array
- * elements.
+ * the variant. For structs and dict entries, contained_signature
+ * should be #NULL; it will be set to whatever types you write into
+ * the struct. For arrays, contained_signature should be the type of
+ * the array elements.
*
* @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_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_container (type), FALSE);
+ _dbus_return_val_if_fail (dbus_type_is_container (type), FALSE);
_dbus_return_val_if_fail (sub != NULL, FALSE);
_dbus_return_val_if_fail ((type == DBUS_TYPE_STRUCT &&
contained_signature == NULL) ||
+ (type == DBUS_TYPE_DICT_ENTRY &&
+ contained_signature == NULL) ||
contained_signature != NULL, FALSE);
+
+#if 0
+ /* FIXME this would fail if the contained_signature is a dict entry,
+ * since dict entries are invalid signatures standalone (they must be in
+ * an array)
+ */
+ _dbus_return_val_if_fail (contained_signature == NULL ||
+ _dbus_check_is_valid_signature (contained_signature));
+#endif
if (!_dbus_message_iter_open_signature (real))
return FALSE;
- _dbus_string_init_const (&contained_str, contained_signature);
-
*real_sub = *real;
- return _dbus_type_writer_recurse (&real->u.writer,
- type,
- &contained_str, 0,
- &real_sub->u.writer);
+
+ if (contained_signature != NULL)
+ {
+ _dbus_string_init_const (&contained_str, contained_signature);
+
+ return _dbus_type_writer_recurse (&real->u.writer,
+ type,
+ &contained_str, 0,
+ &real_sub->u.writer);
+ }
+ else
+ {
+ return _dbus_type_writer_recurse (&real->u.writer,
+ type,
+ NULL, 0,
+ &real_sub->u.writer);
+ }
}
}
/**
- * Sets a flag indicating that the addressed service will be
- * auto-activated before the message is delivered. When this flag is
- * set, the message is held until the service is succesfully activated
- * or fails to activate. In case of failure, the reply will be an
- * activation error. If this flag is not set (the default
+ * Sets a flag indicating that an owner for the destination name will
+ * be automatically started before the message is delivered. When this
+ * flag is set, the message is held until a name owner finishes
+ * starting up, or fails to start up. In case of failure, the reply
+ * will be an error.
*
* @param message the message
- * @param auto_activation #TRUE if auto-activation is desired
+ * @param auto_start #TRUE if auto-starting is desired
*/
void
-dbus_message_set_auto_activation (DBusMessage *message,
- dbus_bool_t auto_activation)
+dbus_message_set_auto_start (DBusMessage *message,
+ dbus_bool_t auto_start)
{
_dbus_return_if_fail (message != NULL);
_dbus_return_if_fail (!message->locked);
_dbus_header_toggle_flag (&message->header,
- DBUS_HEADER_FLAG_AUTO_ACTIVATION,
- auto_activation);
+ DBUS_HEADER_FLAG_NO_AUTO_START,
+ !auto_start);
}
/**
- * Returns #TRUE if the message will cause the addressed service to be
- * auto-activated.
+ * Returns #TRUE if the message will cause an owner for
+ * destination name to be auto-started.
*
* @param message the message
- * @returns #TRUE if the message will use auto-activation
+ * @returns #TRUE if the message will use auto-start
*/
dbus_bool_t
-dbus_message_get_auto_activation (DBusMessage *message)
+dbus_message_get_auto_start (DBusMessage *message)
{
_dbus_return_val_if_fail (message != NULL, FALSE);
- return _dbus_header_get_flag (&message->header,
- DBUS_HEADER_FLAG_AUTO_ACTIVATION);
+ return !_dbus_header_get_flag (&message->header,
+ DBUS_HEADER_FLAG_NO_AUTO_START);
}
}
/**
+ * Checks if the message has a path
+ *
+ * @param message the message
+ * @returns #TRUE if there is a path field in the header
+ */
+dbus_bool_t
+dbus_message_has_path (DBusMessage *message,
+ const char *path)
+{
+ const char *msg_path;
+ msg_path = dbus_message_get_path (message);
+
+ if (msg_path == NULL)
+ {
+ if (path == NULL)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ if (path == NULL)
+ return FALSE;
+
+ if (strcmp (msg_path, path) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
* Gets the object path this message is being sent to
* (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
* from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed
}
/**
+ * Checks if the message has an interface
+ *
+ * @param message the message
+ * @returns #TRUE if there is a interface field in the header
+ */
+dbus_bool_t
+dbus_message_has_interface (DBusMessage *message,
+ const char *interface)
+{
+ const char *msg_interface;
+ msg_interface = dbus_message_get_interface (message);
+
+ if (msg_interface == NULL)
+ {
+ if (interface == NULL)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ if (interface == NULL)
+ return FALSE;
+
+ if (strcmp (msg_interface, interface) == 0)
+ return TRUE;
+
+ return FALSE;
+
+}
+
+/**
* Sets the interface member being invoked
* (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted
* (DBUS_MESSAGE_TYPE_SIGNAL).
}
/**
+ * Checks if the message has an interface member
+ *
+ * @param message the message
+ * @returns #TRUE if there is a member field in the header
+ */
+dbus_bool_t
+dbus_message_has_member (DBusMessage *message,
+ const char *member)
+{
+ const char *msg_member;
+ msg_member = dbus_message_get_member (message);
+
+ if (msg_member == NULL)
+ {
+ if (member == NULL)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ if (member == NULL)
+ return FALSE;
+
+ if (strcmp (msg_member, member) == 0)
+ return TRUE;
+
+ return FALSE;
+
+}
+
+/**
* Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR).
* The name is fully-qualified (namespaced).
*
}
/**
- * Sets the message's destination service.
+ * Sets the message's destination. The destination is the name of
+ * another connection on the bus and may be either the unique name
+ * assigned by the bus to each connection, or a well-known name
+ * specified in advance.
*
* @param message the message
- * @param destination the destination service name or #NULL to unset
+ * @param destination the destination name or #NULL to unset
* @returns #FALSE if not enough memory
*/
dbus_bool_t
_dbus_return_val_if_fail (message != NULL, FALSE);
_dbus_return_val_if_fail (!message->locked, FALSE);
_dbus_return_val_if_fail (destination == NULL ||
- _dbus_check_is_valid_service (destination),
+ _dbus_check_is_valid_bus_name (destination),
FALSE);
return set_or_delete_string_field (message,
}
/**
- * Gets the destination service of a message or #NULL if there is
- * none set.
+ * Gets the destination of a message or #NULL if there is none set.
*
* @param message the message
- * @returns the message destination service (should not be freed) or #NULL
+ * @returns the message destination (should not be freed) or #NULL
*/
const char*
dbus_message_get_destination (DBusMessage *message)
_dbus_return_val_if_fail (message != NULL, FALSE);
_dbus_return_val_if_fail (!message->locked, FALSE);
_dbus_return_val_if_fail (sender == NULL ||
- _dbus_check_is_valid_service (sender),
+ _dbus_check_is_valid_bus_name (sender),
FALSE);
return set_or_delete_string_field (message,
}
/**
- * Gets the service which originated this message,
- * or #NULL if unknown or inapplicable.
+ * Gets the unique name of the connection which originated this
+ * message, or #NULL if unknown or inapplicable. The sender is filled
+ * in by the message bus.
*
* @param message the message
- * @returns the service name or #NULL
+ * @returns the unique name of the sender or #NULL
*/
const char*
dbus_message_get_sender (DBusMessage *message)
}
/**
- * Checks whether the message was sent to the given service. If the
- * message has no service specified or has a different name, returns
- * #FALSE.
+ * Checks whether the message was sent to the given name. If the
+ * message has no destination specified or has a different
+ * destination, returns #FALSE.
*
* @param message the message
- * @param service the service to check (must not be #NULL)
+ * @param name the name to check (must not be #NULL)
*
- * @returns #TRUE if the message has the given destination service
+ * @returns #TRUE if the message has the given destination name
*/
dbus_bool_t
dbus_message_has_destination (DBusMessage *message,
- const char *service)
+ const char *name)
{
const char *s;
_dbus_return_val_if_fail (message != NULL, FALSE);
- _dbus_return_val_if_fail (service != NULL, FALSE);
- /* don't check that service name is valid since it would be expensive,
- * and not catch many common errors
+ _dbus_return_val_if_fail (name != NULL, FALSE);
+ /* don't check that name is valid since it would be expensive, and
+ * not catch many common errors
*/
s = dbus_message_get_destination (message);
- if (s && strcmp (s, service) == 0)
+ if (s && strcmp (s, name) == 0)
return TRUE;
else
return FALSE;
}
/**
- * Checks whether the message has the given service as its sender. If
- * the message has no sender specified or has a different sender,
- * returns #FALSE. Note that if a peer application owns multiple
- * services, its messages will have only one of those services as the
- * sender (usually the base service). So you can't use this
- * function to prove the sender didn't own service Foo, you can
- * only use it to prove that it did.
+ * Checks whether the message has the given unique name as its sender.
+ * If the message has no sender specified or has a different sender,
+ * returns #FALSE. Note that a peer application will always have the
+ * unique name of the connection as the sender. So you can't use this
+ * function to see whether a sender owned a well-known name.
*
- * @todo this function is probably useless unless we make a hard guarantee
- * that the sender field in messages will always be the base service name
+ * Messages from the bus itself will have #DBUS_SERVICE_DBUS
+ * as the sender.
*
* @param message the message
- * @param service the service to check (must not be #NULL)
+ * @param name the name to check (must not be #NULL)
*
- * @returns #TRUE if the message has the given origin service
+ * @returns #TRUE if the message has the given sender
*/
dbus_bool_t
dbus_message_has_sender (DBusMessage *message,
- const char *service)
+ const char *name)
{
const char *s;
_dbus_return_val_if_fail (message != NULL, FALSE);
- _dbus_return_val_if_fail (service != NULL, FALSE);
- /* don't check that service name is valid since it would be expensive,
- * and not catch many common errors
+ _dbus_return_val_if_fail (name != NULL, FALSE);
+ /* don't check that name is valid since it would be expensive, and
+ * not catch many common errors
*/
s = dbus_message_get_sender (message);
- if (s && strcmp (s, service) == 0)
+ if (s && strcmp (s, name) == 0)
return TRUE;
else
return FALSE;
loader = dbus_new0 (DBusMessageLoader, 1);
if (loader == NULL)
return NULL;
-
+
loader->refcount = 1;
- /* Try to cap message size at something that won't *totally* hose
- * the system if we have a couple of them.
- */
- loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
+ loader->corrupted = FALSE;
+ loader->corruption_reason = DBUS_VALID;
+
+ /* this can be configured by the app, but defaults to the protocol max */
+ loader->max_message_size = DBUS_MAXIMUM_MESSAGE_LENGTH;
if (!_dbus_string_init (&loader->data))
{
}
/**
- * The smallest header size that can occur. (It won't be valid due to
- * missing required header fields.) This is 4 bytes, two uint32, an
- * array length.
- */
-#define DBUS_MINIMUM_HEADER_SIZE 16
-
-/**
* Returns a buffer obtained from _dbus_message_loader_get_buffer(),
* indicating to the loader how many bytes of the buffer were filled
* in. This function must always be called, even if no bytes were
* loader->data and only delete it occasionally, instead of after
* each message is loaded.
*
- * load_message() returns FALSE if not enough memory
+ * load_message() returns FALSE if not enough memory OR the loader was corrupted
*/
static dbus_bool_t
load_message (DBusMessageLoader *loader,
DBusValidity validity;
const DBusString *type_str;
int type_pos;
+ DBusValidationMode mode;
+ mode = DBUS_VALIDATION_MODE_DATA_IS_UNTRUSTED;
+
oom = FALSE;
#if 0
_dbus_assert (_dbus_string_get_length (&message->header.data) == 0);
_dbus_assert ((header_len + body_len) <= _dbus_string_get_length (&loader->data));
- if (!_dbus_header_load_untrusted (&message->header,
- &validity,
- byte_order,
- fields_array_len,
- header_len,
- body_len,
- &loader->data, 0,
- _dbus_string_get_length (&loader->data)))
+ if (!_dbus_header_load (&message->header,
+ mode,
+ &validity,
+ byte_order,
+ fields_array_len,
+ header_len,
+ body_len,
+ &loader->data, 0,
+ _dbus_string_get_length (&loader->data)))
{
_dbus_verbose ("Failed to load header for new message code %d\n", validity);
- if (validity == DBUS_VALID)
+
+ /* assert here so we can catch any code that still uses DBUS_VALID to indicate
+ oom errors. They should use DBUS_VALIDITY_UNKNOWN_OOM_ERROR instead */
+ _dbus_assert (validity != DBUS_VALID);
+
+ if (validity == DBUS_VALIDITY_UNKNOWN_OOM_ERROR)
oom = TRUE;
+ else
+ {
+ loader->corrupted = TRUE;
+ loader->corruption_reason = validity;
+ }
goto failed;
}
message->byte_order = byte_order;
/* 2. VALIDATE BODY */
-
- 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 (validity != DBUS_VALID)
+ if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
{
- _dbus_verbose ("Failed to validate message body code %d\n", validity);
- goto failed;
+ 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 (validity != DBUS_VALID)
+ {
+ _dbus_verbose ("Failed to validate message body code %d\n", validity);
+
+ loader->corrupted = TRUE;
+ loader->corruption_reason = validity;
+
+ goto failed;
+ }
}
/* 3. COPY OVER BODY AND QUEUE MESSAGE */
_dbus_assert (!oom);
_dbus_assert (!loader->corrupted);
+ _dbus_assert (loader->messages != NULL);
+ _dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL);
return TRUE;
/* does nothing if the message isn't in the list */
_dbus_list_remove_last (&loader->messages, message);
-
- if (!oom)
- loader->corrupted = TRUE;
+
+ if (oom)
+ _dbus_assert (!loader->corrupted);
+ else
+ _dbus_assert (loader->corrupted);
_dbus_verbose_bytes_of_string (&loader->data, 0, _dbus_string_get_length (&loader->data));
- return !oom;
+ return FALSE;
}
/**
header_len, body_len))
{
dbus_message_unref (message);
- return FALSE;
+ /* load_message() returns false if corrupted or OOM; if
+ * corrupted then return TRUE for not OOM
+ */
+ return loader->corrupted;
}
+
+ _dbus_assert (loader->messages != NULL);
+ _dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL);
}
else
{
_dbus_verbose ("Initial peek at header says we don't have a whole message yet, or data broken with invalid code %d\n",
validity);
if (validity != DBUS_VALID)
- loader->corrupted = TRUE;
+ {
+ loader->corrupted = TRUE;
+ loader->corruption_reason = validity;
+ }
return TRUE;
}
}
dbus_bool_t
_dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
{
+ _dbus_assert ((loader->corrupted && loader->corruption_reason != DBUS_VALID) ||
+ (!loader->corrupted && loader->corruption_reason == DBUS_VALID));
return loader->corrupted;
}