[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / gdbusconnection.c
index 7e2d9af..ca09ae3 100644 (file)
 #include "gsimpleasyncresult.h"
 
 #ifdef G_OS_UNIX
+#include "gkdbus.h"
 #include "gunixconnection.h"
 #include "gunixfdmessage.h"
 #endif
  * over any transport that can by represented as an #GIOStream.
  *
  * This class is rarely used directly in D-Bus clients. If you are writing
- * an D-Bus client, it is often easier to use the g_bus_own_name(),
+ * a D-Bus client, it is often easier to use the g_bus_own_name(),
  * g_bus_watch_name() or g_dbus_proxy_new_for_bus() APIs.
  *
  * As an exception to the usual GLib rule that a particular object must not
  * #GError, the only valid thing you can do with that #GDBusConnection is to
  * free it with g_object_unref().
  *
- * <example id="gdbus-server"><title>D-Bus server example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ * ## An example D-Bus server # {#gdbus-server}
  *
- * <example id="gdbus-subtree-server"><title>D-Bus subtree example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-subtree.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ * Here is an example for a D-Bus server:
+ * [gdbus-example-server.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-server.c)
  *
- * <example id="gdbus-unix-fd-client"><title>D-Bus UNIX File Descriptor example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-unix-fd-client.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ * ## An example for exporting a subtree # {#gdbus-subtree-server}
  *
- * <example id="gdbus-export"><title>Exporting a GObject</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-export.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ * Here is an example for exporting a subtree:
+ * [gdbus-example-subtree.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-subtree.c)
+ *
+ * ## An example for file descriptor passing # {#gdbus-unix-fd-client}
+ *
+ * Here is an example for passing UNIX file descriptors:
+ * [gdbus-unix-fd-client.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-unix-fd-client.c)
+ *
+ * ## An example for exporting a GObject # {#gdbus-export}
+ *
+ * Here is an example for exporting a #GObject:
+ * [gdbus-example-export.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-export.c)
  */
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -200,6 +213,8 @@ G_LOCK_DEFINE_STATIC (message_bus_lock);
 
 static GWeakRef the_session_bus;
 static GWeakRef the_system_bus;
+static GWeakRef the_user_bus;
+static GWeakRef the_machine_bus;
 
 /* Extra pseudo-member of GDBusSendMessageFlags.
  * Set by initable_init() to indicate that despite not being initialized yet,
@@ -269,6 +284,7 @@ call_destroy_notify (GMainContext  *context,
                          call_destroy_notify_data_in_idle,
                          data,
                          (GDestroyNotify) call_destroy_notify_data_free);
+  g_source_set_name (idle_source, "[gio] call_destroy_notify_data_in_idle");
   g_source_attach (idle_source, data->context);
   g_source_unref (idle_source);
 
@@ -374,6 +390,7 @@ struct _GDBusConnection
    * hold @init_lock or check for initialization first.
    */
   GDBusWorker *worker;
+  GKDBusWorker *kdbus_worker;
 
   /* If connected to a message bus, this contains the unique name assigned to
    * us by the bus (e.g. ":1.42").
@@ -1145,8 +1162,12 @@ g_dbus_connection_start_message_processing (GDBusConnection *connection)
   if (!check_initialized (connection))
     return;
 
-  g_assert (connection->worker != NULL);
-  _g_dbus_worker_unfreeze (connection->worker);
+  g_assert (connection->worker || connection->kdbus_worker);
+
+  if (connection->kdbus_worker)
+    g_kdbus_worker_unfreeze (connection->kdbus_worker);
+  else
+    _g_dbus_worker_unfreeze (connection->worker);
 }
 
 /**
@@ -1226,9 +1247,9 @@ flush_in_thread_func (GSimpleAsyncResult *res,
  * been sent to the networking buffers in the OS kernel.
  *
  * This is an asynchronous method. When the operation is finished,
- * @callback will be invoked in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * loop</link> of the thread you are calling this method from. You can
+ * @callback will be invoked in the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread you are calling this method from. You can
  * then call g_dbus_connection_flush_finish() to get the result of the
  * operation. See g_dbus_connection_flush_sync() for the synchronous
  * version.
@@ -1403,6 +1424,7 @@ schedule_closed_unlocked (GDBusConnection *connection,
                          emit_closed_in_idle,
                          data,
                          (GDestroyNotify) emit_closed_data_free);
+  g_source_set_name (idle_source, "[gio] emit_closed_in_idle");
   g_source_attach (idle_source, connection->main_context_at_construction);
   g_source_unref (idle_source);
 }
@@ -1430,14 +1452,14 @@ schedule_closed_unlocked (GDBusConnection *connection,
  * %G_IO_ERROR_CLOSED.
  *
  * When @connection has been closed, the #GDBusConnection::closed
- * signal is emitted in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * loop</link> of the thread that @connection was constructed in.
+ * signal is emitted in the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread that @connection was constructed in.
  *
  * This is an asynchronous method. When the operation is finished,
- * @callback will be invoked in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * loop</link> of the thread you are calling this method from. You can
+ * @callback will be invoked in the 
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread you are calling this method from. You can
  * then call g_dbus_connection_close_finish() to get the result of the
  * operation. See g_dbus_connection_close_sync() for the synchronous
  * version.
@@ -1577,6 +1599,468 @@ g_dbus_connection_close_sync (GDBusConnection  *connection,
 /* ---------------------------------------------------------------------------------------------------- */
 
 /**
+ * g_dbus_request_name:
+ * @connection: a #GDBusConnection
+ * @name: well-known bus name (name to request)
+ * @flags: a set of flags from the GBusNameOwnerFlags enumeration
+ * @error: return location for error or %NULL
+ *
+ * Synchronously acquires name on the bus and returns status code.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: status code or %G_BUS_REQUEST_NAME_FLAGS_ERROR
+ *     if @error is set.
+ *
+ * Since: 2.4x
+ */
+GBusRequestNameReplyFlags
+g_dbus_request_name (GDBusConnection     *connection,
+                     const gchar         *name,
+                     GBusNameOwnerFlags   flags,
+                     GError             **error)
+{
+  GVariant *result;
+  guint32 request_name_reply;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+  g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+  g_return_val_if_fail (error == NULL || *error == NULL, G_BUS_RELEASE_NAME_FLAGS_ERROR);
+
+  if (connection->kdbus_worker)
+    result = _g_kdbus_RequestName (connection->kdbus_worker, name, flags, error);
+  else
+    result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
+                                          "org.freedesktop.DBus", "RequestName",
+                                          g_variant_new ("(su)", name, flags), G_VARIANT_TYPE ("(u)"),
+                                          G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+
+  if (result != NULL)
+    {
+      g_variant_get (result, "(u)", &request_name_reply);
+      g_variant_unref (result);
+    }
+  else
+    request_name_reply = G_BUS_REQUEST_NAME_FLAGS_ERROR;
+
+  return (GBusRequestNameReplyFlags) request_name_reply;
+}
+
+/**
+ * g_dbus_release_name:
+ * @connection: a #GDBusConnection
+ * @name: well-known bus name (name to release)
+ * @error: return location for error or %NULL
+ *
+ * Synchronously releases name on the bus and returns status code.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: status code or %G_BUS_RELEASE_NAME_FLAGS_ERROR
+ *     if @error is set.
+ *
+ * Since: 2.4x
+ */
+GBusReleaseNameReplyFlags
+g_dbus_release_name (GDBusConnection     *connection,
+                     const gchar         *name,
+                     GError             **error)
+{
+  GVariant *result;
+  guint32 release_name_reply;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+  g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+  g_return_val_if_fail (error == NULL || *error == NULL, G_BUS_RELEASE_NAME_FLAGS_ERROR);
+
+  if (connection->kdbus_worker)
+    result = _g_kdbus_ReleaseName (connection->kdbus_worker, name, error);
+  else
+    result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
+                                          "org.freedesktop.DBus", "ReleaseName",
+                                          g_variant_new ("(s)", name), G_VARIANT_TYPE ("(u)"),
+                                          G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+
+  if (result != NULL)
+    {
+      g_variant_get (result, "(u)", &release_name_reply);
+      g_variant_unref (result);
+    }
+  else
+    release_name_reply = G_BUS_RELEASE_NAME_FLAGS_ERROR;
+
+  return (GBusReleaseNameReplyFlags) release_name_reply;
+}
+
+/**
+ * g_dbus_get_bus_id:
+ * @connection: a #GDBusConnection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the unique ID of the bus.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the unique ID of the bus or %NULL if @error is set.
+ *     Free with g_free().
+ *
+ * Since: 2.4x
+ */
+gchar *
+g_dbus_get_bus_id (GDBusConnection  *connection,
+                   GError          **error)
+{
+  GVariant *result;
+  gchar *bus_id;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  result = NULL;
+  bus_id = NULL;
+
+  if (connection->kdbus_worker)
+    {
+      result = _g_kdbus_GetBusId (connection->kdbus_worker, error);
+    }
+  else
+    {
+      result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+                                            "org.freedesktop.DBus", "GetId",
+                                            NULL, G_VARIANT_TYPE ("(s)"),
+                                            G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+    }
+
+  if (result != NULL)
+    {
+      g_variant_get (result, "(s)", &bus_id);
+      g_variant_unref (result);
+    }
+
+  return bus_id;
+}
+
+typedef enum
+{
+  LIST_NAMES,
+  LIST_ACTIVATABLE_NAMES,
+  LIST_QUEUED_OWNERS
+} GDBusListNameType;
+
+static gchar **
+_g_dbus_get_list_internal (GDBusConnection    *connection,
+                           const gchar        *name,
+                           GDBusListNameType   list_name_type,
+                           GError            **error)
+{
+  gchar **strv;
+  GVariant *result;
+  GVariantIter *iter;
+  gchar *str;
+  gsize n, i;
+
+  result = NULL;
+  strv = NULL;
+
+  if (list_name_type == LIST_QUEUED_OWNERS)
+    {
+      if (connection->kdbus_worker)
+        result = _g_kdbus_GetListQueuedOwners (connection->kdbus_worker, name, error);
+      else
+        result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+                                              "org.freedesktop.DBus", "ListQueuedOwners",
+                                              g_variant_new ("(s)", name), G_VARIANT_TYPE ("(as)"),
+                                              G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+    }
+  else
+    {
+      gchar *method_name;
+
+      if (list_name_type == LIST_NAMES)
+        method_name = "ListNames";
+      else
+        method_name = "ListActivatableNames";
+
+      if (connection->kdbus_worker)
+        result = _g_kdbus_GetListNames (connection->kdbus_worker, list_name_type, error);
+      else
+        result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+                                              "org.freedesktop.DBus", method_name,
+                                              NULL, G_VARIANT_TYPE ("(as)"),
+                                              G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+    }
+
+  if (result != NULL)
+    {
+      g_variant_get (result, "(as)", &iter);
+      n = g_variant_iter_n_children (iter);
+      strv = g_new (gchar *, n + 1);
+
+      i = 0;
+      while (g_variant_iter_loop (iter, "s", &str))
+        {
+          strv[i] = g_strdup (str);
+          i++;
+        }
+      strv[i] = NULL;
+
+      g_variant_iter_free (iter);
+      g_variant_unref (result);
+    }
+
+  return strv;
+}
+
+/**
+ * g_dbus_get_list_names:
+ * @connection: a #GDBusConnection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns a list of all currently-owned names on the bus.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: a list of all currently-owned names on the bus or %NULL if
+ *     @error is set. Free with g_strfreev().
+ *
+ * Since: 2.4x
+ */
+gchar **
+g_dbus_get_list_names (GDBusConnection  *connection,
+                       GError          **error)
+{
+  gchar **strv;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  strv = _g_dbus_get_list_internal (connection, NULL, LIST_NAMES, error);
+
+  return strv;
+}
+
+/**
+ * g_dbus_get_list_activatable_names:
+ * @connection: a #GDBusConnection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns a list of all names that can be activated on the bus.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: a list of all names that can be activated on the bus or %NULL if
+ *     @error is set. Free with g_strfreev().
+ *
+ * Since: 2.4x
+ */
+gchar **
+g_dbus_get_list_activatable_names (GDBusConnection  *connection,
+                                   GError          **error)
+{
+  gchar **strv;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  strv = _g_dbus_get_list_internal (connection, NULL, LIST_ACTIVATABLE_NAMES, error);
+
+  return strv;
+}
+
+/**
+ * g_dbus_get_list_queued_names:
+ * @connection: a #GDBusConnection
+ * @name: a unique or well-known bus name
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the unique bus names of connections currently queued
+ * for the @name.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns %NULL and @error is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the unique bus names of connections currently queued for the @name
+ *     or %NULL if @error is set. Free with g_strfreev().
+ *
+ * Since: 2.4x
+ */
+gchar **
+g_dbus_get_list_queued_owners (GDBusConnection  *connection,
+                               const gchar      *name,
+                               GError          **error)
+{
+  gchar **strv;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+  g_return_val_if_fail (name == NULL || g_dbus_is_name (name), NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  strv = _g_dbus_get_list_internal (connection, name, LIST_QUEUED_OWNERS, error);
+
+  return strv;
+}
+
+/**
+ * g_dbus_get_name_owner:
+ * @connection: a #GDBusConnection
+ * @name: well-known bus name to get the owner of
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the unique connection name of the primary owner of
+ * the name given. If the requested name doesn't have an owner, an @error is
+ * returned.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns %NULL and @error is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the unique connection name of the primary owner of the
+ *     name given. If the requested name doesn't have an owner, function
+ *     returns %NULL and @error is set. Free with g_free().
+ *
+ * Since: 2.4x
+ */
+gchar *
+g_dbus_get_name_owner (GDBusConnection  *connection,
+                       const gchar      *name,
+                       GError          **error)
+{
+  GVariant *result;
+  gchar *name_owner;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+  g_return_val_if_fail (name == NULL || g_dbus_is_name (name), NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  name_owner = NULL;
+  result = NULL;
+
+  if (connection->kdbus_worker)
+    result = _g_kdbus_GetNameOwner (connection->kdbus_worker, name, error);
+  else
+    result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+                                          "org.freedesktop.DBus", "GetNameOwner",
+                                          g_variant_new ("(s)", name), G_VARIANT_TYPE ("(s)"),
+                                          G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+  if (result != NULL)
+    {
+      g_variant_get (result, "(s)", &name_owner);
+      g_variant_unref (result);
+    }
+  else
+    name_owner = NULL;
+
+  return name_owner;
+}
+
+/**
+ * g_dbus_get_connection_pid:
+ * @connection: a #GDBusConnection
+ * @name: a unique or well-known bus name of the connection to query
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the Unix process ID of the process connected to the
+ * bus. If unable to determine it, an @error is returned.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns (guint32) -1 and @error
+ * is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the Unix process ID of the process connected to the bus or
+ *     (guint32) -1 if @error is set.
+ *
+ * Since: 2.4x
+ */
+guint32
+g_dbus_get_connection_pid (GDBusConnection  *connection,
+                           const gchar      *name,
+                           GError          **error)
+{
+  GVariant *result;
+  guint32 pid;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), -1);
+  g_return_val_if_fail (name == NULL || g_dbus_is_name (name), -1);
+  g_return_val_if_fail (error == NULL || *error == NULL, -1);
+
+  result = NULL;
+  pid = -1;
+
+  if (connection->kdbus_worker)
+    result = _g_kdbus_GetConnectionUnixProcessID (connection->kdbus_worker, name, error);
+  else
+    result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+                                          "org.freedesktop.DBus", "GetConnectionUnixProcessID",
+                                          g_variant_new ("(s)", name), G_VARIANT_TYPE ("(u)"),
+                                          G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+  if (result != NULL)
+    {
+      g_variant_get (result, "(u)", &pid);
+      g_variant_unref (result);
+    }
+
+  return pid;
+}
+
+/**
+ * g_dbus_get_connection_uid:
+ * @connection: a #GDBusConnection
+ * @name: a unique or well-known bus name of the connection to query
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the Unix user ID of the process connected to the
+ * bus. If unable to determine it, an @error is returned.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns (guint32) -1 and @error
+ * is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the Unix user ID of the process connected to the bus or
+ *     (guint32) -1 if @error is set.
+ *
+ * Since: 2.4x
+ */
+guint32
+g_dbus_get_connection_uid (GDBusConnection  *connection,
+                           const gchar      *name,
+                           GError          **error)
+{
+  GVariant *result;
+  guint32 uid;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), -1);
+  g_return_val_if_fail (name == NULL || g_dbus_is_name (name), -1);
+  g_return_val_if_fail (error == NULL || *error == NULL, -1);
+
+  result = NULL;
+  uid = -1;
+
+  if (connection->kdbus_worker)
+    result = _g_kdbus_GetConnectionUnixUser (connection->kdbus_worker, name, error);
+  else
+    result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+                                          "org.freedesktop.DBus", "GetConnectionUnixUser",
+                                          g_variant_new ("(s)", name), G_VARIANT_TYPE ("(u)"),
+                                          G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+  if (result != NULL)
+    {
+      g_variant_get (result, "(u)", &uid);
+      g_variant_unref (result);
+    }
+
+  return uid;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
  * g_dbus_connection_get_last_serial:
  * @connection: a #GDBusConnection
  *
@@ -1607,7 +2091,7 @@ g_dbus_connection_get_last_serial (GDBusConnection *connection)
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
-
+#include "gkdbus.h"
 /* Can be called by any thread, with the connection lock held */
 static gboolean
 g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
@@ -1648,13 +2132,16 @@ g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
                                  &blob_size,
                                  connection->capabilities,
                                  error);
+
   if (blob == NULL)
     goto out;
 
-  if (flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL)
-    serial_to_use = g_dbus_message_get_serial (message);
-  else
-    serial_to_use = ++connection->last_serial; /* TODO: handle overflow */
+  if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
+    g_dbus_message_set_serial (message, ++connection->last_serial);
+
+  serial_to_use = g_dbus_message_get_serial (message);
+
+  g_dbus_message_lock (message);
 
   switch (blob[0])
     {
@@ -1691,14 +2178,14 @@ g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
                         g_thread_self (),
                         GUINT_TO_POINTER (serial_to_use));
 
-  if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
-    g_dbus_message_set_serial (message, serial_to_use);
-
-  g_dbus_message_lock (message);
+  if (connection->worker)
   _g_dbus_worker_send_message (connection->worker,
                                message,
                                (gchar*) blob,
                                blob_size);
+  else
+  g_kdbus_worker_send_message (connection->kdbus_worker, message, error);
+
   blob = NULL; /* since _g_dbus_worker_send_message() steals the blob */
 
   ret = TRUE;
@@ -1731,9 +2218,9 @@ g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
  * %G_IO_ERROR_CLOSED. If @message is not well-formed,
  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
  *
- * See <xref linkend="gdbus-server"/> and <xref
- * linkend="gdbus-unix-fd-client"/> for an example of how to use this
- * low-level API to send and receive UNIX file descriptors.
+ * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
+ * for an example of how to use this low-level API to send and receive
+ * UNIX file descriptors.
  *
  * Note that @message must be unlocked, unless @flags contain the
  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
@@ -1905,6 +2392,7 @@ send_message_with_reply_cancelled_cb (GCancellable *cancellable,
                          send_message_with_reply_cancelled_idle_cb,
                          send_message_data_ref (data),
                          (GDestroyNotify) send_message_data_unref);
+  g_source_set_name (idle_source, "[gio] send_message_with_reply_cancelled_idle_cb");
   g_source_attach (idle_source, data->main_context);
   g_source_unref (idle_source);
 }
@@ -2050,8 +2538,9 @@ g_dbus_connection_send_message_with_reply_unlocked (GDBusConnection     *connect
  * fail with %G_IO_ERROR_CANCELLED. If @message is not well-formed,
  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
  *
- * This is an asynchronous method. When the operation is finished, @callback will be invoked
- * in the <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * This is an asynchronous method. When the operation is finished, @callback
+ * will be invoked in the 
+ * [thread-default main context][g-main-context-push-thread-default]
  * of the thread you are calling this method from. You can then call
  * g_dbus_connection_send_message_with_reply_finish() to get the result of the operation.
  * See g_dbus_connection_send_message_with_reply_sync() for the synchronous version.
@@ -2059,9 +2548,9 @@ g_dbus_connection_send_message_with_reply_unlocked (GDBusConnection     *connect
  * Note that @message must be unlocked, unless @flags contain the
  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
  *
- * See <xref linkend="gdbus-server"/> and <xref
- * linkend="gdbus-unix-fd-client"/> for an example of how to use this
- * low-level API to send and receive UNIX file descriptors.
+ * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
+ * for an example of how to use this low-level API to send and receive
+ * UNIX file descriptors.
  *
  * Since: 2.26
  */
@@ -2106,9 +2595,9 @@ g_dbus_connection_send_message_with_reply (GDBusConnection       *connection,
  * be of type %G_DBUS_MESSAGE_TYPE_ERROR. Use
  * g_dbus_message_to_gerror() to transcode this to a #GError.
  *
- * See <xref linkend="gdbus-server"/> and <xref
- * linkend="gdbus-unix-fd-client"/> for an example of how to use this
- * low-level API to send and receive UNIX file descriptors.
+ * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
+ * for an example of how to use this low-level API to send and receive
+ * UNIX file descriptors.
  *
  * Returns: (transfer full): a locked #GDBusMessage or %NULL if @error is set
  *
@@ -2192,9 +2681,9 @@ send_message_with_reply_sync_cb (GDBusConnection *connection,
  * be of type %G_DBUS_MESSAGE_TYPE_ERROR. Use
  * g_dbus_message_to_gerror() to transcode this to a #GError.
  *
- * See <xref linkend="gdbus-server"/> and <xref
- * linkend="gdbus-unix-fd-client"/> for an example of how to use this
- * low-level API to send and receive UNIX file descriptors.
+ * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
+ * for an example of how to use this low-level API to send and receive
+ * UNIX file descriptors.
  *
  * Note that @message must be unlocked, unless @flags contain the
  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
@@ -2269,8 +2758,7 @@ typedef struct
 
 /* Called in GDBusWorker's thread - we must not block - with no lock held */
 static void
-on_worker_message_received (GDBusWorker  *worker,
-                            GDBusMessage *message,
+on_worker_message_received (GDBusMessage *message,
                             gpointer      user_data)
 {
   GDBusConnection *connection;
@@ -2371,8 +2859,7 @@ on_worker_message_received (GDBusWorker  *worker,
 
 /* Called in GDBusWorker's thread, lock is not held */
 static GDBusMessage *
-on_worker_message_about_to_be_sent (GDBusWorker  *worker,
-                                    GDBusMessage *message,
+on_worker_message_about_to_be_sent (GDBusMessage *message,
                                     gpointer      user_data)
 {
   GDBusConnection *connection;
@@ -2448,10 +2935,9 @@ cancel_method_on_close (gpointer key, gpointer value, gpointer user_data)
 
 /* Called in GDBusWorker's thread - we must not block - without lock held */
 static void
-on_worker_closed (GDBusWorker *worker,
-                  gboolean     remote_peer_vanished,
-                  GError      *error,
-                  gpointer     user_data)
+on_worker_closed (gboolean  remote_peer_vanished,
+                  GError   *error,
+                  gpointer  user_data)
 {
   GDBusConnection *connection;
   gboolean alive;
@@ -2513,6 +2999,7 @@ initable_init (GInitable     *initable,
                GError       **error)
 {
   GDBusConnection *connection = G_DBUS_CONNECTION (initable);
+  gboolean initially_frozen;
   gboolean ret;
 
   /* This method needs to be idempotent to work with the singleton
@@ -2550,6 +3037,8 @@ initable_init (GInitable     *initable,
    */
   if (connection->address != NULL)
     {
+      GObject *ret;
+
       g_assert (connection->stream == NULL);
 
       if ((connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER) ||
@@ -2562,12 +3051,18 @@ initable_init (GInitable     *initable,
           goto out;
         }
 
-      connection->stream = g_dbus_address_get_stream_sync (connection->address,
-                                                           NULL, /* TODO: out_guid */
-                                                           cancellable,
-                                                           &connection->initialization_error);
-      if (connection->stream == NULL)
+      ret = g_dbus_address_get_stream_internal (connection->address, TRUE,
+                                                NULL, /* TODO: out_guid */
+                                                cancellable, &connection->initialization_error);
+      if (ret == NULL)
         goto out;
+
+      if (G_IS_IO_STREAM (ret))
+        connection->stream = G_IO_STREAM (ret);
+      else if (G_IS_KDBUS_WORKER (ret))
+        connection->kdbus_worker = G_KDBUS_WORKER (ret);
+      else
+        g_assert_not_reached ();
     }
   else if (connection->stream != NULL)
     {
@@ -2578,6 +3073,12 @@ initable_init (GInitable     *initable,
       g_assert_not_reached ();
     }
 
+  /* [KDBUS] Skip authentication process for kdbus transport */
+  if (connection->kdbus_worker)
+    {
+      goto authenticated;
+    }
+
   /* Authenticate the connection */
   if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER)
     {
@@ -2616,6 +3117,8 @@ initable_init (GInitable     *initable,
       connection->authentication_observer = NULL;
     }
 
+authenticated:
+
   //g_output_stream_flush (G_SOCKET_CONNECTION (connection->stream)
 
   //g_debug ("haz unix fd passing powers: %d", connection->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
@@ -2636,13 +3139,23 @@ initable_init (GInitable     *initable,
   g_hash_table_insert (alive_connections, connection, connection);
   G_UNLOCK (message_bus_lock);
 
-  connection->worker = _g_dbus_worker_new (connection->stream,
-                                           connection->capabilities,
-                                           ((connection->flags & G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING) != 0),
-                                           on_worker_message_received,
-                                           on_worker_message_about_to_be_sent,
-                                           on_worker_closed,
-                                           connection);
+  initially_frozen = (connection->flags & G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING) != 0;
+
+  if (connection->kdbus_worker)
+   g_kdbus_worker_associate (connection->kdbus_worker,
+                             connection->capabilities,
+                             on_worker_message_received,
+                             on_worker_message_about_to_be_sent,
+                             on_worker_closed,
+                             connection);
+  else
+    connection->worker = _g_dbus_worker_new (connection->stream,
+                                             connection->capabilities,
+                                             initially_frozen,
+                                             on_worker_message_received,
+                                             on_worker_message_about_to_be_sent,
+                                             on_worker_closed,
+                                             connection);
 
   /* if a bus connection, call org.freedesktop.DBus.Hello - this is how we're getting a name */
   if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
@@ -2659,17 +3172,25 @@ initable_init (GInitable     *initable,
           goto out;
         }
 
-      hello_result = g_dbus_connection_call_sync (connection,
-                                                  "org.freedesktop.DBus", /* name */
-                                                  "/org/freedesktop/DBus", /* path */
-                                                  "org.freedesktop.DBus", /* interface */
-                                                  "Hello",
-                                                  NULL, /* parameters */
-                                                  G_VARIANT_TYPE ("(s)"),
-                                                  CALL_FLAGS_INITIALIZING,
-                                                  -1,
-                                                  NULL, /* TODO: cancellable */
-                                                  &connection->initialization_error);
+      if (connection->kdbus_worker)
+        {
+          hello_result = _g_kdbus_Hello (connection->kdbus_worker, &connection->initialization_error);
+        }
+      else
+        {
+          hello_result = g_dbus_connection_call_sync (connection,
+                                                      "org.freedesktop.DBus", /* name */
+                                                      "/org/freedesktop/DBus", /* path */
+                                                      "org.freedesktop.DBus", /* interface */
+                                                      "Hello",
+                                                      NULL, /* parameters */
+                                                      G_VARIANT_TYPE ("(s)"),
+                                                      CALL_FLAGS_INITIALIZING,
+                                                      -1,
+                                                      NULL, /* TODO: cancellable */
+                                                      &connection->initialization_error);
+        }
+
       if (hello_result == NULL)
         goto out;
 
@@ -2678,6 +3199,9 @@ initable_init (GInitable     *initable,
       //g_debug ("unique name is '%s'", connection->bus_unique_name);
     }
 
+  if (connection->kdbus_worker && !initially_frozen)
+    g_kdbus_worker_unfreeze (connection->kdbus_worker);
+
   ret = TRUE;
  out:
   if (!ret)
@@ -3416,11 +3940,10 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
  * @user_data_free_func: (allow-none): function to free @user_data with when
  *     subscription is removed or %NULL
  *
- * Subscribes to signals on @connection and invokes @callback with a
- * whenever the signal is received. Note that @callback will be invoked
- * in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * loop</link> of the thread you are calling this method from.
+ * Subscribes to signals on @connection and invokes @callback with a whenever
+ * the signal is received. Note that @callback will be invoked in the 
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread you are calling this method from.
  *
  * If @connection is not a message bus connection, @sender must be
  * %NULL.
@@ -3535,7 +4058,20 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
   if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
     {
       if (!is_signal_data_for_name_lost_or_acquired (signal_data))
-        add_match_rule (connection, signal_data->rule);
+        if (connection->kdbus_worker)
+          _g_kdbus_AddMatch (connection->kdbus_worker, signal_data->rule, subscriber.id);
+        else
+          add_match_rule (connection, signal_data->rule);
+      else
+        {
+          if (connection->kdbus_worker)
+            {
+              if (g_strcmp0 (signal_data->member, "NameAcquired") == 0)
+                _g_kdbus_subscribe_name_acquired (connection->kdbus_worker, arg0);
+              else if (g_strcmp0 (signal_data->member, "NameLost") == 0)
+                _g_kdbus_subscribe_name_lost (connection->kdbus_worker, arg0);
+            }
+        }
     }
 
   signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
@@ -3620,7 +4156,20 @@ unsubscribe_id_internal (GDBusConnection *connection,
                * so on_worker_closed() can't happen between the check we just
                * did, and releasing the lock later.
                */
-              remove_match_rule (connection, signal_data->rule);
+              if (connection->kdbus_worker)
+                _g_kdbus_RemoveMatch (connection->kdbus_worker, subscription_id);
+              else
+                remove_match_rule (connection, signal_data->rule);
+            }
+          else
+            {
+              if (connection->kdbus_worker)
+                {
+                  if (g_strcmp0 (signal_data->member, "NameAcquired") == 0)
+                    _g_kdbus_unsubscribe_name_acquired (connection->kdbus_worker);
+                  else if (g_strcmp0 (signal_data->member, "NameLost") == 0)
+                    _g_kdbus_unsubscribe_name_lost (connection->kdbus_worker);
+                }
             }
 
           signal_data_free (signal_data);
@@ -3713,7 +4262,7 @@ emit_signal_instance_in_idle_cb (gpointer data)
     }
   else
     {
-      g_variant_ref_sink (parameters);
+      g_variant_ref (parameters);
     }
 
 #if 0
@@ -3890,6 +4439,7 @@ schedule_callbacks (GDBusConnection *connection,
                                  emit_signal_instance_in_idle_cb,
                                  signal_instance,
                                  (GDestroyNotify) signal_instance_free);
+          g_source_set_name (idle_source, "[gio] emit_signal_instance_in_idle_cb");
           g_source_attach (idle_source, subscriber->context);
           g_source_unref (idle_source);
         }
@@ -4380,6 +4930,10 @@ validate_and_maybe_schedule_property_getset (GDBusConnection            *connect
                          is_get ? invoke_get_property_in_idle_cb : invoke_set_property_in_idle_cb,
                          property_data,
                          (GDestroyNotify) property_data_free);
+  if (is_get)
+    g_source_set_name (idle_source, "[gio] invoke_get_property_in_idle_cb");
+  else
+    g_source_set_name (idle_source, "[gio] invoke_set_property_in_idle_cb");
   g_source_attach (idle_source, main_context);
   g_source_unref (idle_source);
 
@@ -4597,6 +5151,7 @@ validate_and_maybe_schedule_property_get_all (GDBusConnection            *connec
                          invoke_get_all_properties_in_idle_cb,
                          property_get_all_data,
                          (GDestroyNotify) property_get_all_data_free);
+  g_source_set_name (idle_source, "[gio] invoke_get_all_properties_in_idle_cb");
   g_source_attach (idle_source, main_context);
   g_source_unref (idle_source);
 
@@ -4913,6 +5468,7 @@ schedule_method_call (GDBusConnection            *connection,
                          call_in_idle_cb,
                          invocation,
                          g_object_unref);
+  g_source_set_name (idle_source, "[gio] call_in_idle_cb");
   g_source_attach (idle_source, main_context);
   g_source_unref (idle_source);
 }
@@ -5091,9 +5647,10 @@ obj_message_func (GDBusConnection *connection,
  * Registers callbacks for exported objects at @object_path with the
  * D-Bus interface that is described in @interface_info.
  *
- * Calls to functions in @vtable (and @user_data_free_func) will
- * happen in the <link linkend="g-main-context-push-thread-default">thread-default main
- * loop</link> of the thread you are calling this method from.
+ * Calls to functions in @vtable (and @user_data_free_func) will happen
+ * in the 
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread you are calling this method from.
  *
  * Note that all #GVariant values passed to functions in @vtable will match
  * the signature given in @interface_info - if a remote caller passes
@@ -5124,7 +5681,7 @@ obj_message_func (GDBusConnection *connection,
  * reference count is -1, see g_dbus_interface_info_ref()) for as long
  * as the object is exported. Also note that @vtable will be copied.
  *
- * See <xref linkend="gdbus-server"/> for an example of how to use this method.
+ * See this [server][gdbus-server] for an example of how to use this method.
  *
  * Returns: 0 if @error is set, otherwise a registration id (never 0)
  *     that can be used with g_dbus_connection_unregister_object()
@@ -5811,8 +6368,9 @@ g_dbus_connection_call_sync_internal (GDBusConnection         *connection,
  *                          NULL);
  * ]|
  *
- * This is an asynchronous method. When the operation is finished, @callback will be invoked
- * in the <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * This is an asynchronous method. When the operation is finished,
+ * @callback will be invoked in the
+ * [thread-default main context][g-main-context-push-thread-default]
  * of the thread you are calling this method from. You can then call
  * g_dbus_connection_call_finish() to get the result of the operation.
  * See g_dbus_connection_call_sync() for the synchronous version of this
@@ -6486,6 +7044,7 @@ subtree_message_func (GDBusConnection *connection,
                          process_subtree_vtable_message_in_idle_cb,
                          data,
                          (GDestroyNotify) subtree_deferred_data_free);
+  g_source_set_name (idle_source, "[gio] process_subtree_vtable_message_in_idle_cb");
   g_source_attach (idle_source, es->context);
   g_source_unref (idle_source);
 
@@ -6522,9 +7081,9 @@ subtree_message_func (GDBusConnection *connection,
  * #gpointer will be used to call into the interface vtable for processing
  * the request.
  *
- * All calls into user-provided code will be invoked in the <link
- * linkend="g-main-context-push-thread-default">thread-default main
- * loop</link> of the thread you are calling this method from.
+ * All calls into user-provided code will be invoked in the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * of the thread you are calling this method from.
  *
  * If an existing subtree is already registered at @object_path or
  * then @error is set to #G_IO_ERROR_EXISTS.
@@ -6539,7 +7098,8 @@ subtree_message_func (GDBusConnection *connection,
  * Note that @vtable will be copied so you cannot change it after
  * registration.
  *
- * See <xref linkend="gdbus-subtree-server"/> for an example of how to use this method.
+ * See this [server][gdbus-subtree-server] for an example of how to use
+ * this method.
  *
  * Returns: 0 if @error is set, otherwise a subtree registration id (never 0)
  * that can be used with g_dbus_connection_unregister_subtree() .
@@ -6883,6 +7443,14 @@ message_bus_get_singleton (GBusType   bus_type,
       ret = &the_system_bus;
       break;
 
+    case G_BUS_TYPE_USER:
+      ret = &the_user_bus;
+      break;
+
+    case G_BUS_TYPE_MACHINE:
+      ret = &the_machine_bus;
+      break;
+
     case G_BUS_TYPE_STARTER:
       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
       if (g_strcmp0 (starter_bus, "session") == 0)