[kdbus] Use new API insted of direct call to org.freedesktop.DBus
[platform/upstream/glib.git] / gio / gkdbus.c
index 2a68d40..40b5085 100644 (file)
 #include "glibintl.h"
 #include "gunixfdmessage.h"
 
-#define KDBUS_TIMEOUT_NS 2000000000LU
-#define KDBUS_POOL_SIZE (16 * 1024LU * 1024LU)
-#define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
-#define KDBUS_ALIGN8_PTR(p) ((void*) (uintptr_t)(p))
+#define KDBUS_MSG_MAX_SIZE         8192
+#define KDBUS_TIMEOUT_NS           2000000000LU
+#define KDBUS_POOL_SIZE            (16 * 1024LU * 1024LU)
+#define KDBUS_ALIGN8(l)            (((l) + 7) & ~7)
+#define KDBUS_ALIGN8_PTR(p)        ((void*) (uintptr_t)(p))
 
 #define KDBUS_ITEM_HEADER_SIZE G_STRUCT_OFFSET(struct kdbus_item, data)
 #define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
@@ -86,7 +87,37 @@ struct dbus_fixed_header {
 #define DBUS_EXTENDED_HEADER_TYPE  ((const GVariantType *) "a{tv}")
 #define DBUS_MESSAGE_TYPE          ((const GVariantType *) "((yyyyut)a{tv}v)")
 
-#define KDBUS_MSG_MAX_SIZE         8192
+/*
+ * Macros for SipHash algorithm
+ */
+
+#define ROTL(x,b) (guint64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
+
+#define U32TO8_LE(p, v)         \
+    (p)[0] = (guint8)((v)      ); (p)[1] = (guint8)((v) >>  8); \
+    (p)[2] = (guint8)((v) >> 16); (p)[3] = (guint8)((v) >> 24);
+
+#define U64TO8_LE(p, v)         \
+  U32TO8_LE((p),     (guint32)((v)      ));   \
+  U32TO8_LE((p) + 4, (guint32)((v) >> 32));
+
+#define U8TO64_LE(p) \
+  (((guint64)((p)[0])      ) | \
+   ((guint64)((p)[1]) <<  8) | \
+   ((guint64)((p)[2]) << 16) | \
+   ((guint64)((p)[3]) << 24) | \
+   ((guint64)((p)[4]) << 32) | \
+   ((guint64)((p)[5]) << 40) | \
+   ((guint64)((p)[6]) << 48) | \
+   ((guint64)((p)[7]) << 56))
+
+#define SIPROUND            \
+  do {              \
+    v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
+    v2 += v3; v3=ROTL(v3,16); v3 ^= v2;     \
+    v0 += v3; v3=ROTL(v3,21); v3 ^= v0;     \
+    v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
+  } while(0)
 
 typedef enum
 {
@@ -181,6 +212,70 @@ typedef struct {
 
 
 /**
+ * SipHash algorithm
+ *
+ */
+static void
+_g_siphash24 (guint8         out[8],
+              const void    *_in,
+              gsize          inlen,
+              const guint8   k[16])
+{
+  /* "somepseudorandomlygeneratedbytes" */
+  guint64 v0 = 0x736f6d6570736575ULL;
+  guint64 v1 = 0x646f72616e646f6dULL;
+  guint64 v2 = 0x6c7967656e657261ULL;
+  guint64 v3 = 0x7465646279746573ULL;
+  guint64 b;
+  guint64 k0 = U8TO64_LE (k);
+  guint64 k1 = U8TO64_LE (k + 8);
+  guint64 m;
+  const guint8 *in = _in;
+  const guint8 *end = in + inlen - (inlen % sizeof(guint64));
+  const int left = inlen & 7;
+  b = ((guint64) inlen) << 56;
+  v3 ^= k1;
+  v2 ^= k0;
+  v1 ^= k1;
+  v0 ^= k0;
+
+  for (; in != end; in += 8)
+    {
+      m = U8TO64_LE (in);
+      v3 ^= m;
+      SIPROUND;
+      SIPROUND;
+      v0 ^= m;
+    }
+
+  switch (left)
+    {
+      case 7: b |= ((guint64) in[6]) << 48;
+      case 6: b |= ((guint64) in[5]) << 40;
+      case 5: b |= ((guint64) in[4]) << 32;
+      case 4: b |= ((guint64) in[3]) << 24;
+      case 3: b |= ((guint64) in[2]) << 16;
+      case 2: b |= ((guint64) in[1]) <<  8;
+      case 1: b |= ((guint64) in[0]); break;
+      case 0: break;
+    }
+
+  v3 ^= b;
+  SIPROUND;
+  SIPROUND;
+  v0 ^= b;
+
+  v2 ^= 0xff;
+  SIPROUND;
+  SIPROUND;
+  SIPROUND;
+  SIPROUND;
+  b = v0 ^ v1 ^ v2  ^ v3;
+  U64TO8_LE (out, b);
+}
+
+
+/**
  * is_key()
  *
  */
@@ -459,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;
 }
@@ -515,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;
 }
@@ -592,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;
@@ -650,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);
 }
@@ -721,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);
@@ -1061,7 +1181,7 @@ g_kdbus_GetConnInfo_internal (GKDBusWorker  *worker,
        memcpy (cmd->items[0].str, name, len);
     }
 
-  cmd->flags = _KDBUS_ATTACH_ALL;
+  cmd->attach_flags = _KDBUS_ATTACH_ALL;
   cmd->size = size;
 
   ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
@@ -1198,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;
@@ -1209,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;
             }
 
@@ -1289,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;
@@ -1338,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;
               }
@@ -1415,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);
 }
@@ -1427,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),
@@ -1435,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);
@@ -1469,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;
     }
@@ -1498,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;
+    }
 }
 
 
@@ -1519,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);
 }
 
 
@@ -1561,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;
+        }
+    }
 }
 
 
@@ -1747,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:
@@ -1767,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
 }
 
 
@@ -1826,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));
@@ -1935,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;
@@ -1944,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;
           }
 
@@ -1963,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:
@@ -1986,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]);
 
@@ -2001,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);
 
@@ -2049,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)
@@ -2066,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
@@ -2125,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"
 
@@ -2228,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);
 
@@ -2240,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)
@@ -2431,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;
@@ -2449,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;
     }
 
@@ -2574,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