[kdbus] Use new API insted of direct call to org.freedesktop.DBus
[platform/upstream/glib.git] / gio / gkdbus.c
index 21fe806..40b5085 100644 (file)
@@ -554,7 +554,7 @@ g_kdbus_worker_init (GKDBusWorker *kdbus)
 
   kdbus->kdbus_buffer = NULL;
 
-  kdbus->flags = 0; /* KDBUS_HELLO_ACCEPT_FD */
+  kdbus->flags = KDBUS_HELLO_ACCEPT_FD;
   kdbus->attach_flags_send = _KDBUS_ATTACH_ALL;
   kdbus->attach_flags_recv = _KDBUS_ATTACH_ALL;
 }
@@ -687,7 +687,8 @@ _g_kdbus_Hello (GKDBusWorker *worker,
                 GError    **error)
 {
   struct kdbus_cmd_hello *cmd;
-  struct kdbus_item *item;
+  struct kdbus_bloom_parameter *bloom;
+  struct kdbus_item *item, *items;
 
   gchar *conn_name;
   size_t size, conn_name_size;
@@ -745,8 +746,32 @@ _g_kdbus_Hello (GKDBusWorker *worker,
   asprintf(&worker->unique_name, ":1.%llu", (unsigned long long) cmd->id);
 
   /* read bloom filters parameters */
-  //worker->bloom_size = (gsize) cmd->bloom.size;
-  //worker->bloom_n_hash = (guint) cmd->bloom.n_hash;
+  bloom = NULL;
+  items = (void*)(worker->kdbus_buffer + cmd->offset);
+  KDBUS_FOREACH(item, items, cmd->items_size)
+    {
+      switch (item->type)
+        {
+          case KDBUS_ITEM_BLOOM_PARAMETER:
+            bloom = &item->bloom_parameter;
+          break;
+        }
+    }
+
+  if (bloom != NULL)
+    {
+      worker->bloom_size = (gsize) bloom->size;
+      worker->bloom_n_hash = (guint) bloom->n_hash;
+    }
+  else
+    {
+      g_set_error_literal (error,
+                           G_IO_ERROR,
+                           G_IO_ERROR_FAILED,
+                           _("Can't read bloom filter parameters"));
+      return NULL;
+    }
+
 
   return g_variant_new ("(s)", worker->unique_name);
 }
@@ -1293,6 +1318,7 @@ g_kdbus_bloom_add_data (GKDBusWorker  *worker,
   guint64 bit_num;
   guint bytes_num = 0;
   guint cnt_1, cnt_2;
+  guint hash_index = 0;
 
   guint c = 0;
   guint64 p = 0;
@@ -1304,11 +1330,11 @@ g_kdbus_bloom_add_data (GKDBusWorker  *worker,
 
   for (cnt_1 = 0; cnt_1 < (worker->bloom_n_hash); cnt_1++)
     {
-      for (cnt_2 = 0; cnt_2 < bytes_num; cnt_2++)
+      for (cnt_2 = 0, hash_index = 0; cnt_2 < bytes_num; cnt_2++)
         {
           if (c <= 0)
             {
-              _g_siphash24(hash, data, n, hash_keys[cnt_1++]);
+              _g_siphash24(hash, data, n, hash_keys[hash_index++]);
               c += 8;
             }
 
@@ -1384,7 +1410,7 @@ g_kdbus_bloom_add_prefixes (GKDBusWorker  *worker,
 void
 _g_kdbus_AddMatch (GKDBusWorker  *worker,
                    const gchar   *match_rule,
-                   guint          cookie)
+                   guint64        cookie)
 {
   Match *match;
   MatchElement *element;
@@ -1433,7 +1459,7 @@ _g_kdbus_AddMatch (GKDBusWorker  *worker,
               }
             else
               {
-                g_critical ("Error while adding a match: %d", cookie);
+                g_critical ("Error while adding a match");
                 match_free (match);
                 return;
               }
@@ -1510,7 +1536,7 @@ _g_kdbus_AddMatch (GKDBusWorker  *worker,
 
   ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
   if (ret < 0)
-    g_critical ("Error while adding a match: %d", cookie);
+    g_warning ("Error while adding a match: %d", (int) errno);
 
   match_free (match);
 }
@@ -1522,7 +1548,7 @@ _g_kdbus_AddMatch (GKDBusWorker  *worker,
  */
 void
 _g_kdbus_RemoveMatch (GKDBusWorker  *worker,
-                      guint          cookie)
+                      guint64        cookie)
 {
   struct kdbus_cmd_match cmd = {
     .size = sizeof(cmd),
@@ -1530,31 +1556,40 @@ _g_kdbus_RemoveMatch (GKDBusWorker  *worker,
   };
   gint ret;
 
+  g_print ("Unsubscribe match entry with cookie - %d\n", (int)cookie);
+
   ret = ioctl(worker->fd, KDBUS_CMD_MATCH_REMOVE, &cmd);
   if (ret < 0)
-    g_warning ("Error while removing a match: %d\n", (int) errno);
+    {
+      g_warning ("Error while removing a match: %d\n", errno);
+      return;
+    }
 }
 
 
 /**
- * _g_kdbus_subscribe_name_acquired:
+ * _g_kdbus_subscribe_name_owner_changed_internal:
  *
  */
 static void
-_g_kdbus_subscribe_name_owner_changed (GKDBusWorker  *worker,
-                                       const gchar      *name,
-                                       const gchar      *old_name,
-                                       const gchar      *new_name,
-                                       guint             cookie)
+_g_kdbus_subscribe_name_owner_changed_internal (GKDBusWorker  *worker,
+                                                const gchar   *name,
+                                                const gchar   *old_name,
+                                                const gchar   *new_name,
+                                                guint64        cookie)
 {
   struct kdbus_item *item;
   struct kdbus_cmd_match *cmd;
   gssize size, len;
   gint ret;
-  guint64 old_id = 0; /* XXX why? */
+  guint64 old_id = 0;
   guint64 new_id = KDBUS_MATCH_ID_ANY;
 
-  len = strlen(name) + 1;
+  if (name)
+    len = strlen(name) + 1;
+  else
+    len = 0;
+
   size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
                       G_STRUCT_OFFSET (struct kdbus_item, name_change) +
                       G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
@@ -1564,26 +1599,26 @@ _g_kdbus_subscribe_name_owner_changed (GKDBusWorker  *worker,
   cmd->cookie = cookie;
   item = cmd->items;
 
-  if (old_name[0] == 0)
+  if (old_name == NULL)
     {
       old_id = KDBUS_MATCH_ID_ANY;
     }
   else
     {
       if (g_dbus_is_unique_name(old_name))
-        old_id = old_id+3;
+        old_id = strtoull (old_name + 3, NULL, 10);
       else
         return;
     }
 
-  if (new_name[0] == 0)
+  if (new_name == NULL)
     {
       new_id = KDBUS_MATCH_ID_ANY;
     }
   else
     {
       if (g_dbus_is_unique_name(new_name))
-        new_id = new_id+3;
+        new_id = strtoull (new_name + 3, NULL, 10);
       else
         return;
     }
@@ -1593,18 +1628,23 @@ _g_kdbus_subscribe_name_owner_changed (GKDBusWorker  *worker,
   cmd->cookie = cookie;
   item = cmd->items;
 
-  /* KDBUS_ITEM_NAME_CHANGE */
   item->type = KDBUS_ITEM_NAME_CHANGE;
   item->name_change.old_id.id = old_id;
   item->name_change.new_id.id = new_id;
-  memcpy(item->name_change.name, name, len);
+
+  if (name)
+    memcpy(item->name_change.name, name, len);
+
   item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
-               G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
+               G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
   item = KDBUS_ITEM_NEXT(item);
 
   ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
   if (ret < 0)
-    g_warning ("ERROR - %d\n", (int) errno);
+    {
+      g_warning ("ERROR - %d\n", (int) errno);
+      return;
+    }
 }
 
 
@@ -1614,39 +1654,49 @@ _g_kdbus_subscribe_name_owner_changed (GKDBusWorker  *worker,
  */
 void
 _g_kdbus_subscribe_name_acquired (GKDBusWorker  *worker,
-                                  const gchar      *name)
+                                  const gchar   *name,
+                                  guint64        cookie)
 {
   struct kdbus_item *item;
   struct kdbus_cmd_match *cmd;
   gssize size, len;
-  guint64 cookie;
   gint ret;
 
-  len = strlen(name) + 1;
+  g_print ("Subscribe 'NameAcquired': name - %s ; cookie - %d\n", name, (int)cookie);
+
+  if (name)
+    len = strlen(name) + 1;
+  else
+    len = 0;
+
   size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
                       G_STRUCT_OFFSET (struct kdbus_item, name_change) +
                       G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
 
-  cookie = 0xbeefbeefbeefbeef;
   cmd = g_alloca0 (size);
   cmd->size = size;
   cmd->cookie = cookie;
   item = cmd->items;
 
-  /* KDBUS_ITEM_NAME_ADD */
   item->type = KDBUS_ITEM_NAME_ADD;
   item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
   item->name_change.new_id.id = worker->unique_id;
-  memcpy(item->name_change.name, name, len);
+
+  if (name)
+    memcpy(item->name_change.name, name, len);
+
   item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
-               G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
+               G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
   item = KDBUS_ITEM_NEXT(item);
 
   ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
   if (ret < 0)
-    g_warning ("ERROR - %d\n", (int) errno);
+    {
+      g_warning ("ERROR - %d\n", (int) errno);
+      return;
+    }
 
-  _g_kdbus_subscribe_name_owner_changed (worker, name, "", worker->unique_name, cookie);
+  _g_kdbus_subscribe_name_owner_changed_internal (worker, name, NULL, worker->unique_name, cookie);
 }
 
 
@@ -1656,89 +1706,161 @@ _g_kdbus_subscribe_name_acquired (GKDBusWorker  *worker,
  */
 void
 _g_kdbus_subscribe_name_lost (GKDBusWorker  *worker,
-                              const gchar      *name)
+                              const gchar   *name,
+                              guint64        cookie)
 {
   struct kdbus_item *item;
   struct kdbus_cmd_match *cmd;
   gssize size, len;
-  guint64 cookie;
   gint ret;
 
-  len = strlen(name) + 1;
+  g_print ("Subscribe 'NameLost': name - %s ; cookie - %d\n", name, (int)cookie);
+
+  if (name)
+    len = strlen(name) + 1;
+  else
+    len = 0;
+
   size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
                       G_STRUCT_OFFSET (struct kdbus_item, name_change) +
                       G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
 
-  cookie = 0xdeafdeafdeafdeaf;
   cmd = g_alloca0 (size);
   cmd->size = size;
   cmd->cookie = cookie;
   item = cmd->items;
 
-  /* KDBUS_ITEM_NAME_REMOVE */
   item->type = KDBUS_ITEM_NAME_REMOVE;
   item->name_change.old_id.id = worker->unique_id;
   item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
-  memcpy(item->name_change.name, name, len);
+
+  if (name)
+    memcpy(item->name_change.name, name, len);
+
   item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
                G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
   item = KDBUS_ITEM_NEXT(item);
 
   ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
   if (ret < 0)
-    g_warning ("ERROR - %d\n", (int) errno);
+    {
+      g_warning ("ERROR - %d\n", (int) errno);
+      return;
+    }
 
-  _g_kdbus_subscribe_name_owner_changed (worker, name, worker->unique_name, "", cookie);
+  _g_kdbus_subscribe_name_owner_changed_internal (worker, name, worker->unique_name, NULL, cookie);
 }
 
 
 /**
- * _g_kdbus_unsubscribe_name_acquired:
+ * _g_kdbus_subscribe_name_owner_changed:
  *
  */
 void
-_g_kdbus_unsubscribe_name_acquired (GKDBusWorker  *worker)
+_g_kdbus_subscribe_name_owner_changed (GKDBusWorker  *worker,
+                                       const gchar   *name,
+                                       guint64        cookie)
 {
-  guint64 cookie;
+  struct kdbus_item *item;
+  struct kdbus_cmd_match *cmd;
+  gssize size, len;
+  gint ret;
 
-  cookie = 0xbeefbeefbeefbeef;
-  _g_kdbus_RemoveMatch (worker, cookie);
-}
+  if (name != NULL)
+    if (!g_dbus_is_name (name))
+      {
+        g_warning ("ERROR\n");
+        return;
+      }
 
+  g_print ("Subscribe 'NameOwnerChanged': name - %s ; cookie - %d\n", name, (int)cookie);
 
-/**
- * _g_kdbus_unsubscribe_name_lost:
- *
- */
-void
-_g_kdbus_unsubscribe_name_lost (GKDBusWorker  *worker)
-{
-  guint64 cookie;
+  /* 'name' argument is missing or is a unique name */
+  if (name == NULL || g_dbus_is_unique_name (name))
+    {
+      size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+                          G_STRUCT_OFFSET (struct kdbus_item, id_change) +
+                          sizeof (struct kdbus_notify_id_change));
 
-  cookie = 0xdeafdeafdeafdeaf;
-  _g_kdbus_RemoveMatch (worker, cookie);
-}
+      cmd = g_alloca0 (size);
+      cmd->size = size;
+      cmd->cookie = cookie;
+      item = cmd->items;
 
+      if (name)
+        item->id_change.id = strtoull (name + 3, NULL, 10);
+      else
+        item->id_change.id = KDBUS_MATCH_ID_ANY;
 
-/**
- * g_kdbus_append_payload_bloom:
- *
- */
-static struct kdbus_bloom_filter *
-g_kdbus_append_bloom (struct kdbus_item **item,
-                      gsize               size)
-{
-  struct kdbus_item *bloom_item;
+      item->size = G_STRUCT_OFFSET (struct kdbus_item, id_change) +
+                   sizeof (struct kdbus_notify_id_change);
+
+      item->type = KDBUS_ITEM_ID_ADD;
+      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+      if (ret < 0)
+        {
+          g_warning ("ERROR - %d\n", (int) errno);
+          return;
+        }
 
-  bloom_item = KDBUS_ALIGN8_PTR(*item);
-  bloom_item->size = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
-                     G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
-                     size;
+      item->type = KDBUS_ITEM_ID_REMOVE;
+      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+      if (ret < 0)
+        {
+          g_warning ("ERROR - %d\n", (int) errno);
+          return;
+        }
+    }
 
-  bloom_item->type = KDBUS_ITEM_BLOOM_FILTER;
+  /* 'name' argument is missing or is a well-known name */
+  if (name == NULL || !g_dbus_is_unique_name (name))
+    {
+      if (name)
+        len = strlen(name) + 1;
+      else
+        len = 0;
 
-  *item = KDBUS_ITEM_NEXT(bloom_item);
-  return &bloom_item->bloom_filter;
+      size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+                          G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+                          G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
+
+      cmd = g_alloca0 (size);
+      cmd->size = size;
+      cmd->cookie = cookie;
+      item = cmd->items;
+
+      item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
+      item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
+      item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+                   G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
+
+      if (name)
+        memcpy(item->name_change.name, name, len);
+
+      item->type = KDBUS_ITEM_NAME_ADD;
+      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+      if (ret < 0)
+        {
+          g_warning ("ERROR - %d\n", (int) errno);
+          return;
+        }
+
+      item->type = KDBUS_ITEM_NAME_REMOVE;
+      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+      if (ret < 0)
+        {
+          g_warning ("ERROR - %d\n", (int) errno);
+          return;
+        }
+
+      item->type = KDBUS_ITEM_NAME_CHANGE;
+      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+      if (ret < 0)
+        {
+          g_warning ("ERROR - %d\n", (int) errno);
+          return;
+        }
+    }
 }
 
 
@@ -1843,26 +1965,117 @@ g_kdbus_setup_bloom (GKDBusWorker                     *worker,
 
 
 /**
- *
+ * g_kdbus_translate_id_change:
  *
  */
 static void
 g_kdbus_translate_id_change (GKDBusWorker       *worker,
                              struct kdbus_item  *item)
 {
-  g_error ("TODO: translate_id_change\n");
+  GDBusMessage *signal_message;
+  gchar *name;
+
+  signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+                                              "org.freedesktop.DBus",
+                                              "NameOwnerChanged");
+
+  name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->id_change.id);
+
+  g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+  g_dbus_message_set_body (signal_message,
+                           g_variant_new ("(sss)",
+                                          name,
+                                          item->type == KDBUS_ITEM_ID_ADD ? "" : name,
+                                          item->type == KDBUS_ITEM_ID_ADD ? name : ""));
+
+  (* worker->message_received_callback) (signal_message, worker->user_data);
+
+  g_free (name);
+  g_object_unref (signal_message);
 }
 
 
 /**
- *
+ * g_kdbus_translate_name_change:
  *
  */
 static void
 g_kdbus_translate_name_change (GKDBusWorker       *worker,
                                struct kdbus_item  *item)
 {
-  g_error ("TODO: translate_name_change\n");
+  GDBusMessage *signal_message;
+
+  signal_message = NULL;
+
+  /* NameAcquired */
+  if ((item->type == KDBUS_ITEM_NAME_ADD) ||
+      (item->type == KDBUS_ITEM_NAME_CHANGE && ((guint64)item->name_change.new_id.id == worker->unique_id)))
+    {
+      signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+                                                  "org.freedesktop.DBus",
+                                                  "NameAcquired");
+
+      g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+      g_dbus_message_set_body (signal_message,
+                               g_variant_new ("(s)", item->name_change.name));
+
+      (* worker->message_received_callback) (signal_message, worker->user_data);
+      g_object_unref (signal_message);
+    }
+
+  /* NameLost */
+  if ((item->type == KDBUS_ITEM_NAME_REMOVE) ||
+      (item->type == KDBUS_ITEM_NAME_CHANGE && ((guint64)item->name_change.old_id.id == worker->unique_id)))
+    {
+      signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+                                                  "org.freedesktop.DBus",
+                                                  "NameLost");
+
+      g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+      g_dbus_message_set_body (signal_message,
+                               g_variant_new ("(s)", item->name_change.name));
+
+      (* worker->message_received_callback) (signal_message, worker->user_data);
+      g_object_unref (signal_message);
+    }
+
+  /* NameOwnerChanged */
+  if (1)
+    {
+      gchar *old_name;
+      gchar *new_name;
+
+      old_name = NULL;
+      new_name = NULL;
+
+      /* old_name */
+      if (!(item->type == KDBUS_ITEM_NAME_ADD || (item->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))))
+        old_name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->name_change.old_id.id);
+
+      /* new_name */
+      if (!(item->type == KDBUS_ITEM_NAME_REMOVE || (item->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))))
+        new_name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->name_change.new_id.id);
+      else
+        if (old_name == NULL)
+          return;
+
+      /* send signal */
+      signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+                                                  "org.freedesktop.DBus",
+                                                  "NameOwnerChanged");
+      g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+      g_dbus_message_set_body (signal_message,
+                               g_variant_new ("(sss)",
+                                              item->name_change.name,
+                                              old_name ? old_name : "",
+                                              new_name ? new_name : ""));
+
+      (* worker->message_received_callback) (signal_message, worker->user_data);
+
+      g_free (old_name);
+      g_free (new_name);
+      g_object_unref (signal_message);
+    }
 }
 
 
@@ -1872,9 +2085,30 @@ g_kdbus_translate_name_change (GKDBusWorker       *worker,
  */
 static void
 g_kdbus_translate_kernel_reply (GKDBusWorker       *worker,
+                                struct kdbus_msg   *msg,
                                 struct kdbus_item  *item)
 {
-  g_error ("TODO: translate_kernel_reply\n");
+  GDBusMessage *message;
+
+  message = g_dbus_message_new ();
+
+  g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_ERROR);
+  g_dbus_message_set_flags (message, G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED);
+  g_dbus_message_set_reply_serial (message, (guint32) msg->cookie_reply);
+
+  g_dbus_message_set_sender (message, "org.freedesktop.DBus");
+  g_dbus_message_set_destination (message, worker->unique_name);
+
+  g_dbus_message_set_error_name (message, "org.freedesktop.DBus.Error.NoReply");
+
+  if (item->type == KDBUS_ITEM_REPLY_TIMEOUT)
+    g_dbus_message_set_body (message, g_variant_new ("(s)", "Method call timed out"));
+  else
+    g_dbus_message_set_body (message, g_variant_new ("(s)", "Method call peer died"));
+
+  (* worker->message_received_callback) (message, worker->user_data);
+
+  g_object_unref (message);
 }
 
 
@@ -1905,27 +2139,16 @@ g_kdbus_decode_kernel_msg (GKDBusWorker           *worker,
 
           case KDBUS_ITEM_REPLY_TIMEOUT:
           case KDBUS_ITEM_REPLY_DEAD:
-            g_kdbus_translate_kernel_reply (worker, item);
+            g_kdbus_translate_kernel_reply (worker, msg, item);
+            break;
+
+          case KDBUS_ITEM_TIMESTAMP:
             break;
 
           default:
             g_warning ("Unknown field in kernel message - %lld", item->type);
        }
     }
-
-#if 0
-  /* Override information from the user header with data from the kernel */
-  g_string_printf (worker->msg_sender, "org.freedesktop.DBus");
-
-  /* for destination */
-  if (worker->kmsg->dst_id == KDBUS_DST_ID_BROADCAST)
-    /* for broadcast messages we don't have to set destination */
-    ;
-  else if (worker->kmsg->dst_id == KDBUS_DST_ID_NAME)
-    g_string_printf (worker->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) worker->unique_id);
-  else
-   g_string_printf (worker->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) worker->kmsg->dst_id);
-#endif
 }
 
 
@@ -1952,7 +2175,6 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
   GVariant *value;
   guint64 serial;
 
-
   message = g_dbus_message_new ();
 
   body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
@@ -2113,11 +2335,6 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
   parts[1] = g_variant_get_child_value (body, 1);
   g_variant_unref (body);
 
-  body = g_variant_get_variant (parts[1]);
-  g_variant_unref (parts[1]);
-  g_dbus_message_set_body (message, body);
-  g_variant_unref (body);
-
   g_variant_get (parts[0], "(yyyyuta{tv})", &endianness, &type, &flags, &version, NULL, &serial, &fields_iter);
   g_variant_unref (parts[0]);
 
@@ -2128,6 +2345,15 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
   g_dbus_message_set_serial (message, serial);
   g_dbus_message_set_message_type (message, type);
 
+  body = g_variant_get_variant (parts[1]);
+  if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
+    g_dbus_message_set_body (message, body);
+  else
+    g_dbus_message_set_body (message, NULL);
+
+  g_variant_unref (body);
+  g_variant_unref (parts[1]);
+
   //g_print ("Received:\n%s\n", g_dbus_message_print (message, 2));
 
   (* worker->message_received_callback) (message, worker->user_data);
@@ -2250,6 +2476,31 @@ g_kdbus_msg_append_payload_memfd (struct kdbus_msg *msg,
   return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_MEMFD, &mfd, sizeof mfd);
 }
 
+static struct kdbus_bloom_filter *
+g_kdbus_msg_append_bloom (struct kdbus_msg *msg,
+                          gsize             size)
+{
+  struct kdbus_item *bloom_item;
+  gsize bloom_item_size;
+
+  bloom_item_size = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
+                    G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
+                    size;
+  if (msg->size + bloom_item_size > KDBUS_MSG_MAX_SIZE)
+    return NULL;
+
+  /* align */
+  msg->size += (-msg->size) & 7;
+  bloom_item = (struct kdbus_item *) ((guchar *) msg + msg->size);
+
+  /* set size and type */
+  bloom_item->size = bloom_item_size;
+  bloom_item->type = KDBUS_ITEM_BLOOM_FILTER;
+
+  msg->size += bloom_item->size;
+  return &bloom_item->bloom_filter;
+}
+
 #if 0
 #include "dbusheader.h"
 
@@ -2555,15 +2806,21 @@ _g_kdbus_send (GKDBusWorker        *kdbus,
   else
     msg->cookie_reply = g_dbus_message_get_reply_serial(message);
 
+  if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL)
+    msg->flags |= KDBUS_MSG_SIGNAL;
+
   /*
-  if (dst_id == KDBUS_DST_ID_BROADCAST)
+   * append bloom filter item for broadcast signals
+   */
+  if (msg->dst_id == KDBUS_DST_ID_BROADCAST)
     {
       struct kdbus_bloom_filter *bloom_filter;
 
-      bloom_filter = g_kdbus_append_bloom (&item, kdbus->bloom_size);
+      bloom_filter = g_kdbus_msg_append_bloom (msg, kdbus->bloom_size);
+      if (bloom_filter == NULL)
+        goto need_compact;
       g_kdbus_setup_bloom (kdbus, message, bloom_filter);
     }
-    */
 
   send.size = sizeof (send);
   send.flags = 0;
@@ -2589,8 +2846,14 @@ _g_kdbus_send (GKDBusWorker        *kdbus,
           g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
                        "The memory pool of the receiver is full");
         }
+      else if (errno == ENOBUFS)
+        {
+          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
+                       "Too many pending messages on the receiver side");
+        }
       else
         {
+          g_error ("WTF? %d\n", errno);
           g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
                        "%s", strerror(errno));
         }
@@ -2668,14 +2931,17 @@ g_kdbus_worker_send_message (GKDBusWorker  *worker,
   return _g_kdbus_send (worker, message, error);
 }
 
+/* TODO */
 void
-g_kdbus_worker_stop (GKDBusWorker *worker)
+g_kdbus_worker_flush_sync (GKDBusWorker *worker)
 {
+  g_warning ("TODO: Implement sync flush");
 }
 
 void
-g_kdbus_worker_flush_sync (GKDBusWorker *worker)
+g_kdbus_worker_stop (GKDBusWorker *worker)
 {
+  g_warning ("TODO: Implement worker stop");
 }
 
 void