diff options
| author | Michael Biebl <biebl@debian.org> | 2016-01-20 16:26:51 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2016-01-20 16:26:51 +0100 |
| commit | 494f296a3baab08522617b24b1f126d8f9a17502 (patch) | |
| tree | c8ef32fb0dd1c4ff35a0b38e787abb58692de0cd /libnm/nm-dbus-helpers.c | |
| parent | 54f6333410ffd570e62717d9e77c5c987175e397 (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.c | 242 |
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 |