[gupnp] Use GUPnPWhiteList in GUPnPContextManager



commit 37554c2b9279dc13ffaf2224fae993e82094a8f2
Author: Ludovic Ferrandis <ludovic ferrandis intel com>
Date:   Wed Aug 7 15:31:59 2013 +0200

    Use GUPnPWhiteList in GUPnPContextManager
    
    GUPnPContextManager is now using GUPnPWhiteList to filter networks
    
    Add test program
    
    https://bugzilla.gnome.org/show_bug.cgi?id=705712

 libgupnp/gupnp-context-manager.c |  233 ++++++++++++++++++++++++++++++++--
 libgupnp/gupnp-context-manager.h |    5 +
 tests/Makefile.am                |    8 +-
 tests/test-white-list.c          |  262 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 495 insertions(+), 13 deletions(-)
---
diff --git a/libgupnp/gupnp-context-manager.c b/libgupnp/gupnp-context-manager.c
index 4bf3cee..4e0a84a 100644
--- a/libgupnp/gupnp-context-manager.c
+++ b/libgupnp/gupnp-context-manager.c
@@ -1,9 +1,11 @@
 /*
  * Copyright (C) 2009 Nokia Corporation.
  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
+ * Copyright (C) 2013 Intel Corporation.
  *
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  *         Jorn Baayen <jorn openedhand com>
+ *         Ludovic Ferrandis <ludovic ferrandis intel com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -55,12 +57,16 @@ struct _GUPnPContextManagerPrivate {
         GUPnPContextManager *impl;
 
         GList *objects; /* control points and root devices */
+        GList *blacklisted; /* Blacklisted Context */
+
+        GUPnPWhiteList *white_list;
 };
 
 enum {
         PROP_0,
         PROP_MAIN_CONTEXT,
         PROP_PORT,
+        PROP_WHITE_LIST
 };
 
 enum {
@@ -72,11 +78,40 @@ enum {
 static guint signals[SIGNAL_LAST];
 
 static void
+on_context_available (GUPnPContextManager    *manager,
+                      GUPnPContext           *context,
+                      G_GNUC_UNUSED gpointer *user_data)
+{
+        GUPnPWhiteList *white_list;
+
+        white_list = manager->priv->white_list;
+
+        /* Try to catch the notification, only if the white list
+         * is enabled, not empty and the context doesn't match */
+        if (!gupnp_white_list_is_empty (white_list) &&
+            gupnp_white_list_is_enabled (white_list) &&
+            !gupnp_white_list_check_context (white_list, context)) {
+                /* If the conext doesn't match, block the notification
+                 * and disable the context */
+                g_signal_stop_emission_by_name (manager, "context-available");
+
+                /* Make sure we don't send anything on now blocked network */
+                g_object_set (context, "active", FALSE, NULL);
+
+                /* Save it in case we need to re-enable it */
+                manager->priv->blacklisted = g_list_prepend (
+                                                manager->priv->blacklisted,
+                                                g_object_ref (context));
+        }
+}
+
+static void
 on_context_unavailable (GUPnPContextManager    *manager,
                         GUPnPContext           *context,
                         G_GNUC_UNUSED gpointer *user_data)
 {
         GList *l;
+        GList *black;
 
         /* Make sure we don't send anything on now unavailable network */
         g_object_set (context, "active", FALSE, NULL);
@@ -113,6 +148,119 @@ on_context_unavailable (GUPnPContextManager    *manager,
                         l = l->next;
                 }
         }
+
+        black = g_list_find (manager->priv->blacklisted, context);
+
+        if (black != NULL) {
+                g_signal_stop_emission_by_name (manager, "context-unavailable");
+
+                g_object_unref (black->data);
+                manager->priv->blacklisted =
+                        g_list_delete_link (manager->priv->blacklisted, black);
+        }
+}
+
+static void
+gupnp_context_manager_filter_context (GUPnPWhiteList *white_list,
+                                      GUPnPContextManager *manager,
+                                      gboolean check)
+{
+        GList *next;
+        GList *obj;
+        GList *blk;
+        gboolean match;
+        GUPnPContext *context;
+        GSSDPResourceBrowser *browser;
+
+        obj = manager->priv->objects;
+        blk = manager->priv->blacklisted;
+
+        while (obj != NULL) {
+                if (!GUPNP_IS_CONTROL_POINT (obj->data))
+                        continue;
+
+                /* If the white list is empty, treat it as disabled */
+                if (check) {
+                        /* Filter out context */
+                        context = gupnp_control_point_get_context (obj->data);
+                        match = gupnp_white_list_check_context (white_list,
+                                                                context);
+                } else {
+                        /* Re-activate all context, if needed */
+                        match = TRUE;
+                }
+
+                browser = GSSDP_RESOURCE_BROWSER (obj->data);
+                gssdp_resource_browser_set_active (browser, match);
+
+                if (match)
+                        (void) gssdp_resource_browser_rescan (browser);
+
+                obj = obj->next;
+        }
+
+        while (blk != NULL) {
+                /* If the white list is empty, treat it as disabled */
+                if (check)
+                        /* Filter out context */
+                        match = gupnp_white_list_check_context (white_list,
+                                                                blk->data);
+                else
+                        /* Re-activate all context, if needed */
+                        match = TRUE;
+
+                if (!match) {
+                        blk = blk->next;
+                        continue;
+                }
+
+                next = blk->next;
+                g_object_set (blk->data, "active", TRUE, NULL);
+
+                g_signal_emit_by_name (manager, "context-available", blk->data);
+
+                g_object_unref (blk->data);
+                manager->priv->blacklisted = g_list_delete_link (
+                                                manager->priv->blacklisted,
+                                                blk);
+                blk = next;
+        }
+}
+
+static void
+on_white_list_change_cb (GUPnPWhiteList *white_list,
+                         GParamSpec *pspec,
+                         gpointer user_data)
+{
+        GUPnPContextManager *manager = GUPNP_CONTEXT_MANAGER (user_data);
+        gboolean enabled;
+        gboolean is_empty;
+
+        enabled = gupnp_white_list_is_enabled (white_list);
+        is_empty = gupnp_white_list_is_empty (white_list);
+
+        if (enabled)
+                gupnp_context_manager_filter_context (white_list,
+                                                      manager,
+                                                      !is_empty);
+}
+
+static void
+on_white_list_enabled_cb (GUPnPWhiteList *white_list,
+                          GParamSpec *pspec,
+                          gpointer user_data)
+{
+        GUPnPContextManager *manager = GUPNP_CONTEXT_MANAGER (user_data);
+        gboolean enabled;
+        gboolean is_empty;
+
+        enabled = gupnp_white_list_is_enabled (white_list);
+        is_empty = gupnp_white_list_is_empty (white_list);
+
+        if (!is_empty)
+                gupnp_context_manager_filter_context (white_list,
+                                                      manager,
+                                                      enabled);
 }
 
 static void
@@ -122,6 +270,14 @@ gupnp_context_manager_init (GUPnPContextManager *manager)
                 G_TYPE_INSTANCE_GET_PRIVATE (manager,
                                              GUPNP_TYPE_CONTEXT_MANAGER,
                                              GUPnPContextManagerPrivate);
+
+        manager->priv->white_list = gupnp_white_list_new ();
+
+        g_signal_connect_after (manager->priv->white_list, "notify::entries",
+                                G_CALLBACK (on_white_list_change_cb), manager);
+
+        g_signal_connect_after (manager->priv->white_list, "notify::enabled",
+                                G_CALLBACK (on_white_list_enabled_cb), manager);
 }
 
 static void
@@ -174,6 +330,9 @@ gupnp_context_manager_get_property (GObject    *object,
                 g_value_set_pointer (value,
                                      g_main_context_get_thread_default ());
                 break;
+        case PROP_WHITE_LIST:
+                g_value_set_object (value, manager->priv->white_list);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
                 break;
@@ -184,13 +343,29 @@ static void
 gupnp_context_manager_dispose (GObject *object)
 {
         GUPnPContextManager *manager;
+        GUPnPWhiteList *wl;
         GObjectClass *object_class;
 
         manager = GUPNP_CONTEXT_MANAGER (object);
+        wl = manager->priv->white_list;
+
+        g_signal_handlers_disconnect_by_func (wl,
+                                              on_white_list_enabled_cb,
+                                              manager);
 
-        g_list_foreach (manager->priv->objects, (GFunc) g_object_unref, NULL);
-        g_list_free (manager->priv->objects);
+        g_signal_handlers_disconnect_by_func (wl,
+                                              on_white_list_change_cb,
+                                              NULL);
+
+        g_list_free_full (manager->priv->objects, g_object_unref);
         manager->priv->objects = NULL;
+        g_list_free_full (manager->priv->blacklisted, g_object_unref);
+        manager->priv->blacklisted = NULL;
+
+        if (wl) {
+                g_object_unref (wl);
+                manager->priv->white_list = NULL;
+        }
 
         /* Call super */
         object_class = G_OBJECT_CLASS (gupnp_context_manager_parent_class);
@@ -250,7 +425,24 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass)
                                     G_PARAM_STATIC_NICK |
                                     G_PARAM_STATIC_BLURB));
 
-        /**
+         /**
+         * GUPnPContextManager:white-list:
+         *
+         * The white list to use.
+         **/
+        g_object_class_install_property
+                (object_class,
+                 PROP_WHITE_LIST,
+                 g_param_spec_object ("white-list",
+                                      "White List",
+                                      "The white list to use",
+                                      GUPNP_TYPE_WHITE_LIST,
+                                      G_PARAM_READABLE |
+                                      G_PARAM_STATIC_NAME |
+                                      G_PARAM_STATIC_NICK |
+                                      G_PARAM_STATIC_BLURB));
+
+       /**
          * GUPnPContextManager::context-available:
          * @context_manager: The #GUPnPContextManager that received the signal
          * @context: The now available #GUPnPContext
@@ -259,15 +451,15 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass)
          *
          **/
         signals[CONTEXT_AVAILABLE] =
-                g_signal_new ("context-available",
-                              GUPNP_TYPE_CONTEXT_MANAGER,
-                              G_SIGNAL_RUN_LAST,
-                              0,
-                              NULL, NULL,
-                              g_cclosure_marshal_VOID__OBJECT,
-                              G_TYPE_NONE,
-                              1,
-                              GUPNP_TYPE_CONTEXT);
+                g_signal_new_class_handler ("context-available",
+                                            GUPNP_TYPE_CONTEXT_MANAGER,
+                                            G_SIGNAL_RUN_FIRST,
+                                            G_CALLBACK (on_context_available),
+                                            NULL, NULL,
+                                            g_cclosure_marshal_VOID__OBJECT,
+                                            G_TYPE_NONE,
+                                            1,
+                                            GUPNP_TYPE_CONTEXT);
 
         /**
          * GUPnPContextManager::context-unavailable:
@@ -467,3 +659,20 @@ gupnp_context_manager_get_port (GUPnPContextManager *manager)
 
         return manager->priv->port;
 }
+
+/**
+ * gupnp_context_manager_get_white_list:
+ * @manager: A #GUPnPContextManager
+ *
+ * Get the #GUPnPWhiteList associated with @manager.
+ *
+ * Returns: (transfer none):  The #GUPnPWhiteList asssociated with this
+ * context manager.
+ */
+GUPnPWhiteList *
+gupnp_context_manager_get_white_list (GUPnPContextManager *manager)
+{
+        g_return_val_if_fail (GUPNP_IS_CONTEXT_MANAGER (manager), NULL);
+
+        return manager->priv->white_list;
+}
diff --git a/libgupnp/gupnp-context-manager.h b/libgupnp/gupnp-context-manager.h
index 1e04b4c..6124ea9 100644
--- a/libgupnp/gupnp-context-manager.h
+++ b/libgupnp/gupnp-context-manager.h
@@ -26,6 +26,7 @@
 
 #include <glib.h>
 #include "gupnp.h"
+#include "gupnp-white-list.h"
 
 G_BEGIN_DECLS
 
@@ -105,6 +106,10 @@ gupnp_context_manager_manage_root_device
 
 guint
 gupnp_context_manager_get_port         (GUPnPContextManager *manager);
+
+GUPnPWhiteList *
+gupnp_context_manager_get_white_list   (GUPnPContextManager *manager);
+
 G_END_DECLS
 
 #endif /* __GUPNP_CONTEXT_MANAGER_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4c70f1a..8209270 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -5,7 +5,8 @@ AM_CFLAGS = $(LIBGUPNP_CFLAGS) $(GTHREAD_CFLAGS) -I$(top_srcdir)
 noinst_PROGRAMS = test-browsing      \
                  test-proxy         \
                  test-server        \
-                 test-introspection
+                 test-introspection \
+                 test-white-list
 
 test_browsing_SOURCES = test-browsing.c
 test_browsing_LDADD   = $(top_builddir)/libgupnp/libgupnp-1.0.la \
@@ -28,6 +29,11 @@ test_server_LDADD   = $(top_builddir)/libgupnp/libgupnp-1.0.la \
                      $(LIBGUPNP_LIBS)
 test_server_LDFLAGS = -export-dynamic
 
+test_white_list_SOURCES = test-white-list.c
+test_white_list_LDADD   = $(top_builddir)/libgupnp/libgupnp-1.0.la \
+                         $(GTHREAD_LIBS) \
+                         $(LIBGUPNP_LIBS)
+
 CLEANFILES = $(BUILT_SOURCES)
 DISTCLEANFILES = $(BUILT_SOURCES)
 MAINTAINERCLEANFILES = Makefile.in $(BUILT_SOURCES)
diff --git a/tests/test-white-list.c b/tests/test-white-list.c
new file mode 100644
index 0000000..ed04d48
--- /dev/null
+++ b/tests/test-white-list.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * Author: Ludovic Ferrandis <ludovic ferrandis intel com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <libgupnp/gupnp-control-point.h>
+#include <libgupnp/gupnp-context-manager.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <signal.h>
+#include <glib.h>
+
+GMainLoop *main_loop;
+
+static void
+interrupt_signal_handler (G_GNUC_UNUSED int signum)
+{
+        g_main_loop_quit (main_loop);
+}
+
+static void
+device_proxy_available_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
+                           GUPnPDeviceProxy                *proxy)
+{
+        const char *type, *location;
+
+        type = gupnp_device_info_get_device_type (GUPNP_DEVICE_INFO (proxy));
+        location = gupnp_device_info_get_location (GUPNP_DEVICE_INFO (proxy));
+
+        g_print ("Device available:\n");
+        g_print ("\ttype:     %s\n", type);
+        g_print ("\tlocation: %s\n", location);
+}
+
+static void
+device_proxy_unavailable_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
+                             GUPnPDeviceProxy                *proxy)
+{
+        const char *type, *location;
+
+        type = gupnp_device_info_get_device_type (GUPNP_DEVICE_INFO (proxy));
+        location = gupnp_device_info_get_location (GUPNP_DEVICE_INFO (proxy));
+
+        g_print ("Device unavailable:\n");
+        g_print ("\ttype:     %s\n", type);
+        g_print ("\tlocation: %s\n", location);
+}
+
+static void
+service_proxy_available_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
+                            GUPnPServiceProxy               *proxy)
+{
+        const char *type, *location;
+
+        type = gupnp_service_info_get_service_type (GUPNP_SERVICE_INFO (proxy));
+        location = gupnp_service_info_get_location (GUPNP_SERVICE_INFO (proxy));
+
+        g_print ("Service available:\n");
+        g_print ("\ttype:     %s\n", type);
+        g_print ("\tlocation: %s\n", location);
+}
+
+static void
+service_proxy_unavailable_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
+                              GUPnPServiceProxy               *proxy)
+{
+        const char *type, *location;
+
+        type = gupnp_service_info_get_service_type (GUPNP_SERVICE_INFO (proxy));
+        location = gupnp_service_info_get_location (GUPNP_SERVICE_INFO (proxy));
+
+        g_print ("Service unavailable:\n");
+        g_print ("\ttype:     %s\n", type);
+        g_print ("\tlocation: %s\n", location);
+}
+
+static void
+context_available_cb(GUPnPContextManager *context_manager,
+                     GUPnPContext *context,
+                     gpointer user_data)
+{
+        GUPnPControlPoint *cp;
+        GSSDPClient *client = GSSDP_CLIENT(context);
+
+        g_print ("Context Available:\n");
+        g_print ("\tServer ID:     %s\n", gssdp_client_get_server_id (client));
+        g_print ("\tInterface:     %s\n", gssdp_client_get_interface (client));
+        g_print ("\tHost IP  :     %s\n", gssdp_client_get_host_ip (client));
+        g_print ("\tNetwork  :     %s\n", gssdp_client_get_network (client));
+        g_print ("\tActive   :     %s\n", gssdp_client_get_active (client)? "TRUE" : "FALSE");
+
+
+        /* We're interested in everything */
+        cp = gupnp_control_point_new (context, "ssdp:all");
+
+        g_signal_connect (cp,
+                          "device-proxy-available",
+                          G_CALLBACK (device_proxy_available_cb),
+                          NULL);
+        g_signal_connect (cp,
+                          "device-proxy-unavailable",
+                          G_CALLBACK (device_proxy_unavailable_cb),
+                          NULL);
+        g_signal_connect (cp,
+                          "service-proxy-available",
+                          G_CALLBACK (service_proxy_available_cb),
+                          NULL);
+        g_signal_connect (cp,
+                          "service-proxy-unavailable",
+                          G_CALLBACK (service_proxy_unavailable_cb),
+                          NULL);
+
+        gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
+        gupnp_context_manager_manage_control_point(context_manager, cp);
+        g_object_unref(cp);
+}
+
+static void
+context_unavailable_cb(GUPnPContextManager *context_manager,
+                       GUPnPContext *context,
+                       gpointer user_data)
+{
+        GSSDPClient *client = GSSDP_CLIENT(context);
+
+        g_print ("Context Unavailable:\n");
+        g_print ("\tServer ID:     %s\n", gssdp_client_get_server_id (client));
+        g_print ("\tInterface:     %s\n", gssdp_client_get_interface (client));
+        g_print ("\tHost IP  :     %s\n", gssdp_client_get_host_ip (client));
+        g_print ("\tNetwork  :     %s\n", gssdp_client_get_network (client));
+        g_print ("\tActive   :     %s\n", gssdp_client_get_active (client)? "TRUE" : "FALSE");
+}
+
+static gboolean
+change_white_list(gpointer user_data)
+{
+        GUPnPContextManager *context_manager = user_data;
+        GUPnPWhiteList *white_list;
+        static int tomato = 0;
+
+        g_print ("\nChange White List:\n");
+        g_print ("\t Action number %d:\n", tomato);
+
+        white_list = gupnp_context_manager_get_white_list(context_manager);
+
+        switch (tomato) {
+        case 0:
+                g_print ("\t Add Entry eth0\n\n");
+                gupnp_white_list_add_entry(white_list, "eth0");
+                break;
+        case 1:
+                g_print ("\t Enable WL\n\n");
+                gupnp_white_list_enable(white_list, TRUE);
+                break;
+        case 2:
+                g_print ("\t Add Entry 127.0.0.1\n\n");
+                gupnp_white_list_add_entry(white_list, "127.0.0.1");
+                break;
+        case 3:
+                g_print ("\t Clear all entries\n\n");
+                gupnp_white_list_clear(white_list);
+                break;
+        case 4:
+                g_print ("\t Add Entry wlan2\n\n");
+                gupnp_white_list_add_entry(white_list, "wlan2");
+                break;
+        case 5:
+                g_print ("\t Disable WL\n\n");
+                gupnp_white_list_enable(white_list, FALSE);
+                break;
+        case 6:
+                g_print ("\t Enable WL\n\n");
+                gupnp_white_list_enable(white_list, TRUE);
+                break;
+        case 7:
+                g_print ("\t Connect to wlan0\n\n");
+                g_timeout_add_seconds (35, change_white_list, context_manager);
+                break;
+        case 8:
+                g_print ("\t Add Entry wlan0\n\n");
+                gupnp_white_list_add_entry(white_list, "wlan0");
+                break;
+        //~ case 8:
+                //~ g_print ("\t Enable WL\n");
+                //~ gupnp_white_list_enable(white_list, FALSE);
+                //~ break;
+        default:
+                break;
+        }
+
+        tomato++;
+
+        return (tomato < 9) && (tomato != 8);
+}
+
+int
+main (G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
+{
+        GError *error;
+        GUPnPContextManager *cm;
+        guint id;
+#ifndef G_OS_WIN32
+        struct sigaction sig_action;
+#endif /* G_OS_WIN32 */
+
+#if !GLIB_CHECK_VERSION(2,35,0)
+        g_type_init ();
+#endif
+        setlocale (LC_ALL, "");
+
+        error = NULL;
+
+        cm = gupnp_context_manager_create(0);
+
+        g_signal_connect(cm,
+                         "context-available",
+                         G_CALLBACK(context_available_cb),
+                         NULL);
+
+        g_signal_connect(cm,
+                         "context-unavailable",
+                         G_CALLBACK(context_unavailable_cb),
+                         NULL);
+
+        main_loop = g_main_loop_new (NULL, FALSE);
+
+        id = g_timeout_add_seconds (5, change_white_list, cm);
+
+#ifndef G_OS_WIN32
+        /* Hook the handler for SIGTERM */
+        memset (&sig_action, 0, sizeof (sig_action));
+        sig_action.sa_handler = interrupt_signal_handler;
+        sigaction (SIGINT, &sig_action, NULL);
+#else
+        signal(SIGINT, interrupt_signal_handler);
+#endif /* G_OS_WIN32 */
+
+        g_main_loop_run (main_loop);
+        g_main_loop_unref (main_loop);
+
+        g_source_remove (id);
+
+        g_object_unref (cm);
+
+        return EXIT_SUCCESS;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]