GDBusConnection.call(): add 'reply_type' argument
authorRyan Lortie <desrt@desrt.ca>
Mon, 24 May 2010 20:46:24 +0000 (16:46 -0400)
committerRyan Lortie <desrt@desrt.ca>
Mon, 24 May 2010 21:00:04 +0000 (17:00 -0400)
This allows the caller to specify the reply type that they are expecting
for this call.  If the reply comes back with the wrong type, GDBus will
generate an appropriate error internally.

  - add a GVariantType * argument to g_dbus_connection_call() and
    _call_sync().

  - move the internal API for computing message types from introspection
    data to be based on GVariantType instead of strings.  Update users
    of this code.

  - have GDBusProxy pass this calculated GVariantType into
    g_dbus_connection_call().  Remove the checks done in GDBusProxy.

  - Update other users of the code (test cases, gdbus-tool, GSettings
    tool, etc).  In some cases, remove redundant checks; in some other
    cases, we are fixing bugs because no checking was done where it
    should have been.

Closes bug #619391.

15 files changed:
gio/gdbus-tool.c
gio/gdbusconnection.c
gio/gdbusconnection.h
gio/gdbusmethodinvocation.c
gio/gdbusnameowning.c
gio/gdbusnamewatching.c
gio/gdbusprivate.c
gio/gdbusprivate.h
gio/gdbusproxy.c
gio/gsettings-tool.c
gio/tests/gdbus-connection.c
gio/tests/gdbus-example-peer.c
gio/tests/gdbus-export.c
gio/tests/gdbus-names.c
gio/tests/gdbus-threading.c

index 4826b35d646ff4f28791d8b2b9129b2e711f1451..11ffb6cd2895c4d6ff1c07f025095921ab7f16d1 100644 (file)
@@ -150,6 +150,7 @@ print_methods (GDBusConnection *c,
                                         "org.freedesktop.DBus.Introspectable",
                                         "Introspect",
                                         NULL,
+                                        G_VARIANT_TYPE ("(s)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         3000, /* 3 secs */
                                         NULL,
@@ -160,13 +161,6 @@ print_methods (GDBusConnection *c,
       g_error_free (error);
       goto out;
     }
-  if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
-    {
-      g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
-                  g_variant_get_type_string (result));
-      g_variant_unref (result);
-      goto out;
-    }
   g_variant_get (result, "(&s)", &xml_data);
 
   error = NULL;
@@ -212,6 +206,7 @@ print_paths (GDBusConnection *c,
                                         "org.freedesktop.DBus.Introspectable",
                                         "Introspect",
                                         NULL,
+                                        G_VARIANT_TYPE ("(s)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         3000, /* 3 secs */
                                         NULL,
@@ -222,13 +217,6 @@ print_paths (GDBusConnection *c,
       g_error_free (error);
       goto out;
     }
-  if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
-    {
-      g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
-                  g_variant_get_type_string (result));
-      g_variant_unref (result);
-      goto out;
-    }
   g_variant_get (result, "(&s)", &xml_data);
 
   //g_printerr ("xml=`%s'", xml_data);
@@ -290,6 +278,7 @@ print_names (GDBusConnection *c,
                                         "org.freedesktop.DBus",
                                         "ListNames",
                                         NULL,
+                                        G_VARIANT_TYPE ("(as)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         3000, /* 3 secs */
                                         NULL,
@@ -300,12 +289,6 @@ print_names (GDBusConnection *c,
       g_error_free (error);
       goto out;
     }
-  if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)")))
-    {
-      g_printerr (_("Error: Result is type `%s', expected `(as)'\n"), g_variant_get_type_string (result));
-      g_variant_unref (result);
-      goto out;
-    }
   g_variant_get (result, "(as)", &iter);
   while (g_variant_iter_loop (iter, "s", &str))
     g_hash_table_insert (name_set, g_strdup (str), NULL);
@@ -319,6 +302,7 @@ print_names (GDBusConnection *c,
                                         "org.freedesktop.DBus",
                                         "ListActivatableNames",
                                         NULL,
+                                        G_VARIANT_TYPE ("(as)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         3000, /* 3 secs */
                                         NULL,
@@ -329,12 +313,6 @@ print_names (GDBusConnection *c,
       g_error_free (error);
       goto out;
     }
-  if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)")))
-    {
-      g_printerr (_("Error: Result is type `%s', expected `(as)'\n"), g_variant_get_type_string (result));
-      g_variant_unref (result);
-      goto out;
-    }
   g_variant_get (result, "(as)", &iter);
   while (g_variant_iter_loop (iter, "s", &str))
     g_hash_table_insert (name_set, g_strdup (str), NULL);
@@ -461,6 +439,7 @@ call_helper_get_method_in_signature (GDBusConnection  *c,
                                         "org.freedesktop.DBus.Introspectable",
                                         "Introspect",
                                         NULL,
+                                        G_VARIANT_TYPE ("(s)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         3000, /* 3 secs */
                                         NULL,
@@ -468,14 +447,6 @@ call_helper_get_method_in_signature (GDBusConnection  *c,
   if (result == NULL)
     goto out;
 
-  if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   _("Error: Result is type `%s', expected `(s)'\n"),
-                   g_variant_get_type_string (result));
-      goto out;
-    }
-
   g_variant_get (result, "(&s)", &xml_data);
   node_info = g_dbus_node_info_new_for_xml (xml_data, error);
   if (node_info == NULL)
@@ -833,6 +804,7 @@ handle_call (gint        *argc,
                                         interface_name,
                                         method_name,
                                         parameters,
+                                        NULL,
                                         G_DBUS_CALL_FLAGS_NONE,
                                         -1,
                                         NULL,
@@ -1056,6 +1028,7 @@ dump_interface (GDBusConnection          *c,
                                             "org.freedesktop.DBus.Properties",
                                             "GetAll",
                                             g_variant_new ("(s)", o->name),
+                                            NULL,
                                             G_DBUS_CALL_FLAGS_NONE,
                                             3000,
                                             NULL,
@@ -1094,6 +1067,7 @@ dump_interface (GDBusConnection          *c,
                                                     "org.freedesktop.DBus.Properties",
                                                     "Get",
                                                     g_variant_new ("(ss)", o->name, o->properties[n]->name),
+                                                    G_VARIANT_TYPE ("(v)"),
                                                     G_DBUS_CALL_FLAGS_NONE,
                                                     3000,
                                                     NULL,
@@ -1338,6 +1312,7 @@ handle_introspect (gint        *argc,
                                         "org.freedesktop.DBus.Introspectable",
                                         "Introspect",
                                         NULL,
+                                        G_VARIANT_TYPE ("(s)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         3000, /* 3 sec */
                                         NULL,
@@ -1348,12 +1323,6 @@ handle_introspect (gint        *argc,
       g_error_free (error);
       goto out;
     }
-  if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(s)")))
-    {
-      g_printerr (_("Error: Result is type `%s', expected `(s)'\n"),
-                  g_variant_get_type_string (result));
-      goto out;
-    }
   g_variant_get (result, "(&s)", &xml_data);
 
   error = NULL;
index 346afcfb0a91bcc4a7072797531809e542c6ea7b..b79e0010d520efc5403da28b67d29ee09a611ff6 100644 (file)
@@ -1845,6 +1845,7 @@ initable_init (GInitable     *initable,
                                                   "org.freedesktop.DBus", /* interface */
                                                   "Hello",
                                                   NULL, /* parameters */
+                                                  G_VARIANT_TYPE ("(s)"),
                                                   G_DBUS_CALL_FLAGS_NONE,
                                                   -1,
                                                   NULL, /* TODO: cancellable */
@@ -3730,7 +3731,7 @@ validate_and_maybe_schedule_method_call (GDBusConnection            *connection,
   GVariant *parameters;
   GSource *idle_source;
   gboolean handled;
-  gchar *in_signature;
+  GVariantType *in_type;
 
   handled = FALSE;
 
@@ -3752,37 +3753,41 @@ validate_and_maybe_schedule_method_call (GDBusConnection            *connection,
       goto out;
     }
 
+  parameters = g_dbus_message_get_body (message);
+  if (parameters == NULL)
+    {
+      parameters = g_variant_new ("()");
+      g_variant_ref_sink (parameters);
+    }
+  else
+    {
+      g_variant_ref (parameters);
+    }
+
   /* Check that the incoming args are of the right type - if they are not, return
    * the org.freedesktop.DBus.Error.InvalidArgs error to the caller
-   *
-   * TODO: might also be worth caching the combined signature.
    */
-  in_signature = _g_dbus_compute_complete_signature (method_info->in_args, FALSE);
-  if (g_strcmp0 (g_dbus_message_get_signature (message), in_signature) != 0)
+  in_type = _g_dbus_compute_complete_signature (method_info->in_args);
+  if (!g_variant_is_of_type (parameters, in_type))
     {
+      gchar *type_string;
+
+      type_string = g_variant_type_dup_string (in_type);
+
       reply = g_dbus_message_new_method_error (message,
                                                "org.freedesktop.DBus.Error.InvalidArgs",
-                                               _("Signature of message, `%s', does not match expected signature `%s'"),
-                                               g_dbus_message_get_signature (message),
-                                               in_signature);
+                                               _("Type of message, `%s', does not match expected type `%s'"),
+                                               g_variant_get_type_string (parameters),
+                                               type_string);
       g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
+      g_variant_type_free (in_type);
+      g_variant_unref (parameters);
       g_object_unref (reply);
-      g_free (in_signature);
+      g_free (type_string);
       handled = TRUE;
       goto out;
     }
-  g_free (in_signature);
-
-  parameters = g_dbus_message_get_body (message);
-  if (parameters == NULL)
-    {
-      parameters = g_variant_new ("()");
-      g_variant_ref_sink (parameters);
-    }
-  else
-    {
-      g_variant_ref (parameters);
-    }
+  g_variant_type_free (in_type);
 
   /* schedule the call in idle */
   invocation = g_dbus_method_invocation_new (g_dbus_message_get_sender (message),
@@ -4131,6 +4136,105 @@ add_call_flags (GDBusMessage           *message,
     g_dbus_message_set_flags (message, G_DBUS_MESSAGE_FLAGS_NO_AUTO_START);
 }
 
+static GVariant *
+decode_method_reply (GDBusMessage        *reply,
+                     const gchar         *method_name,
+                     const GVariantType  *reply_type,
+                     GError             **error)
+{
+  GVariant *result;
+
+  result = NULL;
+  switch (g_dbus_message_get_message_type (reply))
+    {
+    case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
+      result = g_dbus_message_get_body (reply);
+      if (result == NULL)
+        {
+          result = g_variant_new ("()");
+          g_variant_ref_sink (result);
+        }
+      else
+        {
+          g_variant_ref (result);
+        }
+
+      if (!g_variant_is_of_type (result, reply_type))
+        {
+          gchar *type_string = g_variant_type_dup_string (reply_type);
+
+          g_set_error (error,
+                       G_IO_ERROR,
+                       G_IO_ERROR_INVALID_ARGUMENT,
+                       _("Method `%s' returned type `%s', but expected `%s'"),
+                       method_name, g_variant_get_type_string (result), type_string);
+
+          g_variant_unref (result);
+          g_free (type_string);
+          result = NULL;
+        }
+      break;
+
+    case G_DBUS_MESSAGE_TYPE_ERROR:
+      g_dbus_message_to_gerror (reply, error);
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  return result;
+}
+
+
+typedef struct
+{
+  GSimpleAsyncResult *simple;
+  GVariantType *reply_type;
+  gchar *method_name; /* for error message */
+} CallState;
+
+static void
+g_dbus_connection_call_done (GObject      *source,
+                             GAsyncResult *result,
+                             gpointer      user_data)
+{
+  GDBusConnection *connection = G_DBUS_CONNECTION (source);
+  CallState *state = user_data;
+  GError *error = NULL;
+  GDBusMessage *reply;
+  GVariant *value;
+
+  reply = g_dbus_connection_send_message_with_reply_finish (connection,
+                                                            result, &error);
+
+  if (reply != NULL)
+    {
+      value = decode_method_reply (reply, state->method_name,
+                                   state->reply_type, &error);
+      g_object_unref (reply);
+    }
+  else
+    value = NULL;
+
+  if (value == NULL)
+    {
+      g_simple_async_result_set_from_error (state->simple, error);
+      g_error_free (error);
+    }
+  else
+    g_simple_async_result_set_op_res_gpointer (state->simple, value,
+                                               (GDestroyNotify) g_variant_unref);
+
+  g_simple_async_result_complete (state->simple);
+  g_variant_type_free (state->reply_type);
+  g_object_unref (state->simple);
+  g_free (state->method_name);
+
+  g_slice_free (CallState, state);
+}
+
 /**
  * g_dbus_connection_call:
  * @connection: A #GDBusConnection.
@@ -4139,6 +4243,7 @@ add_call_flags (GDBusMessage           *message,
  * @interface_name: D-Bus interface to invoke method on.
  * @method_name: The name of the method to invoke.
  * @parameters: A #GVariant tuple with parameters for the method or %NULL if not passing parameters.
+ * @reply_type: The expected type of the reply, or %NULL.
  * @flags: Flags from the #GDBusCallFlags enumeration.
  * @timeout_msec: The timeout in milliseconds or -1 to use the default timeout.
  * @cancellable: A #GCancellable or %NULL.
@@ -4156,6 +4261,10 @@ add_call_flags (GDBusMessage           *message,
  * not compatible with the D-Bus protocol, the operation fails with
  * %G_IO_ERROR_INVALID_ARGUMENT.
  *
+ * If @reply_type is non-%NULL then the reply will be checked for having this type and an
+ * error will be raised if it does not match.  Said another way, if you give a @reply_type
+ * then any non-%NULL return value will be of this type.
+ *
  * If the @parameters #GVariant is floating, it is consumed. This allows
  * convenient 'inline' use of g_variant_new(), e.g.:
  * |[
@@ -4167,6 +4276,7 @@ add_call_flags (GDBusMessage           *message,
  *                          g_variant_new ("(ss)",
  *                                         "Thing One",
  *                                         "Thing Two"),
+ *                          NULL,
  *                          G_DBUS_CALL_FLAGS_NONE,
  *                          -1,
  *                          NULL,
@@ -4190,6 +4300,7 @@ g_dbus_connection_call (GDBusConnection        *connection,
                         const gchar            *interface_name,
                         const gchar            *method_name,
                         GVariant               *parameters,
+                        const GVariantType     *reply_type,
                         GDBusCallFlags          flags,
                         gint                    timeout_msec,
                         GCancellable           *cancellable,
@@ -4197,6 +4308,7 @@ g_dbus_connection_call (GDBusConnection        *connection,
                         gpointer                user_data)
 {
   GDBusMessage *message;
+  CallState *state;
 
   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
   g_return_if_fail (bus_name == NULL || g_dbus_is_name (bus_name));
@@ -4206,6 +4318,17 @@ g_dbus_connection_call (GDBusConnection        *connection,
   g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
   g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
 
+  state = g_slice_new (CallState);
+  state->simple = g_simple_async_result_new (G_OBJECT (connection),
+                                             callback, user_data,
+                                             g_dbus_connection_call);
+  state->method_name = g_strjoin (".", interface_name, method_name, NULL);
+
+  if (reply_type == NULL)
+    reply_type = G_VARIANT_TYPE_ANY;
+
+  state->reply_type = g_variant_type_copy (reply_type);
+
   message = g_dbus_message_new_method_call (bus_name,
                                             object_path,
                                             interface_name,
@@ -4219,47 +4342,13 @@ g_dbus_connection_call (GDBusConnection        *connection,
                                              timeout_msec,
                                              NULL, /* volatile guint32 *out_serial */
                                              cancellable,
-                                             callback,
-                                             user_data);
+                                             g_dbus_connection_call_done,
+                                             state);
 
   if (message != NULL)
     g_object_unref (message);
 }
 
-static GVariant *
-decode_method_reply (GDBusMessage  *reply,
-                     GError       **error)
-{
-  GVariant *result;
-
-  result = NULL;
-  switch (g_dbus_message_get_message_type (reply))
-    {
-    case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
-      result = g_dbus_message_get_body (reply);
-      if (result == NULL)
-        {
-          result = g_variant_new ("()");
-          g_variant_ref_sink (result);
-        }
-      else
-        {
-          g_variant_ref (result);
-        }
-      break;
-
-    case G_DBUS_MESSAGE_TYPE_ERROR:
-      g_dbus_message_to_gerror (reply, error);
-      break;
-
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-
-  return result;
-}
-
 /**
  * g_dbus_connection_call_finish:
  * @connection: A #GDBusConnection.
@@ -4278,25 +4367,19 @@ g_dbus_connection_call_finish (GDBusConnection  *connection,
                                GAsyncResult     *res,
                                GError          **error)
 {
-  GDBusMessage *reply;
-  GVariant *result;
+  GSimpleAsyncResult *simple;
 
   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
-  g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
+  g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (connection),
+                                                        g_dbus_connection_call), NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-  result = NULL;
-
-  reply = g_dbus_connection_send_message_with_reply_finish (connection, res, error);
-  if (reply == NULL)
-    goto out;
+  simple = G_SIMPLE_ASYNC_RESULT (res);
 
-  result = decode_method_reply (reply, error);
-
-  g_object_unref (reply);
+  if (g_simple_async_result_propagate_error (simple, error))
+    return FALSE;
 
- out:
-  return result;
+  return g_variant_ref (g_simple_async_result_get_op_res_gpointer (simple));
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -4309,6 +4392,7 @@ g_dbus_connection_call_finish (GDBusConnection  *connection,
  * @interface_name: D-Bus interface to invoke method on.
  * @method_name: The name of the method to invoke.
  * @parameters: A #GVariant tuple with parameters for the method or %NULL if not passing parameters.
+ * @reply_type: The expected type of the reply, or %NULL.
  * @flags: Flags from the #GDBusCallFlags enumeration.
  * @timeout_msec: The timeout in milliseconds or -1 to use the default timeout.
  * @cancellable: A #GCancellable or %NULL.
@@ -4323,6 +4407,11 @@ g_dbus_connection_call_finish (GDBusConnection  *connection,
  * operation will fail with %G_IO_ERROR_CANCELLED. If @parameters
  * contains a value not compatible with the D-Bus protocol, the operation
  * fails with %G_IO_ERROR_INVALID_ARGUMENT.
+
+ * If @reply_type is non-%NULL then the reply will be checked for having
+ * this type and an error will be raised if it does not match.  Said
+ * another way, if you give a @reply_type then any non-%NULL return
+ * value will be of this type.
  *
  * If the @parameters #GVariant is floating, it is consumed.
  * This allows convenient 'inline' use of g_variant_new(), e.g.:
@@ -4335,6 +4424,7 @@ g_dbus_connection_call_finish (GDBusConnection  *connection,
  *                               g_variant_new ("(ss)",
  *                                              "Thing One",
  *                                              "Thing Two"),
+ *                               NULL,
  *                               G_DBUS_CALL_FLAGS_NONE,
  *                               -1,
  *                               NULL,
@@ -4357,6 +4447,7 @@ g_dbus_connection_call_sync (GDBusConnection         *connection,
                              const gchar             *interface_name,
                              const gchar             *method_name,
                              GVariant                *parameters,
+                             const GVariantType      *reply_type,
                              GDBusCallFlags           flags,
                              gint                     timeout_msec,
                              GCancellable            *cancellable,
@@ -4378,6 +4469,9 @@ g_dbus_connection_call_sync (GDBusConnection         *connection,
   g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
   g_return_val_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
 
+  if (reply_type == NULL)
+    reply_type = G_VARIANT_TYPE_ANY;
+
   message = g_dbus_message_new_method_call (bus_name,
                                             object_path,
                                             interface_name,
@@ -4396,7 +4490,7 @@ g_dbus_connection_call_sync (GDBusConnection         *connection,
   if (reply == NULL)
     goto out;
 
-  result = decode_method_reply (reply, error);
+  result = decode_method_reply (reply, method_name, reply_type, error);
 
  out:
   if (message != NULL)
index 42ba476766afe04cb904b83ca36786cf9243eca3..1055a58b1464afce14506fc786ec2b4fd86b542c 100644 (file)
@@ -179,6 +179,7 @@ void      g_dbus_connection_call                              (GDBusConnection
                                                                const gchar        *interface_name,
                                                                const gchar        *method_name,
                                                                GVariant           *parameters,
+                                                               const GVariantType *reply_type,
                                                                GDBusCallFlags      flags,
                                                                gint                timeout_msec,
                                                                GCancellable       *cancellable,
@@ -193,6 +194,7 @@ GVariant *g_dbus_connection_call_sync                         (GDBusConnection
                                                                const gchar        *interface_name,
                                                                const gchar        *method_name,
                                                                GVariant           *parameters,
+                                                               const GVariantType *reply_type,
                                                                GDBusCallFlags      flags,
                                                                gint                timeout_msec,
                                                                GCancellable       *cancellable,
index 404652e3d1bb1f826156d9f447cbbef5c55aa9e6..44461664888141382a180c9f038e61a78ff2a0e0 100644 (file)
@@ -340,29 +340,27 @@ g_dbus_method_invocation_return_value (GDBusMethodInvocation *invocation,
   g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
   g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
 
-  if (parameters != NULL)
-    g_variant_ref_sink (parameters);
+  if (parameters == NULL)
+    parameters = g_variant_new_tuple (NULL, 0);
 
   /* if we have introspection data, check that the signature of @parameters is correct */
   if (invocation->priv->method_info != NULL)
     {
-      gchar *signature;
-      const gchar *type_string;
+      GVariantType *type;
 
-      type_string = "()";
-      if (parameters != NULL)
-        type_string = g_variant_get_type_string (parameters);
-      signature = _g_dbus_compute_complete_signature (invocation->priv->method_info->out_args, TRUE);
+      type = _g_dbus_compute_complete_signature (invocation->priv->method_info->out_args);
 
-      if (g_strcmp0 (type_string, signature) != 0)
+      if (!g_variant_is_of_type (parameters, type))
         {
-          g_warning (_("Type of return value is incorrect, got `%s', expected  `%s'"),
-                     type_string,
-                     signature);
-          g_free (signature);
+          gchar *type_string = g_variant_type_dup_string (type);
+
+          g_warning (_("Type of return value is incorrect, got `%s', expected `%s'"),
+                     g_variant_get_type_string (parameters), type_string);
+          g_variant_type_free (type);
+          g_free (type_string);
           goto out;
         }
-      g_free (signature);
+      g_variant_type_free (type);
     }
 
   reply = g_dbus_message_new_method_reply (invocation->priv->message);
@@ -377,8 +375,6 @@ g_dbus_method_invocation_return_value (GDBusMethodInvocation *invocation,
 
  out:
   g_object_unref (invocation);
-  if (parameters != NULL)
-    g_variant_unref (parameters);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
index e1491321763b3bd6669b150a1b5619f10cc3d368..a20a3440227b760e9771b3116fc20d15dc15e117 100644 (file)
@@ -403,6 +403,7 @@ has_connection (Client *client)
                           g_variant_new ("(su)",
                                          client->name,
                                          client->flags),
+                          G_VARIANT_TYPE ("(u)"),
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           NULL,
@@ -681,6 +682,7 @@ g_bus_unown_name (guint owner_id)
                                                 "org.freedesktop.DBus",  /* interface name */
                                                 "ReleaseName",           /* method name */
                                                 g_variant_new ("(s)", client->name),
+                                                G_VARIANT_TYPE ("(u)"),
                                                 G_DBUS_CALL_FLAGS_NONE,
                                                 -1,
                                                 NULL,
index 9fe944d81db812833e4e791a5dc2de98f3500528..8c0e7a5e1f6fb8669c92ce5e2aaced68b068ec94 100644 (file)
@@ -368,6 +368,7 @@ invoke_get_name_owner (Client *client)
                           "org.freedesktop.DBus",  /* interface name */
                           "GetNameOwner",          /* method name */
                           g_variant_new ("(s)", client->name),
+                          G_VARIANT_TYPE ("(s)"),
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           NULL,
@@ -459,6 +460,7 @@ has_connection (Client *client)
                               "org.freedesktop.DBus",  /* interface name */
                               "StartServiceByName",    /* method name */
                               g_variant_new ("(su)", client->name, 0),
+                              G_VARIANT_TYPE ("(u)"),
                               G_DBUS_CALL_FLAGS_NONE,
                               -1,
                               NULL,
index 186ba7f58550174d7e1a5ca6f600507687d23a19..51e8e798c076a0d17f1ec237b258e8f3eb412e43 100644 (file)
@@ -1035,25 +1035,29 @@ _g_dbus_initialize (void)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-gchar *
-_g_dbus_compute_complete_signature (GDBusArgInfo **args,
-                                    gboolean       include_parentheses)
+GVariantType *
+_g_dbus_compute_complete_signature (GDBusArgInfo **args)
 {
-  GString *s;
+  const GVariantType *arg_types[256];
   guint n;
 
-  if (include_parentheses)
-    s = g_string_new ("(");
-  else
-    s = g_string_new ("");
-  if (args != NULL)
+  if (args)
     for (n = 0; args[n] != NULL; n++)
-      g_string_append (s, args[n]->signature);
+      {
+        /* DBus places a hard limit of 255 on signature length.
+         * therefore number of args must be less than 256.
+         */
+        g_assert (n < 256);
 
-  if (include_parentheses)
-    g_string_append_c (s, ')');
+        arg_types[n] = G_VARIANT_TYPE (args[n]->signature);
+
+        if G_UNLIKELY (arg_types[n] == NULL)
+          return NULL;
+      }
+  else
+    n = 0;
 
-  return g_string_free (s, FALSE);
+  return g_variant_type_new_tuple (arg_types, n);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
index 09ec56d623a8808b697a5b041fc5797d344339f6..ba2c8f488a5868262bb1c764db690bdef1fd4db1 100644 (file)
@@ -73,8 +73,7 @@ gboolean _g_dbus_address_parse_entry (const gchar  *address_entry,
                                       GHashTable  **out_key_value_pairs,
                                       GError      **error);
 
-gchar * _g_dbus_compute_complete_signature (GDBusArgInfo **args,
-                                            gboolean       include_parentheses);
+GVariantType * _g_dbus_compute_complete_signature (GDBusArgInfo **args);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
index 51cb5f2babb1cacf4893b42c3f9d48bc81eac84b..8be309f0b86be8f8d967d8c594956d40f621df28 100644 (file)
@@ -845,6 +845,7 @@ initable_init (GInitable     *initable,
                                             "org.freedesktop.DBus.Properties",
                                             "GetAll",
                                             g_variant_new ("(s)", proxy->priv->interface_name),
+                                            G_VARIANT_TYPE ("(a{sv})"),
                                             G_DBUS_CALL_FLAGS_NONE,
                                             -1,           /* timeout */
                                             cancellable,
@@ -927,6 +928,7 @@ async_initable_init_async (GAsyncInitable      *initable,
                               "org.freedesktop.DBus.Properties",
                               "GetAll",
                               g_variant_new ("(s)", proxy->priv->interface_name),
+                              G_VARIANT_TYPE ("(a{sv})"),
                               G_DBUS_CALL_FLAGS_NONE,
                               -1,           /* timeout */
                               cancellable,
@@ -1408,45 +1410,6 @@ lookup_method_info_or_warn (GDBusProxy  *proxy,
   return info;
 }
 
-static gboolean
-validate_method_return (const char             *method_name,
-                        GVariant               *value,
-                        const GDBusMethodInfo  *expected_method_info,
-                        GError                **error)
-{
-  const gchar *type_string;
-  gchar *signature;
-  gboolean ret;
-
-  ret = TRUE;
-  signature = NULL;
-
-  if (value == NULL || expected_method_info == NULL)
-    goto out;
-
-  /* Shouldn't happen... */
-  if (g_variant_classify (value) != G_VARIANT_CLASS_TUPLE)
-    goto out;
-
-  type_string = g_variant_get_type_string (value);
-  signature = _g_dbus_compute_complete_signature (expected_method_info->out_args, TRUE);
-  if (g_strcmp0 (type_string, signature) != 0)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_INVALID_ARGUMENT,
-                   _("Method `%s' returned signature `%s', but expected `%s'"),
-                   method_name,
-                   type_string,
-                   signature);
-      ret = FALSE;
-    }
-
- out:
-  g_free (signature);
-  return ret;
-}
-
 /**
  * g_dbus_proxy_call:
  * @proxy: A #GDBusProxy.
@@ -1514,6 +1477,7 @@ g_dbus_proxy_call (GDBusProxy          *proxy,
   const GDBusMethodInfo *expected_method_info;
   const gchar *target_method_name;
   const gchar *target_interface_name;
+  GVariantType *reply_type;
 
   g_return_if_fail (G_IS_DBUS_PROXY (proxy));
   g_return_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name));
@@ -1534,18 +1498,27 @@ g_dbus_proxy_call (GDBusProxy          *proxy,
   /* Just warn here */
   expected_method_info = lookup_method_info_or_warn (proxy, target_method_name);
 
+  if (expected_method_info)
+    reply_type = _g_dbus_compute_complete_signature (expected_method_info->out_args);
+  else
+    reply_type = NULL;
+
   g_dbus_connection_call (proxy->priv->connection,
                           proxy->priv->unique_bus_name,
                           proxy->priv->object_path,
                           target_interface_name,
                           target_method_name,
                           parameters,
+                          reply_type,
                           flags,
                           timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
                           cancellable,
                           (GAsyncReadyCallback) reply_cb,
                           simple);
 
+  if (reply_type != NULL)
+    g_variant_type_free (reply_type);
+
   g_free (split_interface_name);
 }
 
@@ -1570,7 +1543,6 @@ g_dbus_proxy_call_finish (GDBusProxy    *proxy,
   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
   GVariant *value;
   const char *method_name;
-  const GDBusMethodInfo *expected_method_info;
 
   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
@@ -1586,17 +1558,6 @@ g_dbus_proxy_call_finish (GDBusProxy    *proxy,
   value = g_simple_async_result_get_op_res_gpointer (simple);
   method_name = g_object_get_data (G_OBJECT (simple), "-gdbus-proxy-method-name");
 
-  /* We may not have a method name for internally-generated proxy calls like GetAll */
-  if (value && method_name && proxy->priv->expected_interface)
-    {
-      expected_method_info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, method_name);
-      if (!validate_method_return (method_name, value, expected_method_info, error))
-        {
-          g_variant_unref (value);
-          value = NULL;
-        }
-    }
-
  out:
   return value;
 }
@@ -1663,6 +1624,7 @@ g_dbus_proxy_call_sync (GDBusProxy      *proxy,
   const GDBusMethodInfo *expected_method_info;
   const gchar *target_method_name;
   const gchar *target_interface_name;
+  GVariantType *reply_type;
 
   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
   g_return_val_if_fail (g_dbus_is_member_name (method_name) || g_dbus_is_interface_name (method_name), NULL);
@@ -1689,21 +1651,25 @@ g_dbus_proxy_call_sync (GDBusProxy      *proxy,
       expected_method_info = NULL;
     }
 
+  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->unique_bus_name,
                                      proxy->priv->object_path,
                                      target_interface_name,
                                      target_method_name,
                                      parameters,
+                                     reply_type,
                                      flags,
                                      timeout_msec == -1 ? proxy->priv->timeout_msec : timeout_msec,
                                      cancellable,
                                      error);
-  if (!validate_method_return (target_method_name, ret, expected_method_info, error))
-    {
-      g_variant_unref (ret);
-      ret = NULL;
-    }
+
+  if (reply_type != NULL)
+    g_variant_type_free (reply_type);
 
   g_free (split_interface_name);
 
index fdaacdc60c7ca8a0e686536b790a99d073cafbc2..c9eedfdde61463ac15d30b8e1e33e84f2c6a9ca1 100644 (file)
@@ -230,7 +230,7 @@ handle_set (gint   *argc,
     session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
     g_dbus_connection_call_sync (session, "org.gtk.DoesNotExist", "/",
                                  "org.gtk.DoesNotExist", "Workaround",
-                                 g_variant_new ("()"), 0, -1, NULL, NULL);
+                                 g_variant_new ("()"), NULL, 0, -1, NULL, NULL);
   }
 
  out:
index 266512f3eb11ce63c40c742d1cb2ab547da2bdcd..2a481260ac1556c75dfe220b7d5d65ea3a8afcb4 100644 (file)
@@ -234,7 +234,7 @@ test_connection_send (void)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "GetId",                 /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           ca,
@@ -251,7 +251,7 @@ test_connection_send (void)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "GetId",                 /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           NULL,
@@ -267,7 +267,7 @@ test_connection_send (void)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "NonExistantMethod",     /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           NULL,
@@ -284,7 +284,7 @@ test_connection_send (void)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "GetId",                 /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           ca,
@@ -307,7 +307,7 @@ test_connection_send (void)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "GetId",                 /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           NULL,
@@ -462,6 +462,7 @@ test_connection_signals (void)
                                         "org.freedesktop.DBus",  /* interface name */
                                         "GetId",                 /* method name */
                                         NULL,                    /* parameters */
+                                        NULL,                    /* return type */
                                         G_DBUS_CALL_FLAGS_NONE,
                                         -1,
                                         NULL,
index 316680ea6a2fd3317ed57a5ac05b10165ca1ff13..7df19424d19d389e9d7f3ae5a8a65207694e7748 100644 (file)
@@ -280,6 +280,7 @@ main (int argc, char *argv[])
                                            "org.gtk.GDBus.TestPeerInterface",
                                            "HelloWorld",
                                            g_variant_new ("(s)", greeting),
+                                           G_VARIANT_TYPE ("(s)"),
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1,
                                            NULL,
index b067cee8057eeca4e8882181f33198eeb66652e2..297fb231c57a2d2e0b3b70a27b5f15563f3826b0 100644 (file)
@@ -807,7 +807,7 @@ test_dispatch_thread_func (gpointer user_data)
                                   NULL,
                                   &error);
   g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS);
-  g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Signature of message, `s', does not match expected signature `'");
+  g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Type of message, `(s)', does not match expected type `()'");
   g_error_free (error);
   g_assert (value == NULL);
 
index b48d695aded3c60f3ffbc20525446c2a66ab681c..d5e2342402616135a8855fc97a6763a2d3c16971 100644 (file)
@@ -176,6 +176,7 @@ test_bus_own_name (void)
                                         "org.freedesktop.DBus",  /* interface name */
                                         "NameHasOwner",          /* method name */
                                         g_variant_new ("(s)", name),
+                                        G_VARIANT_TYPE ("(b)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         -1,
                                         NULL,
@@ -201,6 +202,7 @@ test_bus_own_name (void)
                                         "org.freedesktop.DBus",  /* interface name */
                                         "NameHasOwner",          /* method name */
                                         g_variant_new ("(s)", name),
+                                        G_VARIANT_TYPE ("(b)"),
                                         G_DBUS_CALL_FLAGS_NONE,
                                         -1,
                                         NULL,
index 6bfda516fe23f2d516b6326351abe68f0e0ce4dd..6a4e82cf876a4c61e6d6e38450091a6dd265c12f 100644 (file)
@@ -136,7 +136,7 @@ test_delivery_in_thread_func (gpointer _data)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "GetId",                 /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           NULL,
@@ -156,7 +156,7 @@ test_delivery_in_thread_func (gpointer _data)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "GetId",                 /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           ca,
@@ -174,7 +174,7 @@ test_delivery_in_thread_func (gpointer _data)
                           "/org/freedesktop/DBus", /* object path */
                           "org.freedesktop.DBus",  /* interface name */
                           "GetId",                 /* method name */
-                          NULL,
+                          NULL, NULL,
                           G_DBUS_CALL_FLAGS_NONE,
                           -1,
                           ca,