[glib] GDBusProxy: Call into well-known name if no name owner currently exists



commit 5bb94348f4760352f6ae974002db48cb130343a4
Author: David Zeuthen <davidz redhat com>
Date:   Wed Aug 18 11:35:25 2010 -0400

    GDBusProxy: Call into well-known name if no name owner currently exists
    
    This is really what (API) users expect from GDBusProxy - in
    particular, mclasen and I ran into this problem while debugging a
    upower issue, see
    
     https://bugzilla.redhat.com/show_bug.cgi?id=624125
    
    In a nutshell, the problem is that polkitd crashes while upower holds
    a PolkitAuthority object (which in turns contains a GDBusProxy for the
    well-known name org.freedesktop.PolicyKit1). This means that
    subsequent calls on the PolkitAuthority (which is translated into
    calls into the GDBusProxy) fails since :g-name-owner is NULL.
    
    With this fix, we'll be requesting the bus daemon to launch polkitd
    since we will start calling into org.freedesktop.PolicyKit1 as soon as
    we notice that there is no owner for this name.
    
    Unfortunately our test suite doesn't cover service activation so there
    is no way to reliably test this. I will file a bug about this.
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 gio/gdbusproxy.c |  108 ++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 80 insertions(+), 28 deletions(-)
---
diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c
index d47a4ad..17e6730 100644
--- a/gio/gdbusproxy.c
+++ b/gio/gdbusproxy.c
@@ -61,9 +61,13 @@
  * name is tracked and can be read from
  * #GDBusProxy:g-name-owner. Connect to the #GObject::notify signal to
  * get notified of changes. Additionally, only signals and property
- * changes emitted from the current name owner are considered. This
- * avoids a number of race conditions when the name is lost by one
- * owner and claimed by another.
+ * changes emitted from the current name owner are considered and
+ * calls are always sent to the current name owner. This avoids a
+ * number of race conditions when the name is lost by one owner and
+ * claimed by another. However, if no name owner currently exists,
+ * then calls will be sent to the well-known name which may result in
+ * the message bus launching an owner (unless
+ * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is set).
  *
  * The generic #GDBusProxy::g-properties-changed and #GDBusProxy::g-signal
  * signals are not very convenient to work with. Therefore, the recommended
@@ -2179,6 +2183,31 @@ lookup_method_info_or_warn (GDBusProxy  *proxy,
   return info;
 }
 
+static const gchar *
+get_destination_for_call (GDBusProxy *proxy)
+{
+  const gchar *ret;
+
+  ret = NULL;
+
+  /* If proxy->priv->name is a unique name, then proxy->priv->name_owner
+   * is never NULL and always the same as proxy->priv->name. We use this
+   * knowledge to avoid checking if proxy->priv->name is a unique or
+   * well-known name.
+   */
+  ret = proxy->priv->name_owner;
+  if (ret != NULL)
+    goto out;
+
+  if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
+    goto out;
+
+  ret = proxy->priv->name;
+
+ out:
+  return ret;
+}
+
 /**
  * g_dbus_proxy_call:
  * @proxy: A #GDBusProxy.
@@ -2243,9 +2272,9 @@ g_dbus_proxy_call (GDBusProxy          *proxy,
   gboolean was_split;
   gchar *split_interface_name;
   const gchar *split_method_name;
-  const GDBusMethodInfo *expected_method_info;
   const gchar *target_method_name;
   const gchar *target_interface_name;
+  const gchar *destination;
   GVariantType *reply_type;
 
   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
@@ -2253,6 +2282,9 @@ g_dbus_proxy_call (GDBusProxy          *proxy,
   g_return_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
   g_return_if_fail (timeout_msec == -1 || timeout_msec >= 0);
 
+  reply_type = NULL;
+  split_interface_name = NULL;
+
   simple = g_simple_async_result_new (G_OBJECT (proxy),
                                       callback,
                                       user_data,
@@ -2265,17 +2297,30 @@ g_dbus_proxy_call (GDBusProxy          *proxy,
   g_object_set_data_full (G_OBJECT (simple), "-gdbus-proxy-method-name", g_strdup (target_method_name), g_free);
 
   /* Warn if method is unexpected (cf. :g-interface-info) */
-  expected_method_info = NULL;
   if (!was_split)
-    expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
+    {
+      const GDBusMethodInfo *expected_method_info;
+      expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
+      if (expected_method_info != NULL)
+        reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
+    }
 
-  if (expected_method_info)
-    reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
-  else
-    reply_type = NULL;
+  destination = NULL;
+  if (proxy->priv->name != NULL)
+    {
+      destination = get_destination_for_call (proxy);
+      if (destination == NULL)
+        {
+          g_simple_async_result_set_error (simple,
+                                           G_IO_ERROR,
+                                           G_IO_ERROR_FAILED,
+                                           _("Cannot invoke method; proxy is for a well-known name without an owner and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"));
+          goto out;
+        }
+    }
 
   g_dbus_connection_call (proxy->priv->connection,
-                          proxy->priv->name_owner,
+                          destination,
                           proxy->priv->object_path,
                           target_interface_name,
                           target_method_name,
@@ -2287,6 +2332,7 @@ g_dbus_proxy_call (GDBusProxy          *proxy,
                           (GAsyncReadyCallback) reply_cb,
                           simple);
 
+ out:
   if (reply_type != NULL)
     g_variant_type_free (reply_type);
 
@@ -2392,9 +2438,9 @@ g_dbus_proxy_call_sync (GDBusProxy      *proxy,
   gboolean was_split;
   gchar *split_interface_name;
   const gchar *split_method_name;
-  const GDBusMethodInfo *expected_method_info;
   const gchar *target_method_name;
   const gchar *target_interface_name;
+  const gchar *destination;
   GVariantType *reply_type;
 
   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
@@ -2403,32 +2449,37 @@ g_dbus_proxy_call_sync (GDBusProxy      *proxy,
   g_return_val_if_fail (timeout_msec == -1 || timeout_msec >= 0, NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
+  reply_type = NULL;
+
   was_split = maybe_split_method_name (method_name, &split_interface_name, &split_method_name);
   target_method_name = was_split ? split_method_name : method_name;
   target_interface_name = was_split ? split_interface_name : proxy->priv->interface_name;
 
-  if (proxy->priv->expected_interface)
+  /* Warn if method is unexpected (cf. :g-interface-info) */
+  if (!was_split)
     {
-      expected_method_info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, target_method_name);
-      if (expected_method_info == NULL)
-        {
-          g_warning ("Trying to invoke method `%s' which isn't in expected interface `%s'",
-                     target_method_name,
-                     target_interface_name);
-        }
+      const GDBusMethodInfo *expected_method_info;
+      expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
+      if (expected_method_info != NULL)
+        reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
     }
-  else
+
+  destination = NULL;
+  if (proxy->priv->name != NULL)
     {
-      expected_method_info = NULL;
+      destination = get_destination_for_call (proxy);
+      if (destination == NULL)
+        {
+          g_set_error_literal (error,
+                               G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               _("Cannot invoke method; proxy is for a well-known name without an owner and proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag"));
+          goto out;
+        }
     }
 
-  if (expected_method_info)
-    reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
-  else
-    reply_type = NULL;
-
   ret = g_dbus_connection_call_sync (proxy->priv->connection,
-                                     proxy->priv->name_owner,
+                                     destination,
                                      proxy->priv->object_path,
                                      target_interface_name,
                                      target_method_name,
@@ -2439,6 +2490,7 @@ g_dbus_proxy_call_sync (GDBusProxy      *proxy,
                                      cancellable,
                                      error);
 
+ out:
   if (reply_type != NULL)
     g_variant_type_free (reply_type);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]