fix for memleaks
[platform/upstream/dbus.git] / dbus / dbus-message.c
index 0c7e80d..54056f3 100644 (file)
@@ -3,6 +3,7 @@
  *
  * 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);
 
 /**
@@ -52,6 +62,51 @@ 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 */
@@ -68,6 +123,8 @@ enum {
 /** 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
  *
@@ -86,19 +143,82 @@ struct DBusMessageRealIter
   } 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;
@@ -124,7 +244,7 @@ _dbus_message_byteswap (DBusMessage *message)
 
   _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,
@@ -335,8 +455,11 @@ dbus_message_lock (DBusMessage  *message)
 {
   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 ||
@@ -457,7 +580,7 @@ _dbus_message_set_signature (DBusMessage *message,
 /** 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;
@@ -467,7 +590,9 @@ dbus_message_cache_shutdown (void *data)
 {
   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)
@@ -499,7 +624,12 @@ dbus_message_get_cached (void)
 
   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);
 
@@ -545,7 +675,7 @@ static void
 close_unix_fds(int *fds, unsigned *n_fds)
 {
   DBusError e;
-  int i;
+  unsigned int i;
 
   if (*n_fds <= 0)
     return;
@@ -609,9 +739,29 @@ dbus_message_cache_or_finalize (DBusMessage *message)
   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)
     {
@@ -632,6 +782,9 @@ dbus_message_cache_or_finalize (DBusMessage *message)
 
   _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)
@@ -664,7 +817,7 @@ dbus_message_cache_or_finalize (DBusMessage *message)
     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)
 {
@@ -712,15 +865,13 @@ _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
@@ -735,8 +886,9 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
                                     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));
 
@@ -745,12 +897,17 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
   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,
@@ -758,7 +915,7 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
                           _dbus_type_to_string (msg_type));
 
           goto out;
-       }
+        }
 
       if (spec_type == DBUS_TYPE_UNIX_FD)
         {
@@ -839,9 +996,7 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
               _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;
@@ -873,30 +1028,30 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
               /* 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;
@@ -919,6 +1074,9 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
         }
 #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)
         {
@@ -926,14 +1084,71 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
                           "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;
 }
 
@@ -1015,13 +1230,25 @@ dbus_bool_t
 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);
 }
 
@@ -1035,14 +1262,28 @@ dbus_uint32_t
 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;
 }
@@ -1073,7 +1314,7 @@ dbus_message_finalize (DBusMessage *message)
 }
 
 static DBusMessage*
-dbus_message_new_empty_header (void)
+dbus_message_new_empty_header (dbus_bool_t gvariant)
 {
   DBusMessage *message;
   dbus_bool_t from_cache;
@@ -1102,6 +1343,8 @@ dbus_message_new_empty_header (void)
 
   _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;
@@ -1116,6 +1359,8 @@ dbus_message_new_empty_header (void)
   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);
 
@@ -1140,36 +1385,35 @@ dbus_message_new_empty_header (void)
         }
     }
 
+  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;
@@ -1178,6 +1422,42 @@ dbus_message_new (int message_type)
   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
@@ -1194,7 +1474,7 @@ dbus_message_new (int message_type)
  * 
  * @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()
@@ -1202,34 +1482,20 @@ dbus_message_new (int message_type)
 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);
 }
 
 /**
@@ -1251,19 +1517,11 @@ dbus_message_new_method_return (DBusMessage *method_call)
 
   /* 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,
@@ -1286,37 +1544,29 @@ dbus_message_new_method_return (DBusMessage *method_call)
  * 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;
@@ -1355,19 +1605,11 @@ dbus_message_new_error (DBusMessage *reply_to,
    * 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,
@@ -1470,6 +1712,7 @@ dbus_message_copy (const DBusMessage *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))
     {
@@ -1508,6 +1751,7 @@ dbus_message_copy (const DBusMessage *message)
 
 #endif
 
+  _dbus_message_trace_ref (retval, 0, 1, "copy");
   return retval;
 
  failed_copy:
@@ -1535,20 +1779,15 @@ dbus_message_copy (const DBusMessage *message)
 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;
 }
@@ -1573,6 +1812,8 @@ dbus_message_unref (DBusMessage *message)
 
   _dbus_assert (old_refcount >= 1);
 
+  _dbus_message_trace_ref (message, old_refcount, old_refcount - 1, "unref");
+
   if (old_refcount == 1)
     {
       /* Calls application callbacks! */
@@ -1751,9 +1992,7 @@ dbus_message_append_args_valist (DBusMessage *message,
                 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;
@@ -1899,7 +2138,7 @@ _dbus_message_iter_init_common (DBusMessage         *message,
                                 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
@@ -1942,19 +2181,24 @@ dbus_message_iter_init (DBusMessage     *message,
   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;
 }
@@ -2143,22 +2387,22 @@ dbus_message_iter_get_signature (DBusMessageIter *iter)
  * 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
@@ -2199,20 +2443,56 @@ dbus_message_iter_get_basic (DBusMessageIter  *iter,
 }
 
 /**
+ * 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
  */
@@ -2307,10 +2587,14 @@ dbus_message_iter_init_append (DBusMessage     *message,
    * 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);
 }
 
 /**
@@ -2349,11 +2633,21 @@ _dbus_message_iter_open_signature (DBusMessageRealIter *real)
   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;
@@ -3065,23 +3359,23 @@ dbus_message_get_path_decomposed (DBusMessage   *message,
  * 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);
 }
 
 /**
@@ -3116,28 +3410,28 @@ dbus_message_get_interface (DBusMessage *message)
  * 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;
@@ -3387,6 +3681,9 @@ dbus_message_get_sender (DBusMessage *message)
 
   _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,
@@ -3421,7 +3718,7 @@ dbus_message_get_signature (DBusMessage *message)
 
   _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);
 }
@@ -3429,13 +3726,13 @@ dbus_message_get_signature (DBusMessage *message)
 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)
@@ -3451,7 +3748,7 @@ _dbus_message_has_type_interface_member (DBusMessage *message,
     {
       n = dbus_message_get_interface (message);
 
-      if (n == NULL || strcmp (n, interface) == 0)
+      if (n == NULL || strcmp (n, iface) == 0)
         return TRUE;
     }
 
@@ -3467,18 +3764,18 @@ _dbus_message_has_type_interface_member (DBusMessage *message,
  * 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
@@ -3486,7 +3783,7 @@ dbus_message_is_method_call (DBusMessage *message,
 
   return _dbus_message_has_type_interface_member (message,
                                                   DBUS_MESSAGE_TYPE_METHOD_CALL,
-                                                  interface, method);
+                                                  iface, method);
 }
 
 /**
@@ -3495,18 +3792,18 @@ dbus_message_is_method_call (DBusMessage *message,
  * 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
@@ -3514,7 +3811,7 @@ dbus_message_is_signal (DBusMessage *message,
 
   return _dbus_message_has_type_interface_member (message,
                                                   DBUS_MESSAGE_TYPE_SIGNAL,
-                                                  interface, signal_name);
+                                                  iface, signal_name);
 }
 
 /**
@@ -3754,7 +4051,7 @@ _dbus_message_loader_new (void)
   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))
     {
@@ -3851,12 +4148,10 @@ _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
  *
  * @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);
@@ -3920,7 +4215,7 @@ _dbus_message_loader_get_unix_fds(DBusMessageLoader  *loader,
  *
  * @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
@@ -3935,6 +4230,9 @@ _dbus_message_loader_return_unix_fds(DBusMessageLoader  *loader,
 
   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
@@ -4024,18 +4322,33 @@ load_message (DBusMessageLoader *loader,
   /* 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);
@@ -4081,7 +4394,10 @@ load_message (DBusMessageLoader *loader,
 
       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;
@@ -4154,6 +4470,32 @@ load_message (DBusMessageLoader *loader,
   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.
@@ -4176,6 +4518,7 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
     {
       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,
@@ -4184,13 +4527,14 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
                                                &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;
 
@@ -4205,6 +4549,12 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
               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);
        }
@@ -4348,7 +4698,7 @@ _dbus_message_loader_get_max_message_size (DBusMessageLoader  *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,
@@ -4375,8 +4725,55 @@ _dbus_message_loader_get_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
@@ -4396,7 +4793,6 @@ dbus_bool_t
 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);
 }
 
@@ -4633,8 +5029,11 @@ dbus_message_demarshal (const char *str,
     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;
@@ -4669,9 +5068,8 @@ dbus_message_demarshal (const char *str,
  * 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
  * 
  */
@@ -4683,6 +5081,7 @@ dbus_message_demarshal_bytes_needed(const char *buf,
   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;
@@ -4699,7 +5098,8 @@ dbus_message_demarshal_bytes_needed(const char *buf,
                                           &header_len,
                                           &body_len,
                                           &str, 0,
-                                          len);
+                                          len,
+                                          &is_gvariant);
   _dbus_string_free (&str);
 
   if (validity == DBUS_VALID)
@@ -4714,6 +5114,228 @@ dbus_message_demarshal_bytes_needed(const char *buf,
     }
 }
 
+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 */