summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libgupnp/gupnp-context-filter.c52
-rw-r--r--tests/meson.build2
-rw-r--r--tests/test-context-filter.c287
3 files changed, 315 insertions, 26 deletions
diff --git a/libgupnp/gupnp-context-filter.c b/libgupnp/gupnp-context-filter.c
index 4770689..4b533e1 100644
--- a/libgupnp/gupnp-context-filter.c
+++ b/libgupnp/gupnp-context-filter.c
@@ -99,9 +99,13 @@ gupnp_context_filter_set_property (GObject *object,
case PROP_ENABLED:
priv->enabled = g_value_get_boolean (value);
break;
- case PROP_ENTRIES:
- priv->entries = g_value_get_pointer (value);
- break;
+ case PROP_ENTRIES: {
+ GList *entries = g_value_get_pointer (value);
+ g_hash_table_remove_all (priv->entries);
+ for (GList *it = entries; it != NULL; it = g_list_next (it)) {
+ g_hash_table_add (priv->entries, g_strdup (it->data));
+ }
+ } break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -125,7 +129,8 @@ gupnp_context_filter_get_property (GObject *object,
g_value_set_boolean (value, priv->enabled);
break;
case PROP_ENTRIES:
- g_value_set_pointer (value, priv->entries);
+ g_value_set_pointer (value,
+ gupnp_context_filter_get_entries (list));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -230,8 +235,10 @@ gupnp_context_filter_set_enabled (GUPnPContextFilter *context_filter,
g_return_if_fail (GUPNP_IS_CONTEXT_FILTER (context_filter));
priv = gupnp_context_filter_get_instance_private (context_filter);
- priv->enabled = enable;
- g_object_notify (G_OBJECT (context_filter), "enabled");
+ if (priv->enabled != enable) {
+ priv->enabled = enable;
+ g_object_notify (G_OBJECT (context_filter), "enabled");
+ }
}
/**
@@ -275,7 +282,7 @@ gupnp_context_filter_is_empty (GUPnPContextFilter *context_filter)
priv = gupnp_context_filter_get_instance_private (context_filter);
- return (priv->entries == NULL);
+ return (g_hash_table_size (priv->entries) == 0);
}
/**
@@ -327,12 +334,20 @@ gupnp_context_filter_add_entryv (GUPnPContextFilter *context_filter,
gchar **entries)
{
gchar *const *iter = entries;
+ GUPnPContextFilterPrivate *priv;
g_return_if_fail (GUPNP_IS_CONTEXT_FILTER (context_filter));
g_return_if_fail ((entries != NULL));
- for (; *iter != NULL; iter++)
- gupnp_context_filter_add_entry (context_filter, *iter);
+ priv = gupnp_context_filter_get_instance_private (context_filter);
+ gboolean changed = FALSE;
+ for (; *iter != NULL; iter++) {
+ if (g_hash_table_add (priv->entries, g_strdup (*iter)))
+ changed = TRUE;
+ }
+
+ if (changed)
+ g_object_notify (G_OBJECT (context_filter), "entries");
}
/**
@@ -375,7 +390,6 @@ gupnp_context_filter_remove_entry (GUPnPContextFilter *context_filter,
*
* Return value: (element-type utf8) (transfer container)(nullable): a #GList of entries
* used to filter networks, interfaces,... or %NULL.
- * Do not modify or free the list nor its elements.
*
* Since: 1.4.0
**/
@@ -434,11 +448,9 @@ gupnp_context_filter_check_context (GUPnPContextFilter *context_filter,
GUPnPContext *context)
{
GSSDPClient *client;
- GList *l;
const char *interface;
const char *host_ip;
const char *network;
- gboolean match = FALSE;
GUPnPContextFilterPrivate *priv;
g_return_val_if_fail (GUPNP_IS_CONTEXT_FILTER (context_filter), FALSE);
@@ -451,17 +463,7 @@ gupnp_context_filter_check_context (GUPnPContextFilter *context_filter,
host_ip = gssdp_client_get_host_ip (client);
network = gssdp_client_get_network (client);
- GList *head = l = g_hash_table_get_keys (priv->entries);
-
- while (l && !match) {
- match = (interface && !strcmp (l->data, interface)) ||
- (host_ip && !strcmp (l->data, host_ip)) ||
- (network && !strcmp (l->data, network));
-
- l = l->next;
- }
-
- g_list_free (head);
-
- return match;
+ return g_hash_table_contains (priv->entries, interface) ||
+ g_hash_table_contains (priv->entries, host_ip) ||
+ g_hash_table_contains (priv->entries, network);
}
diff --git a/tests/meson.build b/tests/meson.build
index deae7ba..3e656d2 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,4 +1,4 @@
-foreach program : ['context', 'bugs', 'service', 'acl', 'service-proxy']
+foreach program : ['context', 'bugs', 'service', 'acl', 'service-proxy', 'context-filter']
test(
program,
executable(
diff --git a/tests/test-context-filter.c b/tests/test-context-filter.c
new file mode 100644
index 0000000..37ba14b
--- /dev/null
+++ b/tests/test-context-filter.c
@@ -0,0 +1,287 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Jens Georg
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <config.h>
+
+#include "libgupnp/gupnp-context-filter.h"
+
+#include <glib-object.h>
+#include <glib.h>
+
+void
+test_context_filter_construction ()
+{
+ // Default-created filter. No entries, disabled.
+ GUPnPContextFilter *filter =
+ g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL);
+
+ g_assert_null (gupnp_context_filter_get_entries (filter));
+ g_assert (gupnp_context_filter_is_empty (filter));
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+
+ g_object_unref (filter);
+
+ // Filter that is enabled since construction
+ filter =
+ g_object_new (GUPNP_TYPE_CONTEXT_FILTER, "enabled", TRUE, NULL);
+
+ g_assert_null (gupnp_context_filter_get_entries (filter));
+ g_assert (gupnp_context_filter_is_empty (filter));
+ g_assert (gupnp_context_filter_get_enabled (filter));
+
+ g_object_unref (filter);
+
+ GList *entries = NULL;
+ entries = g_list_prepend (entries, g_strdup ("eth0"));
+ entries = g_list_prepend (entries, g_strdup ("::1"));
+ entries = g_list_prepend (entries, g_strdup ("127.0.0.1"));
+ entries = g_list_prepend (entries, g_strdup ("Free WiFi!"));
+
+ filter = g_object_new (GUPNP_TYPE_CONTEXT_FILTER,
+ "entries",
+ entries,
+ NULL);
+
+ g_list_free_full (entries, g_free);
+
+ entries = gupnp_context_filter_get_entries (filter);
+ g_assert_cmpint (g_list_length (entries), ==, 4);
+ GList *it = entries;
+ while (it != NULL) {
+ g_assert (g_str_equal ("eth0", it->data) ||
+ g_str_equal ("::1", it->data) ||
+ g_str_equal ("127.0.0.1", it->data) ||
+ g_str_equal ("Free WiFi!", it->data));
+ it = g_list_next (it);
+ }
+
+ g_list_free (entries);
+
+ g_object_unref (filter);
+}
+
+void
+on_entry (GObject *object, GParamSpec *psec, gpointer user_data)
+{
+ int *count = user_data;
+ *count = *count + 1;
+}
+
+void
+test_context_filter_entry_management ()
+{
+ int entry_change_count = 0;
+
+ // Default-created filter. No entries, disabled.
+ GUPnPContextFilter *filter =
+ g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL);
+
+ g_assert_null (gupnp_context_filter_get_entries (filter));
+ g_assert (gupnp_context_filter_is_empty (filter));
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+
+ g_signal_connect (filter,
+ "notify::entries",
+ G_CALLBACK (on_entry),
+ &entry_change_count);
+ g_assert_cmpint (entry_change_count, ==, 0);
+
+ entry_change_count = 0;
+ gupnp_context_filter_add_entry (filter, "eth0");
+
+ // Just adding an entry should not trigger the filter
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_false (gupnp_context_filter_is_empty (filter));
+ g_assert_cmpint (entry_change_count, ==, 1);
+
+ GList *entries = gupnp_context_filter_get_entries (filter);
+ g_assert_cmpstr (entries->data, ==, "eth0");
+
+ g_list_free (entries);
+
+ entry_change_count = 0;
+ gupnp_context_filter_add_entry (filter, "Free WiFi!");
+
+ // Just adding an entry should not trigger the filter
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_false (gupnp_context_filter_is_empty (filter));
+ g_assert_cmpint (entry_change_count, ==, 1);
+
+ entries = gupnp_context_filter_get_entries (filter);
+
+ g_assert_cmpstr (entries->data, ==, "eth0");
+
+ GList *it = entries;
+ while (it != NULL) {
+ g_assert (g_str_equal ("eth0", it->data) ||
+ g_str_equal ("Free WiFi!", it->data));
+ it = g_list_next (it);
+ }
+
+ g_list_free (entries);
+
+ entry_change_count = 0;
+ gupnp_context_filter_remove_entry (filter, "eth0");
+
+ // Just adding an entry should not trigger the filter
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_false (gupnp_context_filter_is_empty (filter));
+ g_assert_cmpint (entry_change_count, ==, 1);
+ entries = gupnp_context_filter_get_entries (filter);
+
+ g_assert_cmpstr (entries->data, ==, "Free WiFi!");
+ g_list_free (entries);
+
+ entry_change_count = 0;
+ gupnp_context_filter_remove_entry (filter, "Free WiFi!");
+
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert (gupnp_context_filter_is_empty (filter));
+ g_assert_cmpint (entry_change_count, ==, 1);
+ g_assert_null (gupnp_context_filter_get_entries (filter));
+
+ g_list_free (entries);
+
+ {
+ char *entryv[] = { "eth0", "eth1", "eth2", "eth3", NULL };
+
+ entry_change_count = 0;
+ gupnp_context_filter_add_entryv (filter, entryv);
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_false (gupnp_context_filter_is_empty (filter));
+ g_assert_cmpint (entry_change_count, ==, 1);
+ }
+
+ // Re-adding the same entries should not cause any notification
+ {
+ char *entryv[] = { "eth0", "eth3", NULL };
+
+ entry_change_count = 0;
+ gupnp_context_filter_add_entryv (filter, entryv);
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_false (gupnp_context_filter_is_empty (filter));
+ g_assert_cmpint (entry_change_count, ==, 0);
+ }
+
+ entry_change_count = 0;
+ gupnp_context_filter_clear (filter);
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_true (gupnp_context_filter_is_empty (filter));
+ g_assert_cmpint (entry_change_count, ==, 1);
+
+ g_object_unref (filter);
+}
+
+void
+on_enabled (GObject *object, GParamSpec *psec, gpointer user_data)
+{
+ int *count = user_data;
+ *count = *count + 1;
+}
+
+void
+test_context_filter_enable_disable ()
+{
+ int enabled_count = 0;
+
+ // Default-created filter. No entries, disabled.
+ GUPnPContextFilter *filter =
+ g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL);
+
+ g_signal_connect (filter,
+ "notify::enabled",
+ G_CALLBACK (on_enabled),
+ &enabled_count);
+
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+
+ enabled_count = 0;
+ gupnp_context_filter_set_enabled (filter, FALSE);
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_cmpint (enabled_count, ==, 0);
+
+ enabled_count = 0;
+ gupnp_context_filter_set_enabled (filter, TRUE);
+ g_assert (gupnp_context_filter_get_enabled (filter));
+ g_assert_cmpint (enabled_count, ==, 1);
+
+ enabled_count = 0;
+ gupnp_context_filter_set_enabled (filter, TRUE);
+ g_assert (gupnp_context_filter_get_enabled (filter));
+
+ g_assert_cmpint (enabled_count, ==, 0);
+ enabled_count = 0;
+ gupnp_context_filter_set_enabled (filter, FALSE);
+ g_assert_false (gupnp_context_filter_get_enabled (filter));
+ g_assert_cmpint (enabled_count, ==, 1);
+
+ g_object_unref (filter);
+}
+
+void
+test_context_filter_match ()
+{
+ // Default-created filter. No entries, disabled.
+ GUPnPContextFilter *filter =
+ g_object_new (GUPNP_TYPE_CONTEXT_FILTER, NULL);
+
+ GUPnPContext *context = g_object_new (GUPNP_TYPE_CONTEXT,
+ "host-ip",
+ "127.0.0.1",
+ "interface",
+ "lo",
+ "network",
+ "FreeWiFi",
+ NULL);
+
+ g_assert_false (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, TRUE);
+ g_assert_false (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, FALSE);
+
+ g_assert (gupnp_context_filter_add_entry (filter, "FreeWiFi"));
+ g_assert (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, TRUE);
+ g_assert (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, FALSE);
+ gupnp_context_filter_remove_entry (filter, "FreeWiFi");
+
+ g_assert (gupnp_context_filter_add_entry (filter, "lo"));
+ g_assert (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, TRUE);
+ g_assert (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, FALSE);
+ gupnp_context_filter_remove_entry (filter, "lo");
+
+ g_assert (gupnp_context_filter_add_entry (filter, "127.0.0.1"));
+ g_assert (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, TRUE);
+ g_assert (gupnp_context_filter_check_context (filter, context));
+ gupnp_context_filter_set_enabled (filter, FALSE);
+ gupnp_context_filter_remove_entry (filter, "127.0.0.1");
+
+ g_object_unref (context);
+
+ g_object_unref (filter);
+}
+
+int
+main (int argc, char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/context-filter/construction",
+ test_context_filter_construction);
+
+ g_test_add_func ("/context-filter/entry-management",
+ test_context_filter_entry_management);
+
+ g_test_add_func ("/context-filter/enable-disable",
+ test_context_filter_enable_disable);
+
+ g_test_add_func ("/context-filter/match", test_context_filter_match);
+
+ return g_test_run ();
+}