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>
This commit is contained in:
Thomas Haller 2014-09-30 17:48:06 +02:00
parent df57b6b4d1
commit 97b2c1b0d1

View file

@ -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,