2005-01-28 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-message.c
index 8bb4866..8525200 100644 (file)
@@ -25,6 +25,7 @@
 #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-message-private.h"
 #include "dbus-object-tree.h"
@@ -76,6 +77,57 @@ struct DBusMessageRealIter
   } 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.
@@ -250,25 +302,6 @@ set_or_delete_string_field (DBusMessage *message,
                                          &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 */
 /**
@@ -570,7 +603,7 @@ dbus_message_cache_or_finalize (DBusMessage *message)
 {
   dbus_bool_t was_cached;
   int i;
-
+  
   _dbus_assert (message->refcount.value == 0);
 
   /* This calls application code and has to be done first thing
@@ -654,7 +687,7 @@ dbus_message_new_empty_header (void)
       message->generation = _dbus_current_generation;
 #endif
     }
-
+  
   message->refcount.value = 1;
   message->byte_order = DBUS_COMPILER_BYTE_ORDER;
   message->locked = FALSE;
@@ -728,7 +761,7 @@ dbus_message_new (int message_type)
  * 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
@@ -747,7 +780,7 @@ dbus_message_new_method_call (const char *destination,
   _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);
@@ -1345,6 +1378,11 @@ _dbus_message_iter_init_common (DBusMessage         *message,
 {
   _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;
@@ -1381,7 +1419,7 @@ dbus_message_iter_init (DBusMessage     *message,
                           &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
@@ -1401,6 +1439,8 @@ _dbus_message_iter_check (DBusMessageRealIter *iter)
           _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)
     {
@@ -1409,6 +1449,8 @@ _dbus_message_iter_check (DBusMessageRealIter *iter)
           _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
     {
@@ -2070,10 +2112,10 @@ dbus_message_iter_append_fixed_array (DBusMessageIter *iter,
  * 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.
@@ -2100,7 +2142,21 @@ dbus_message_iter_open_container (DBusMessageIter *iter,
   _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);
+  _dbus_return_val_if_fail (type != DBUS_TYPE_DICT_ENTRY ||
+                            dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY,
+                            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;
@@ -2190,41 +2246,41 @@ dbus_message_get_no_reply (DBusMessage *message)
 }
 
 /**
- * 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);
 }
 
 
@@ -2462,10 +2518,13 @@ dbus_message_get_error_name (DBusMessage *message)
 }
 
 /**
- * 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
@@ -2475,7 +2534,7 @@ dbus_message_set_destination (DBusMessage  *message,
   _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,
@@ -2485,11 +2544,10 @@ dbus_message_set_destination (DBusMessage  *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)
@@ -2520,7 +2578,7 @@ dbus_message_set_sender (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,
@@ -2530,11 +2588,12 @@ dbus_message_set_sender (DBusMessage  *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)
@@ -2706,67 +2765,65 @@ dbus_message_is_error (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_ORG_FREEDESKTOP_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;
@@ -2880,9 +2937,12 @@ _dbus_message_loader_new (void)
   loader = dbus_new0 (DBusMessageLoader, 1);
   if (loader == NULL)
     return NULL;
-
+  
   loader->refcount = 1;
 
+  loader->corrupted = FALSE;
+  loader->corruption_reason = DBUS_VALID;
+  
   /* Try to cap message size at something that won't *totally* hose
    * the system if we have a couple of them.
    */
@@ -2966,13 +3026,6 @@ _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
 }
 
 /**
- * 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
@@ -3017,7 +3070,7 @@ _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
  * 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,
@@ -3031,7 +3084,10 @@ 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
@@ -3042,18 +3098,24 @@ load_message (DBusMessageLoader *loader,
   _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)
         oom = TRUE;
+      else
+        {
+          loader->corrupted = TRUE;
+          loader->corruption_reason = validity;
+        }
       goto failed;
     }
 
@@ -3062,23 +3124,29 @@ load_message (DBusMessageLoader *loader,
   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 */
@@ -3110,6 +3178,8 @@ load_message (DBusMessageLoader *loader,
 
   _dbus_assert (!oom);
   _dbus_assert (!loader->corrupted);
+  _dbus_assert (loader->messages != NULL);
+  _dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL);
 
   return TRUE;
 
@@ -3119,13 +3189,15 @@ load_message (DBusMessageLoader *loader,
 
   /* 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;
 }
 
 /**
@@ -3173,15 +3245,24 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
                              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;
         }
     }
@@ -3258,6 +3339,8 @@ _dbus_message_loader_putback_message_link (DBusMessageLoader  *loader,
 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;
 }