diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2012-07-10 07:05:16 +0000 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2012-07-10 09:08:00 +0000 |
commit | 9e02f1fc933fc288cc6f929de30cb65d2108fa29 (patch) | |
tree | 59892cf436de8a4a6a52a6dc3fd3251519d3ef06 /src/gdbusxx/gdbus-cxx-bridge.h | |
parent | 35e81d293c79787cdac02de7513459a1a1cb5f4b (diff) |
D-Bus GIO: reimplemented DBusWatch
The previous implementation did not work at all. It relied
on "NameLost" signals with the watched D-Bus name as sender,
but that is not how the signal works. It is sent by the D-Bus
daemon to the old owner of that name if it looses the name.
Instead we need to watch the "NameOwnerChanged" signal and
detect when the peer we are watching is the one who disconnected
from the bus.
Also moved the actual code into the .cpp file because there is
no need to inline all of it.
This problem was found after adding more failure tests to
test-dbus.py. The real-world effect was that syncevo-dbus-server did
not clean up properly when clients disconnected early and that the
command line kept running after syncevo-dbus-server crashed. Did not
affect syncevolution.org binaries, which do not use D-Bus GIO.
Diffstat (limited to 'src/gdbusxx/gdbus-cxx-bridge.h')
-rw-r--r-- | src/gdbusxx/gdbus-cxx-bridge.h | 48 |
1 files changed, 33 insertions, 15 deletions
diff --git a/src/gdbusxx/gdbus-cxx-bridge.h b/src/gdbusxx/gdbus-cxx-bridge.h index 4ed7c802..ad613f7e 100644 --- a/src/gdbusxx/gdbus-cxx-bridge.h +++ b/src/gdbusxx/gdbus-cxx-bridge.h @@ -1963,20 +1963,37 @@ class DBusWatch : public Watch boost::function<void (void)> m_callback; bool m_called; guint m_watchID; + std::string m_peer; - static void disconnect(GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) + static void nameOwnerChanged(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { DBusWatch *watch = static_cast<DBusWatch *>(user_data); if (!watch->m_called) { - watch->m_called = true; - if (watch->m_callback) { - watch->m_callback(); + gchar *name = NULL, *oldOwner = NULL, *newOwner = NULL; + g_variant_get(parameters, "(sss)", &name, &oldOwner, &newOwner); + bool matches = name && watch->m_peer == name && + newOwner && !*newOwner; + g_free(name); + g_free(oldOwner); + g_free(newOwner); + if (matches) { + watch->disconnected(); + } + } + } + + void disconnected() + { + if (!m_called) { + m_called = true; + if (m_callback) { + m_callback(); } } } @@ -2004,16 +2021,17 @@ class DBusWatch : public Watch if (!peer) { throw std::runtime_error("DBusWatch::activate(): no peer"); } + m_peer = peer; // Install watch first ... m_watchID = g_dbus_connection_signal_subscribe(m_conn.get(), - peer, + NULL, // TODO org.freedesktop.DBus? "org.freedesktop.DBus", - "NameLost", - "/org/freesktop/DBus", + "NameOwnerChanged", + "/org/freedesktop/DBus", NULL, G_DBUS_SIGNAL_FLAGS_NONE, - disconnect, + nameOwnerChanged, this, NULL); if (!m_watchID) { @@ -2044,7 +2062,7 @@ class DBusWatch : public Watch g_variant_get(result, "(b)", &actual_result); if (!actual_result) { - disconnect(m_conn.get(), NULL, NULL, NULL, NULL, NULL, this); + disconnected(); } } else { std::string error_message(error->message); |