summaryrefslogtreecommitdiff
path: root/libnm/nm-dbus-helpers.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-09-30 17:48:06 +0200
committerThomas Haller <thaller@redhat.com>2014-10-03 11:21:40 +0200
commit97b2c1b0d154a27516a9eba2fc67076ce324681c (patch)
tree8b91f4587262d02385eb2f6567f4dfbabb836b32 /libnm/nm-dbus-helpers.c
parentdf57b6b4d19193003f7402ed2ce58b944b650b54 (diff)
downloadNetworkManager-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>
Diffstat (limited to 'libnm/nm-dbus-helpers.c')
-rw-r--r--libnm/nm-dbus-helpers.c98
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,