summary refs log tree commit diff
path: root/libnm/nm-dbus-helpers.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-01-20 16:26:51 +0100
committerMichael Biebl <biebl@debian.org>2016-01-20 16:26:51 +0100
commit494f296a3baab08522617b24b1f126d8f9a17502 (patch)
treec8ef32fb0dd1c4ff35a0b38e787abb58692de0cd /libnm/nm-dbus-helpers.c
parent54f6333410ffd570e62717d9e77c5c987175e397 (diff)
Imported Upstream version 1.1.90 upstream/1.1.90
Diffstat (limited to 'libnm/nm-dbus-helpers.c')
-rw-r--r--libnm/nm-dbus-helpers.c242
1 files changed, 82 insertions, 160 deletions
diff --git a/libnm/nm-dbus-helpers.c b/libnm/nm-dbus-helpers.c
index 45e09442..3c039375 100644
--- a/libnm/nm-dbus-helpers.c
+++ b/libnm/nm-dbus-helpers.c
@@ -21,11 +21,11 @@
 #include "config.h"
 
 #include <string.h>
-#include <gio/gio.h>
 
-#include "nm-glib-compat.h"
+#include "nm-default.h"
 #include "nm-dbus-helpers.h"
 #include "nm-dbus-interface.h"
+#include "nm-macros-internal.h"
 
 static GBusType nm_bus = G_BUS_TYPE_SYSTEM;
 
@@ -44,79 +44,9 @@ _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)
 {
-	GDBusConnection *connection = NULL;
-
-	/* If running as root try the private bus first */
-	if (0 == geteuid () && !g_test_initialized ()) {
-
-		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 _private_dbus_connection_internalize (connection);
-
-		if (g_error_matches (local, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-			g_propagate_error (error, local);
-			return NULL;
-		}
-		g_error_free (local);
-	}
-
 	return g_bus_get_sync (_nm_dbus_bus_type (), cancellable, error);
 }
 
@@ -137,65 +67,6 @@ new_connection_async_got_system (GObject *source, GAsyncResult *result, gpointer
 	g_object_unref (simple);
 }
 
-static void
-new_connection_async_got_private (GObject *source, GAsyncResult *result, gpointer user_data)
-{
-	GSimpleAsyncResult *simple = user_data;
-	GDBusConnection *connection;
-	GError *error = NULL;
-
-	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);
-		return;
-	}
-
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-		g_simple_async_result_take_error (simple, error);
-		g_simple_async_result_complete (simple);
-		g_object_unref (simple);
-		return;
-	}
-
-	g_clear_error (&error);
-	g_bus_get (_nm_dbus_bus_type (),
-	           g_object_get_data (G_OBJECT (simple), "cancellable"),
-	           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,
@@ -205,25 +76,9 @@ _nm_dbus_new_connection_async (GCancellable *cancellable,
 
 	simple = g_simple_async_result_new (NULL, callback, user_data, _nm_dbus_new_connection_async);
 
-	/* If running as root try the private bus first */
-	if (0 == geteuid () && !g_test_initialized ()) {
-		GDBusConnection *p;
-
-		if (cancellable) {
-			g_object_set_data_full (G_OBJECT (simple), "cancellable",
-			                        g_object_ref (cancellable), g_object_unref);
-		}
-		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,
-		           new_connection_async_got_system, simple);
-	}
+	g_bus_get (_nm_dbus_bus_type (),
+	           cancellable,
+	           new_connection_async_got_system, simple);
 }
 
 GDBusConnection *
@@ -262,6 +117,67 @@ _nm_dbus_register_proxy_type (const char *interface,
 #define NM_DBUS_PROXY_FLAGS (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | \
                              G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
 
+/* D-Bus has an upper limit on number of Match rules and it's rather easy
+ * to hit as the proxy likes to add one for each object. Let's remove the Match
+ * rule the proxy added and ensure a less granular rule is present instead.
+ *
+ * Also, don't do this immediately since it has a performance penalty.
+ * Still better than loosing the signals altogether.
+ *
+ * Ideally, we should be able to tell glib not to hook its rules:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=758749
+ */
+static void
+_nm_dbus_proxy_replace_match (GDBusProxy *proxy)
+{
+	GDBusConnection *connection = g_dbus_proxy_get_connection (proxy);
+	static unsigned match_counter = 1024;
+	gchar *match;
+
+	nm_assert (!g_strcmp0 (g_dbus_proxy_get_name (proxy), NM_DBUS_SERVICE));
+
+	if (match_counter == 1) {
+		/* If we hit the low matches watermark, install a
+		 * less granular one. */
+		g_dbus_connection_call (connection,
+		                        "org.freedesktop.DBus",
+		                        "/org/freedesktop/DBus",
+		                        "org.freedesktop.DBus",
+		                        "AddMatch",
+		                        g_variant_new ("(s)", "type='signal',sender='" NM_DBUS_SERVICE "'"),
+		                        NULL,
+		                        G_DBUS_CALL_FLAGS_NONE,
+		                        -1,
+		                        NULL,
+		                        NULL,
+		                        NULL);
+	}
+
+	if (match_counter)
+		match_counter--;
+	if (match_counter)
+		return;
+
+	/* Remove what this proxy added. */
+	match = g_strdup_printf ("type='signal',sender='" NM_DBUS_SERVICE "',"
+	                         "interface='%s',path='%s'",
+	                         g_dbus_proxy_get_interface_name (proxy),
+	                         g_dbus_proxy_get_object_path (proxy));
+	g_dbus_connection_call (connection,
+	                        "org.freedesktop.DBus",
+	                        "/org/freedesktop/DBus",
+	                        "org.freedesktop.DBus",
+	                        "RemoveMatch",
+	                        g_variant_new ("(s)", match),
+	                        NULL,
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        -1,
+	                        NULL,
+	                        NULL,
+	                        NULL);
+	g_free (match);
+}
+
 GDBusProxy *
 _nm_dbus_new_proxy_for_connection (GDBusConnection *connection,
                                    const char *path,
@@ -269,6 +185,7 @@ _nm_dbus_new_proxy_for_connection (GDBusConnection *connection,
                                    GCancellable *cancellable,
                                    GError **error)
 {
+	GDBusProxy *proxy;
 	GType proxy_type;
 	const char *name;
 
@@ -281,13 +198,16 @@ _nm_dbus_new_proxy_for_connection (GDBusConnection *connection,
 	else
 		name = NM_DBUS_SERVICE;
 
-	return g_initable_new (proxy_type, cancellable, error,
-	                       "g-connection", connection,
-	                       "g-flags", NM_DBUS_PROXY_FLAGS,
-	                       "g-name", name,
-	                       "g-object-path", path,
-	                       "g-interface-name", interface,
-	                       NULL);
+	proxy = g_initable_new (proxy_type, cancellable, error,
+	                        "g-connection", connection,
+	                        "g-flags", NM_DBUS_PROXY_FLAGS,
+	                        "g-name", name,
+	                        "g-object-path", path,
+	                        "g-interface-name", interface,
+	                        NULL);
+	_nm_dbus_proxy_replace_match (proxy);
+
+	return proxy;
 }
 
 void
@@ -324,13 +244,15 @@ GDBusProxy *
 _nm_dbus_new_proxy_for_connection_finish (GAsyncResult *result,
                                           GError **error)
 {
-	GObject *source, *proxy;
+	GObject *source;
+	GDBusProxy *proxy;
 
 	source = g_async_result_get_source_object (result);
-	proxy = g_async_initable_new_finish (G_ASYNC_INITABLE (source), result, error);
+	proxy = G_DBUS_PROXY (g_async_initable_new_finish (G_ASYNC_INITABLE (source), result, error));
 	g_object_unref (source);
+	_nm_dbus_proxy_replace_match (proxy);
 
-	return G_DBUS_PROXY (proxy);
+	return proxy;
 }
 
 /* Binds the properties on a generated server-side GDBus object to the