[kdbus] Use new API insted of direct call to org.freedesktop.DBus
[platform/upstream/glib.git] / gio / gkdbus.c
index 10becde..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;
 }
@@ -610,7 +610,7 @@ g_kdbus_free_data (GKDBusWorker      *kdbus,
 
   ret = ioctl (kdbus->fd, KDBUS_CMD_FREE, &cmd);
   if (ret < 0)
-      return FALSE;
+    return FALSE;
 
   return TRUE;
 }
@@ -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);
 }
@@ -816,7 +841,7 @@ _g_kdbus_RequestName (GKDBusWorker        *worker,
         }
     }
 
-  if (cmd->flags & KDBUS_NAME_IN_QUEUE)
+  if (cmd->return_flags & KDBUS_NAME_IN_QUEUE)
     status = G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE;
 
   result = g_variant_new ("(u)", status);
@@ -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);
 
-  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_ADD;
+      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;
+      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;
+        }
+    }
 
-  *item = KDBUS_ITEM_NEXT(bloom_item);
-  return &bloom_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;
+
+      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;
+        }
+    }
 }
 
 
@@ -1842,9 +1964,153 @@ g_kdbus_setup_bloom (GKDBusWorker                     *worker,
 }
 
 
-/*
- * TODO: g_kdbus_NameOwnerChanged_generate, g_kdbus_KernelMethodError_generate
+/**
+ * g_kdbus_translate_id_change:
+ *
  */
+static void
+g_kdbus_translate_id_change (GKDBusWorker       *worker,
+                             struct kdbus_item  *item)
+{
+  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)
+{
+  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);
+    }
+}
+
+
+/**
+ *
+ *
+ */
+static void
+g_kdbus_translate_kernel_reply (GKDBusWorker       *worker,
+                                struct kdbus_msg   *msg,
+                                struct kdbus_item  *item)
+{
+  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);
+}
+
 
 /**
  * g_kdbus_decode_kernel_msg:
@@ -1862,39 +2128,27 @@ g_kdbus_decode_kernel_msg (GKDBusWorker           *worker,
         {
           case KDBUS_ITEM_ID_ADD:
           case KDBUS_ITEM_ID_REMOVE:
+            g_kdbus_translate_id_change (worker, item);
+            break;
+
           case KDBUS_ITEM_NAME_ADD:
           case KDBUS_ITEM_NAME_REMOVE:
           case KDBUS_ITEM_NAME_CHANGE:
-            //size = g_kdbus_NameOwnerChanged_generate (worker, item);
-            g_error ("'NameOwnerChanged'");
+            g_kdbus_translate_name_change (worker, item);
             break;
 
           case KDBUS_ITEM_REPLY_TIMEOUT:
           case KDBUS_ITEM_REPLY_DEAD:
-            //size = g_kdbus_KernelMethodError_generate (worker, item);
-            g_error ("'KernelMethodError'");
+            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);
-
-  return size;
-#endif
 }
 
 
@@ -1921,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));
@@ -2030,8 +2283,9 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
            should be implemented in the future */
         case KDBUS_ITEM_TIMESTAMP:
           {
-            g_print ("time: seq %llu mon %llu real %llu\n",
-                     item->timestamp.seqnum, item->timestamp.monotonic_ns, item->timestamp.realtime_ns);
+            /* g_print ("time: seq %llu mon %llu real %llu\n",
+                     item->timestamp.seqnum, item->timestamp.monotonic_ns, item->timestamp.realtime_ns); */
+
             //g_dbus_message_set_timestamp (message, item->timestamp.monotonic_ns / 1000);
             //g_dbus_message_set_serial (message, item->timestamp.seqnum);
             break;
@@ -2039,9 +2293,9 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
 
         case KDBUS_ITEM_CREDS:
           {
-            g_print ("creds: u%u eu %u su%u fsu%u g%u eg%u sg%u fsg%u\n",
+            /* g_print ("creds: u%llu eu %llu su%llu fsu%llu g%llu eg%llu sg%llu fsg%llu\n",
                      item->creds.uid, item->creds.euid, item->creds.suid, item->creds.fsuid,
-                     item->creds.gid, item->creds.egid, item->creds.sgid, item->creds.fsgid);
+                     item->creds.gid, item->creds.egid, item->creds.sgid, item->creds.fsgid); */
             break;
           }
 
@@ -2058,7 +2312,7 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
         case KDBUS_ITEM_AUXGROUPS:
         case KDBUS_ITEM_OWNED_NAME:
         case KDBUS_ITEM_NAME:
-          g_print ("unhandled %04x\n", (int) item->type);
+          //g_print ("unhandled %04x\n", (int) item->type);
           break;
 
         default:
@@ -2081,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]);
 
@@ -2096,7 +2345,16 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
   g_dbus_message_set_serial (message, serial);
   g_dbus_message_set_message_type (message, type);
 
-  g_print ("Received:\n%s\n", g_dbus_message_print (message, 2));
+  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);
 
@@ -2144,8 +2402,6 @@ again:
         return -1;
       }
 
-    g_print ("but sometimes that's okay\n");
-
    msg = (struct kdbus_msg *)((guint8 *)kdbus->kdbus_buffer + recv.msg.offset);
 
    if (msg->payload_type == KDBUS_PAYLOAD_DBUS)
@@ -2161,9 +2417,9 @@ again:
        return -1;
      }
 
-  ioctl(kdbus->fd, KDBUS_CMD_FREE, &recv.msg.offset);
+  g_kdbus_free_data (kdbus, recv.msg.offset);
 
-   return 0;
+  return 0;
 }
 
 static gboolean
@@ -2220,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"
 
@@ -2323,6 +2604,7 @@ _g_kdbus_send (GKDBusWorker        *kdbus,
   struct kdbus_msg *msg = alloca (KDBUS_MSG_MAX_SIZE);
   GVariantVectors body_vectors;
   struct kdbus_cmd_send send;
+  const gchar *dst_name;
 
   g_return_val_if_fail (G_IS_KDBUS_WORKER (kdbus), -1);
 
@@ -2335,8 +2617,6 @@ _g_kdbus_send (GKDBusWorker        *kdbus,
 
   /* Message destination */
   {
-    const gchar *dst_name;
-
     dst_name = g_dbus_message_get_destination (message);
 
     if (dst_name != NULL)
@@ -2526,16 +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;
@@ -2544,57 +2829,34 @@ _g_kdbus_send (GKDBusWorker        *kdbus,
   /*
    * send message
    */
-//again:
   if (ioctl(kdbus->fd, KDBUS_CMD_SEND, &send))
     {
-/*
-      GString *error_name;
-      error_name = g_string_new (NULL);
-
-      if(errno == EINTR)
+      if (errno == ENXIO || errno == ESRCH)
         {
-          g_string_free (error_name,TRUE);
-          goto again;
+          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
+                       "Destination '%s' not known", dst_name);
         }
-      else if (errno == ENXIO)
+      else if (errno == EADDRNOTAVAIL)
         {
-          g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg));
-          g_kdbus_generate_local_error (worker,
-                                        dbus_msg,
-                                        g_variant_new ("(s)",error_name->str),
-                                        G_DBUS_ERROR_SERVICE_UNKNOWN);
-          g_string_free (error_name,TRUE);
-          return 0;
+          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
+                       "No support for activation for name: %s", dst_name);
         }
-      else if ((errno == ESRCH) || (errno == EADDRNOTAVAIL))
+      else if (errno == EXFULL)
         {
-          if (kmsg->flags & KDBUS_MSG_FLAGS_NO_AUTO_START)
-            {
-              g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg));
-              g_kdbus_generate_local_error (worker,
-                                            dbus_msg,
-                                            g_variant_new ("(s)",error_name->str),
-                                            G_DBUS_ERROR_SERVICE_UNKNOWN);
-              g_string_free (error_name,TRUE);
-              return 0;
-            }
-          else
-            {
-              g_string_printf (error_name, "The name %s was not provided by any .service files", g_dbus_message_get_destination(dbus_msg));
-              g_kdbus_generate_local_error (worker,
-                                            dbus_msg,
-                                            g_variant_new ("(s)",error_name->str),
-                                            G_DBUS_ERROR_SERVICE_UNKNOWN);
-              g_string_free (error_name,TRUE);
-              return 0;
-            }
+          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));
         }
-
-      g_print ("[KDBUS] ioctl error sending kdbus message:%d (%m)\n",errno);
-      g_set_error (error, G_IO_ERROR, g_io_error_from_errno(errno), _("Error sending message - KDBUS_CMD_MSG_SEND error"));
-*/
-      perror("ioctl send");
-      g_error ("IOCTL SEND: %d\n",errno);
       return FALSE;
     }
 
@@ -2669,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