diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2015-11-27 17:41:47 +0100 |
---|---|---|
committer | Philip Withnall <pwithnall@endlessos.org> | 2021-06-17 17:35:09 +0100 |
commit | e5979d1e27e8be475c9848c998f6cc1ed111318d (patch) | |
tree | 3ebecf3d83f211d92039a2f7e44d0bba0e9217ba | |
parent | 132d64db4dff498863ec526eb3b360bf9e8e11e8 (diff) | |
download | glib-1109-no-match-rule.tar.gz |
gdbusproxy: Add G_DBUS_PROXY_FLAGS_NO_MATCH_RULE flag1109-no-match-rule
D-Bus has an upper limit on number of Match rules and it's rather easy to hit
with a big number of proxies with signal subscriptions. This happens with
NetworkManager with hundreds of devices or connection settings. By passing
G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE to g_dbus_connection_signal_subscribe(), the
user can call AddMatch with a less granular match instead of a match per every
proxy.
Tests subsequently added by Philip Withnall.
Fixes: #1109
-rw-r--r-- | gio/gdbusproxy.c | 10 | ||||
-rw-r--r-- | gio/gioenums.h | 6 | ||||
-rw-r--r-- | gio/tests/gdbus-proxy.c | 66 |
3 files changed, 74 insertions, 8 deletions
diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c index 7a2289bd4..9a9b35225 100644 --- a/gio/gdbusproxy.c +++ b/gio/gdbusproxy.c @@ -1694,6 +1694,10 @@ static void async_initable_init_first (GAsyncInitable *initable) { GDBusProxy *proxy = G_DBUS_PROXY (initable); + GDBusSignalFlags signal_flags = G_DBUS_SIGNAL_FLAGS_NONE; + + if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_NO_MATCH_RULE) + signal_flags |= G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE; if (!(proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)) { @@ -1705,7 +1709,7 @@ async_initable_init_first (GAsyncInitable *initable) "PropertiesChanged", proxy->priv->object_path, proxy->priv->interface_name, - G_DBUS_SIGNAL_FLAGS_NONE, + signal_flags, on_properties_changed, weak_ref_new (G_OBJECT (proxy)), (GDestroyNotify) weak_ref_free); @@ -1721,7 +1725,7 @@ async_initable_init_first (GAsyncInitable *initable) NULL, /* member */ proxy->priv->object_path, NULL, /* arg0 */ - G_DBUS_SIGNAL_FLAGS_NONE, + signal_flags, on_signal_received, weak_ref_new (G_OBJECT (proxy)), (GDestroyNotify) weak_ref_free); @@ -1737,7 +1741,7 @@ async_initable_init_first (GAsyncInitable *initable) "NameOwnerChanged", /* signal name */ "/org/freedesktop/DBus", /* path */ proxy->priv->name, /* arg0 */ - G_DBUS_SIGNAL_FLAGS_NONE, + signal_flags, on_name_owner_changed, weak_ref_new (G_OBJECT (proxy)), (GDestroyNotify) weak_ref_free); diff --git a/gio/gioenums.h b/gio/gioenums.h index d81ada416..756aed7a1 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -1021,6 +1021,9 @@ typedef enum * do not ask the bus to launch an owner during proxy initialization, but allow it to be * autostarted by a method call. This flag is only meaningful in proxies for well-known names, * and only if %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is not also specified. + * @G_DBUS_PROXY_FLAGS_NO_MATCH_RULE: Don't actually send the AddMatch D-Bus + * call for this signal subscription. This gives you more control + * over which match rules you add (but you must add them manually). (Since: 2.70) * * Flags used when constructing an instance of a #GDBusProxy derived class. * @@ -1033,7 +1036,8 @@ typedef enum G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1), G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2), G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES = (1<<3), - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION = (1<<4) + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION = (1<<4), + G_DBUS_PROXY_FLAGS_NO_MATCH_RULE GLIB_AVAILABLE_ENUMERATOR_IN_2_70 = (1<<5) } GDBusProxyFlags; /** diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c index 7e619c2ac..a16d70c20 100644 --- a/gio/tests/gdbus-proxy.c +++ b/gio/tests/gdbus-proxy.c @@ -701,7 +701,6 @@ test_basic (GDBusProxy *proxy) connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); g_assert_true (g_dbus_proxy_get_connection (proxy) == connection); - g_assert_cmpint (g_dbus_proxy_get_flags (proxy), ==, G_DBUS_PROXY_FLAGS_NONE); g_assert_null (g_dbus_proxy_get_interface_info (proxy)); g_assert_cmpstr (g_dbus_proxy_get_name (proxy), ==, "com.example.TestService"); g_assert_cmpstr (g_dbus_proxy_get_object_path (proxy), ==, "/com/example/TestObject"); @@ -720,7 +719,7 @@ test_basic (GDBusProxy *proxy) g_assert_true (conn == connection); g_assert_null (info); - g_assert_cmpint (flags, ==, G_DBUS_PROXY_FLAGS_NONE); + g_assert_cmpint (flags, ==, g_dbus_proxy_get_flags (proxy)); g_assert_cmpstr (name, ==, "com.example.TestService"); g_assert_cmpstr (path, ==, "/com/example/TestObject"); g_assert_cmpstr (interface, ==, "com.example.Frob"); @@ -763,7 +762,7 @@ kill_test_service (GDBusConnection *connection) } static void -test_proxy (void) +test_proxy_with_flags (GDBusProxyFlags flags) { GDBusProxy *proxy; GDBusConnection *connection; @@ -777,7 +776,7 @@ test_proxy (void) g_assert_no_error (error); error = NULL; proxy = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_NONE, + flags, NULL, /* GDBusInterfaceInfo */ "com.example.TestService", /* name */ "/com/example/TestObject", /* object path */ @@ -809,6 +808,12 @@ test_proxy (void) g_object_unref (connection); } +static void +test_proxy (void) +{ + test_proxy_with_flags (G_DBUS_PROXY_FLAGS_NONE); +} + /* ---------------------------------------------------------------------------------------------------- */ static void @@ -930,6 +935,58 @@ test_wellknown_noauto (void) g_source_remove (id); } +typedef enum { + ADD_MATCH, + REMOVE_MATCH, +} AddOrRemove; + +static void +add_or_remove_match_rule (GDBusConnection *connection, + AddOrRemove add_or_remove, + GVariant *match_rule) +{ + GDBusMessage *message = NULL; + GError *error = NULL; + + message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */ + "/org/freedesktop/DBus", /* path */ + "org.freedesktop.DBus", /* interface */ + (add_or_remove == ADD_MATCH) ? "AddMatch" : "RemoveMatch"); + g_dbus_message_set_body (message, match_rule); + g_dbus_connection_send_message (connection, + message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, + &error); + g_assert_no_error (error); + g_clear_object (&message); +} + +static void +test_proxy_no_match_rule (void) +{ + GDBusConnection *connection = NULL; + GVariant *match_rule = NULL; + + g_test_summary ("Test that G_DBUS_PROXY_FLAGS_NO_MATCH_RULE works"); + g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1109"); + + connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + + /* Add a custom match rule which matches everything. */ + match_rule = g_variant_ref_sink (g_variant_new ("(s)", "type='signal'")); + add_or_remove_match_rule (connection, ADD_MATCH, match_rule); + + /* Run the tests. */ + test_proxy_with_flags (G_DBUS_PROXY_FLAGS_NO_MATCH_RULE); + + /* Remove the match rule again. */ + add_or_remove_match_rule (connection, REMOVE_MATCH, match_rule); + + g_clear_pointer (&match_rule, g_variant_unref); + g_clear_object (&connection); +} + int main (int argc, char *argv[]) @@ -950,6 +1007,7 @@ main (int argc, g_test_add_func ("/gdbus/proxy/no-properties", test_no_properties); g_test_add_func ("/gdbus/proxy/wellknown-noauto", test_wellknown_noauto); g_test_add_func ("/gdbus/proxy/async", test_async); + g_test_add_func ("/gdbus/proxy/no-match-rule", test_proxy_no_match_rule); ret = session_bus_run(); |