Fix blocking service watch initial connect handling
authorMarcel Holtmann <marcel@holtmann.org>
Fri, 7 Aug 2009 05:10:19 +0000 (22:10 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 7 Aug 2009 05:13:09 +0000 (22:13 -0700)
gdbus/gdbus.h
gdbus/mainloop.c
gdbus/watch.c

index fa618a5..244f797 100644 (file)
@@ -43,8 +43,6 @@ DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
 gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
                                                        DBusError *error);
 
-gboolean g_dbus_check_service(DBusConnection *connection, const char *name);
-
 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
                                GDBusWatchFunction function,
                                void *user_data, DBusFreeFunction destroy);
index eaba42e..a06ed22 100644 (file)
@@ -281,49 +281,6 @@ gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
        return TRUE;
 }
 
-gboolean g_dbus_check_service(DBusConnection *connection, const char *name)
-{
-       DBusMessage *message, *reply;
-       const char **names;
-       int i, count;
-       gboolean result = FALSE;
-
-       message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
-                       DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ListNames");
-       if (message == NULL) {
-               error("Can't allocate new message");
-               return FALSE;
-       }
-
-       reply = dbus_connection_send_with_reply_and_block(connection,
-                                                       message, -1, NULL);
-
-       dbus_message_unref(message);
-
-       if (reply == NULL) {
-               error("Failed to execute method call");
-               return FALSE;
-       }
-
-       if (dbus_message_get_args(reply, NULL,
-                               DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
-                               &names, &count, DBUS_TYPE_INVALID) == FALSE) {
-               error("Failed to read name list");
-               goto done;
-       }
-
-       for (i = 0; i < count; i++)
-               if (g_str_equal(names[i], name) == TRUE) {
-                       result = TRUE;
-                       break;
-               }
-
-done:
-       dbus_message_unref(reply);
-
-       return result;
-}
-
 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
                                GDBusWatchFunction function,
                                void *user_data, DBusFreeFunction destroy)
index c7a4e69..1de21da 100644 (file)
@@ -307,6 +307,97 @@ static DBusHandlerResult name_exit_filter(DBusConnection *connection,
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
+struct service_data {
+       DBusConnection *conn;
+       const char *name;
+       GDBusWatchFunction conn_func;
+       void *user_data;
+};
+
+static void service_reply(DBusPendingCall *call, void *user_data)
+{
+       struct service_data *data = user_data;
+       DBusMessage *reply;
+       DBusError error;
+       char **names;
+       int i, count;
+
+       reply = dbus_pending_call_steal_reply(call);
+       if (reply == NULL)
+               return;
+
+       dbus_error_init(&error);
+
+       if (dbus_message_get_args(reply, &error,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &names, &count,
+                                               DBUS_TYPE_INVALID) == FALSE) {
+               if (dbus_error_is_set(&error) == TRUE) {
+                       error("%s", error.message);
+                       dbus_error_free(&error);
+               } else {
+                       error("Wrong arguments for name list");
+               }
+               goto done;
+       }
+
+       for (i = 0; i < count; i++)
+               if (g_strcmp0(names[i], data->name) == 0) {
+                       if (data->conn_func)
+                               data->conn_func(data->conn, data->user_data);
+                       break;
+               }
+
+       g_strfreev(names);
+
+done:
+       dbus_message_unref(reply);
+}
+
+static void check_service(DBusConnection *connection, const char *name,
+                               GDBusWatchFunction connect, void *user_data)
+{
+       DBusMessage *message;
+       DBusPendingCall *call;
+       struct service_data *data;
+
+       data = g_try_malloc0(sizeof(*data));
+       if (data == NULL) {
+               error("Can't allocate data structure");
+               return;
+       }
+
+       data->conn = connection;
+       data->name = name;
+       data->conn_func = connect;
+       data->user_data = user_data;
+
+       message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
+                       DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ListNames");
+       if (message == NULL) {
+               error("Can't allocate new message");
+               g_free(data);
+               return;
+       }
+
+       if (dbus_connection_send_with_reply(connection, message,
+                                                       &call, -1) == FALSE) {
+               error("Failed to execute method call");
+               g_free(data);
+               goto done;
+       }
+
+       if (call == NULL) {
+               error("D-Bus connection not available");
+               g_free(data);
+               goto done;
+       }
+
+       dbus_pending_call_set_notify(call, service_reply, data, NULL);
+
+done:
+       dbus_message_unref(message);
+}
+
 guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
                                GDBusWatchFunction connect,
                                GDBusWatchFunction disconnect,
@@ -328,7 +419,7 @@ guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
        /* The filter is already added if this is not the first callback
         * registration for the name */
        if (!first)
-               return listener_id;
+               goto done;
 
        if (name) {
                debug("name_listener_add(%s)", name);
@@ -339,6 +430,10 @@ guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
                }
        }
 
+done:
+       if (connect)
+               check_service(connection, name, connect, user_data);
+
        return listener_id;
 }