diff options
author | Thomas Haller <thaller@redhat.com> | 2014-09-30 17:48:06 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-10-03 11:21:40 +0200 |
commit | 97b2c1b0d154a27516a9eba2fc67076ce324681c (patch) | |
tree | 8b91f4587262d02385eb2f6567f4dfbabb836b32 | |
parent | df57b6b4d19193003f7402ed2ce58b944b650b54 (diff) | |
download | NetworkManager-97b2c1b0d154a27516a9eba2fc67076ce324681c.tar.gz |
libnm: share private DBUS connection
Cache the private DBUS connection and reuse it. Otherwise we end up
creating several private connnections, as an NMObject instance creates
a new connection (unless it is passed in as NMObject:dbus-connection
property).
We already pass the existing "parent" DBUS connection when creating
the proxy objects. However, when creating two independent objects
(e.g. nm_client_new() and nm_remote_settings_new()), their private
DBUS connections were not shared.
Implement this sharing inside nm-dbus-helpers.c
https://bugzilla.gnome.org/show_bug.cgi?id=737725
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | libnm/nm-dbus-helpers.c | 98 |
1 files changed, 91 insertions, 7 deletions
diff --git a/libnm/nm-dbus-helpers.c b/libnm/nm-dbus-helpers.c index 10f5913305..4c0318dd2e 100644 --- a/libnm/nm-dbus-helpers.c +++ b/libnm/nm-dbus-helpers.c @@ -41,6 +41,51 @@ _nm_dbus_bus_type (void) return nm_bus; } +static struct { + GMutex mutex; + GWeakRef weak_ref; +} private_connection; + +static void +_private_dbus_connection_closed_cb (GDBusConnection *connection, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) +{ + GDBusConnection *p; + + g_mutex_lock (&private_connection.mutex); + p = g_weak_ref_get (&private_connection.weak_ref); + if (connection == p) { + g_signal_handlers_disconnect_by_func (G_OBJECT (connection), G_CALLBACK (_private_dbus_connection_closed_cb), NULL); + g_weak_ref_set (&private_connection.weak_ref, NULL); + } + if (p) + g_object_unref (p); + g_mutex_unlock (&private_connection.mutex); +} + +static GDBusConnection * +_private_dbus_connection_internalize (GDBusConnection *connection) +{ + GDBusConnection *p; + + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); + g_return_val_if_fail (!g_dbus_connection_is_closed (connection), NULL); + + g_mutex_lock (&private_connection.mutex); + p = g_weak_ref_get (&private_connection.weak_ref); + if (p) { + g_object_unref (connection); + connection = p; + } else { + g_weak_ref_set (&private_connection.weak_ref, connection); + g_signal_connect (connection, "closed", G_CALLBACK (_private_dbus_connection_closed_cb), NULL); + } + g_mutex_unlock (&private_connection.mutex); + return connection; +} + GDBusConnection * _nm_dbus_new_connection (GCancellable *cancellable, GError **error) { @@ -49,12 +94,17 @@ _nm_dbus_new_connection (GCancellable *cancellable, GError **error) /* If running as root try the private bus first */ if (0 == geteuid ()) { GError *local = NULL; + GDBusConnection *p; + + p = g_weak_ref_get (&private_connection.weak_ref); + if (p) + return p; connection = g_dbus_connection_new_for_address_sync ("unix:path=" NMRUNDIR "/private", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, cancellable, &local); if (connection) - return connection; + return _private_dbus_connection_internalize (connection); if (g_error_matches (local, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_propagate_error (error, local); @@ -92,6 +142,7 @@ new_connection_async_got_private (GObject *source, GAsyncResult *result, gpointe connection = g_dbus_connection_new_for_address_finish (result, &error); if (connection) { + connection = _private_dbus_connection_internalize (connection); g_simple_async_result_set_op_res_gpointer (simple, connection, g_object_unref); g_simple_async_result_complete (simple); g_object_unref (simple); @@ -111,6 +162,36 @@ new_connection_async_got_private (GObject *source, GAsyncResult *result, gpointe new_connection_async_got_system, simple); } +static void +_nm_dbus_new_connection_async_do (GSimpleAsyncResult *simple, GCancellable *cancellable) +{ + g_dbus_connection_new_for_address ("unix:path=" NMRUNDIR "/private", + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, + NULL, + cancellable, + new_connection_async_got_private, simple); +} + +static gboolean +_nm_dbus_new_connection_async_get_private (gpointer user_data) +{ + GSimpleAsyncResult *simple = user_data; + GDBusConnection *p; + + p = g_weak_ref_get (&private_connection.weak_ref); + if (!p) { + /* The connection is gone. Create a new one async... */ + _nm_dbus_new_connection_async_do (simple, + g_object_get_data (G_OBJECT (simple), "cancellable")); + } else { + g_simple_async_result_set_op_res_gpointer (simple, p, g_object_unref); + g_simple_async_result_complete (simple); + g_object_unref (simple); + } + + return G_SOURCE_REMOVE; +} + void _nm_dbus_new_connection_async (GCancellable *cancellable, GAsyncReadyCallback callback, @@ -122,15 +203,18 @@ _nm_dbus_new_connection_async (GCancellable *cancellable, /* If running as root try the private bus first */ if (0 == geteuid ()) { + GDBusConnection *p; + if (cancellable) { g_object_set_data_full (G_OBJECT (simple), "cancellable", - g_object_ref (cancellable), g_object_unref); + g_object_ref (cancellable), g_object_unref); } - g_dbus_connection_new_for_address ("unix:path=" NMRUNDIR "/private", - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, - NULL, - cancellable, - new_connection_async_got_private, simple); + p = g_weak_ref_get (&private_connection.weak_ref); + if (p) { + g_object_unref (p); + g_idle_add (_nm_dbus_new_connection_async_get_private, simple); + } else + _nm_dbus_new_connection_async_do (simple, cancellable); } else { g_bus_get (_nm_dbus_bus_type (), cancellable, |