[kdbus] Use new API insted of direct call to org.freedesktop.DBus
[platform/upstream/glib.git] / gio / gkdbus.c
index 499c846..40b5085 100644 (file)
@@ -554,7 +554,6 @@ 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;
@@ -1537,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", (int) errno);
+    g_warning ("Error while adding a match: %d", (int) errno);
 
   match_free (match);
 }
@@ -1558,9 +1557,13 @@ _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", errno);
+    {
+      g_warning ("Error while removing a match: %d\n", errno);
+      return;
+    }
 }
 
 
@@ -1625,7 +1628,6 @@ _g_kdbus_subscribe_name_owner_changed_internal (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;
@@ -1634,12 +1636,15 @@ _g_kdbus_subscribe_name_owner_changed_internal (GKDBusWorker  *worker,
     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;
+    }
 }
 
 
@@ -1658,6 +1663,7 @@ _g_kdbus_subscribe_name_acquired (GKDBusWorker  *worker,
   gint ret;
 
   g_print ("Subscribe 'NameAcquired': name - %s ; cookie - %d\n", name, (int)cookie);
+
   if (name)
     len = strlen(name) + 1;
   else
@@ -1672,7 +1678,6 @@ _g_kdbus_subscribe_name_acquired (GKDBusWorker  *worker,
   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;
@@ -1681,12 +1686,15 @@ _g_kdbus_subscribe_name_acquired (GKDBusWorker  *worker,
     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_internal (worker, name, NULL, worker->unique_name, cookie);
 }
@@ -1707,6 +1715,7 @@ _g_kdbus_subscribe_name_lost (GKDBusWorker  *worker,
   gint ret;
 
   g_print ("Subscribe 'NameLost': name - %s ; cookie - %d\n", name, (int)cookie);
+
   if (name)
     len = strlen(name) + 1;
   else
@@ -1721,7 +1730,6 @@ _g_kdbus_subscribe_name_lost (GKDBusWorker  *worker,
   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;
@@ -1735,14 +1743,17 @@ _g_kdbus_subscribe_name_lost (GKDBusWorker  *worker,
 
   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_internal (worker, name, worker->unique_name, NULL, cookie);
 }
 
 
 /**
- *
+ * _g_kdbus_subscribe_name_owner_changed:
  *
  */
 void
@@ -1750,7 +1761,106 @@ _g_kdbus_subscribe_name_owner_changed (GKDBusWorker  *worker,
                                        const gchar   *name,
                                        guint64        cookie)
 {
-  g_print ("NameOwnerChanged subscription\n");
+  struct kdbus_item *item;
+  struct kdbus_cmd_match *cmd;
+  gssize size, len;
+  gint ret;
+
+  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);
+
+  /* '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));
+
+      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;
+
+      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;
+        }
+
+      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;
+        }
+    }
+
+  /* '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;
+        }
+    }
 }
 
 
@@ -1855,19 +1965,38 @@ 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
@@ -1898,8 +2027,6 @@ g_kdbus_translate_name_change (GKDBusWorker       *worker,
   if ((item->type == KDBUS_ITEM_NAME_REMOVE) ||
       (item->type == KDBUS_ITEM_NAME_CHANGE && ((guint64)item->name_change.old_id.id == worker->unique_id)))
     {
-      GDBusMessage *signal_message;
-
       signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
                                                   "org.freedesktop.DBus",
                                                   "NameLost");
@@ -1913,7 +2040,42 @@ g_kdbus_translate_name_change (GKDBusWorker       *worker,
     }
 
   /* NameOwnerChanged */
-  /* TODO */
+  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);
+    }
 }
 
 
@@ -1923,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);
 }
 
 
@@ -1956,7 +2139,7 @@ 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:
@@ -1992,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));
@@ -2163,12 +2345,13 @@ g_kdbus_decode_dbus_msg (GKDBusWorker           *worker,
   g_dbus_message_set_serial (message, serial);
   g_dbus_message_set_message_type (message, type);
 
-  //if (g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE) != NULL)
-  //  {
-      body = g_variant_get_variant (parts[1]);
-      g_dbus_message_set_body (message, body);
-      g_variant_unref (body);
-  //  }
+  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));
@@ -2298,15 +2481,20 @@ 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 = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
-                     G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
-                     size;
+  bloom_item->size = bloom_item_size;
   bloom_item->type = KDBUS_ITEM_BLOOM_FILTER;
 
   msg->size += bloom_item->size;
@@ -2622,13 +2810,15 @@ _g_kdbus_send (GKDBusWorker        *kdbus,
     msg->flags |= KDBUS_MSG_SIGNAL;
 
   /*
-   *
+   * 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_msg_append_bloom (msg, kdbus->bloom_size);
+      if (bloom_filter == NULL)
+        goto need_compact;
       g_kdbus_setup_bloom (kdbus, message, bloom_filter);
     }
 
@@ -2656,6 +2846,11 @@ _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);
@@ -2736,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