[telepathy-glib/master] Use raw libdbus for GetNameOwner
Simon McVittie
simon.mcvittie at collabora.co.uk
Mon Aug 17 04:13:53 PDT 2009
---
telepathy-glib/dbus.c | 153 +++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 141 insertions(+), 12 deletions(-)
diff --git a/telepathy-glib/dbus.c b/telepathy-glib/dbus.c
index 64d5311..ce68fc7 100644
--- a/telepathy-glib/dbus.c
+++ b/telepathy-glib/dbus.c
@@ -746,6 +746,8 @@ _tp_dbus_daemon_name_owner_changed (TpDBusDaemon *self,
_NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
name);
+ DEBUG ("%s -> %s", name, new_owner);
+
if (watch == NULL)
return;
@@ -819,6 +821,8 @@ noc_idle_context_invoke (gpointer data)
daemons = dbus_connection_get_data (context->libdbus, daemons_slot);
+ DEBUG ("NameOwnerChanged(%s, %s -> %s)", name, old_owner, new_owner);
+
/* should always be non-NULL, barring bugs */
if (G_LIKELY (daemons != NULL))
{
@@ -848,19 +852,91 @@ _tp_dbus_daemon_name_owner_changed_filter (DBusConnection *libdbus,
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
+typedef struct {
+ TpDBusDaemon *self;
+ gchar *name;
+ DBusMessage *reply;
+ gsize refs;
+} GetNameOwnerContext;
+
+static GetNameOwnerContext *
+get_name_owner_context_new (TpDBusDaemon *self,
+ const gchar *name)
+{
+ GetNameOwnerContext *context = g_slice_new (GetNameOwnerContext);
+
+ context->self = g_object_ref (self);
+ context->name = g_strdup (name);
+ context->reply = NULL;
+ DEBUG ("New, 1 ref");
+ context->refs = 1;
+ return context;
+}
+
static void
-_tp_dbus_daemon_got_name_owner (TpDBusDaemon *self,
- const gchar *owner,
- const GError *error,
- gpointer user_data,
- GObject *user_object)
+get_name_owner_context_unref (gpointer data)
{
- gchar *name = user_data;
+ GetNameOwnerContext *context = data;
+
+ DEBUG ("%lu -> %lu", (gulong) context->refs, (gulong) (context->refs-1));
+
+ if (--context->refs == 0)
+ {
+ g_object_unref (context->self);
+ g_free (context->name);
+
+ if (context->reply != NULL)
+ dbus_message_unref (context->reply);
+
+ g_slice_free (GetNameOwnerContext, context);
+ }
+}
+
+static gboolean
+_tp_dbus_daemon_get_name_owner_idle (gpointer data)
+{
+ GetNameOwnerContext *context = data;
+ const gchar *owner = "";
+
+ if (context->reply == NULL)
+ {
+ DEBUG ("Connection disconnected or no reply to GetNameOwner(%s)",
+ context->name);
+ }
+ else if (dbus_message_get_type (context->reply) ==
+ DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ {
+ if (!dbus_message_get_args (context->reply, NULL,
+ DBUS_TYPE_STRING, &owner,
+ DBUS_TYPE_INVALID))
+ {
+ DEBUG ("Malformed reply from GetNameOwner(%s), assuming no owner",
+ context->name);
+ }
+ }
+ else
+ {
+ if (DEBUGGING)
+ {
+ DBusError error = DBUS_ERROR_INIT;
+
+ if (dbus_set_error_from_message (&error, context->reply))
+ {
+ DEBUG ("GetNameOwner(%s) raised %s: %s", context->name,
+ error.name, error.message);
+ dbus_error_free (&error);
+ }
+ else
+ {
+ DEBUG ("Unexpected message type from GetNameOwner(%s)",
+ context->name);
+ }
+ }
+ }
- if (error != NULL)
- owner = "";
+ _tp_dbus_daemon_name_owner_changed (context->self, context->name, owner);
- _tp_dbus_daemon_name_owner_changed (self, name, owner);
+ return FALSE;
}
/**
@@ -887,6 +963,28 @@ _tp_dbus_daemon_get_noc_rule (const gchar *name)
"arg0='%s'", name);
}
+static void
+_tp_dbus_daemon_get_name_owner_notify (DBusPendingCall *pc,
+ gpointer data)
+{
+ GetNameOwnerContext *context = data;
+
+ /* we recycle this function for the case where the connection is already
+ * disconnected: in that case we use pc = NULL */
+ if (pc != NULL)
+ context->reply = dbus_pending_call_steal_reply (pc);
+
+ /* We have to do the real work in an idle, so we don't break re-entrant
+ * calls (the dbus-glib event source isn't re-entrant) */
+ DEBUG ("%lu -> %lu", (gulong) context->refs, (gulong) (context->refs + 1));
+ context->refs++;
+ g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_get_name_owner_idle,
+ context, get_name_owner_context_unref);
+
+ if (pc != NULL)
+ dbus_pending_call_unref (pc);
+}
+
/**
* tp_dbus_daemon_watch_name_owner:
* @self: The D-Bus daemon
@@ -924,6 +1022,9 @@ tp_dbus_daemon_watch_name_owner (TpDBusDaemon *self,
if (watch == NULL)
{
gchar *match_rule;
+ DBusMessage *message;
+ DBusPendingCall *pc = NULL;
+ GetNameOwnerContext *context = get_name_owner_context_new (self, name);
/* Allocate a single watch (common case) */
watch = g_slice_new (_NameOwnerWatch);
@@ -942,9 +1043,37 @@ tp_dbus_daemon_watch_name_owner (TpDBusDaemon *self,
DEBUG ("Adding match rule %s", match_rule);
dbus_bus_add_match (self->priv->libdbus, match_rule, NULL);
- tp_cli_dbus_daemon_call_get_name_owner (self, -1, name,
- _tp_dbus_daemon_got_name_owner,
- g_strdup (name), g_free, NULL);
+ message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
+
+ if (message == NULL)
+ g_error ("Out of memory");
+
+ /* We already checked that @name was in (a small subset of) UTF-8,
+ * so OOM is the only thing that can go wrong. The use of &name here
+ * is because libdbus is strange. */
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ g_error ("Out of memory");
+
+ if (!dbus_connection_send_with_reply (self->priv->libdbus,
+ message, &pc, -1))
+ g_error ("Out of memory");
+ /* pc is unreffed by _tp_dbus_daemon_get_name_owner_notify */
+
+ if (pc == NULL || dbus_pending_call_get_completed (pc))
+ {
+ /* pc can be NULL when the connection is already disconnected */
+ _tp_dbus_daemon_get_name_owner_notify (pc, context);
+ get_name_owner_context_unref (context);
+ }
+ else if (!dbus_pending_call_set_notify (pc,
+ _tp_dbus_daemon_get_name_owner_notify,
+ context, get_name_owner_context_unref))
+ {
+ g_error ("Out of memory");
+ }
}
else
{
--
1.5.6.5
More information about the telepathy-commits
mailing list