daemon/plugin: Made plugin-proxy self disposable with configurable timeout.
authorAmarnath Valluri <amarnath.valluri@linux.intel.com>
Tue, 4 Jun 2013 09:09:50 +0000 (12:09 +0300)
committerAmarnath Valluri <amarnath.valluri@linux.intel.com>
Tue, 4 Jun 2013 13:42:34 +0000 (16:42 +0300)
Plugin timeout can be configurable using either SSO_PLUGIN_TIMEOUT environmental
variable or .conf file General/PluginTimeout key. PluginProxy will be cached
till this timeout before going down after last referece by auth sessions.

Pluginproxy test case added to test this.

include/gsignond/gsignond-config-general.h
src/common/gsignond-config.c
src/daemon/plugins/gsignond-plugin-proxy-factory.c
src/daemon/plugins/gsignond-plugin-proxy.c
src/daemon/plugins/gsignond-plugin-proxy.h
src/daemon/plugins/gsignond-plugin-remote.c
test/daemon/daemon-test.c
test/plugins/pluginproxytest.c

index ccec64e..31419cd 100644 (file)
@@ -39,5 +39,7 @@
                                                 "/Extension"
 #define GSIGNOND_CONFIG_GENERAL_SECURE_DIR      GSIGNOND_CONFIG_GENERAL \
                                                 "/SecureDir"
+#define GSIGNOND_CONFIG_PLUGIN_TIMEOUT          GSIGNOND_CONFIG_GENERAL \
+                                                "/PluginTimeout"
 
 #endif /* __GSIGNOND_GENERAL_CONFIG_H_ */
index 6e2755a..714622d 100644 (file)
@@ -201,6 +201,12 @@ _load_environment (GSignondConfig *self)
                                     GSIGNOND_CONFIG_DBUS_AUTH_SESSION_TIMEOUT,
                                     e_val);
 
+    e_val = g_getenv ("SSO_PLUGIN_TIMEOUT");
+    if (e_val && (timeout = atoi(e_val)))
+        gsignond_config_set_string (self,
+                                    GSIGNOND_CONFIG_PLUGIN_TIMEOUT,
+                                    e_val);
+
     e_val = g_getenv ("SSO_PLUGINS_DIR");
     if (e_val) 
         gsignond_config_set_string (self,
index adcb264..7119743 100644 (file)
@@ -243,6 +243,33 @@ gsignond_plugin_proxy_factory_new(GSignondConfig *config)
     return proxy;
 }
 
+static gboolean
+_find_proxy_by_pointer (gpointer key, gpointer value, gpointer userdata)
+{
+    (void)key;
+    return userdata == value;
+}
+
+static void
+_remove_dead_proxy (gpointer data, GObject *dead_proxy)
+{
+    GSignondPluginProxyFactory *factory = GSIGNOND_PLUGIN_PROXY_FACTORY(data);
+    if (factory) {
+        g_hash_table_foreach_steal (factory->plugins, 
+                _find_proxy_by_pointer, dead_proxy);
+    }
+}
+
+static void
+_proxy_toggle_ref_cb (gpointer userdata, GObject *proxy, gboolean is_last_ref)
+{
+    /* start/stop timeout timer */
+    gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (proxy), is_last_ref);
+
+    if (is_last_ref) g_object_weak_ref (proxy, _remove_dead_proxy, userdata);
+    else g_object_weak_unref (proxy, _remove_dead_proxy, userdata);
+}
+
 GSignondPluginProxy*
 gsignond_plugin_proxy_factory_get_plugin(GSignondPluginProxyFactory* factory,
                                          const gchar* plugin_type)
@@ -274,7 +301,8 @@ gsignond_plugin_proxy_factory_get_plugin(GSignondPluginProxyFactory* factory,
     }
     g_hash_table_insert(factory->plugins, g_strdup (plugin_type), proxy);
     DBG("get new plugin %s -> %p", plugin_type, proxy);
-    g_object_ref(proxy);
+    g_object_add_toggle_ref(G_OBJECT(proxy), _proxy_toggle_ref_cb, factory);
+
     return proxy;
 }
 
index a89d7ca..cfb3638 100644 (file)
@@ -67,7 +67,7 @@ typedef struct {
 
 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 
-G_DEFINE_TYPE (GSignondPluginProxy, gsignond_plugin_proxy, G_TYPE_OBJECT);
+G_DEFINE_TYPE (GSignondPluginProxy, gsignond_plugin_proxy, GSIGNOND_TYPE_DISPOSABLE);
 
 static GSignondProcessData*
 gsignond_process_data_new (
@@ -478,9 +478,14 @@ gsignond_plugin_proxy_new (
         GSignondConfig *config,
         const gchar *plugin_type)
 {
+    g_return_val_if_fail (config && plugin_type, NULL);
+
+    gint timeout = gsignond_config_get_integer (config, GSIGNOND_CONFIG_PLUGIN_TIMEOUT);
     GSignondPluginProxy* proxy = g_object_new (GSIGNOND_TYPE_PLUGIN_PROXY,
                                                "config", config,
                                                "type", plugin_type,
+                                               "auto-dispose", FALSE,
+                                               "timeout", timeout,
                                                NULL);
     if (g_strcmp0 (plugin_type,
                    gsignond_plugin_proxy_get_plugin_type (proxy)) == 0)
index 03d6fb8..089e125 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <glib-object.h>
 
+#include "common/gsignond-disposable.h"
 #include "daemon/gsignond-types.h"
 #include <gsignond/gsignond-plugin-interface.h>
 #include <gsignond/gsignond-config.h>
@@ -54,7 +55,7 @@ typedef struct _GSignondPluginProxyPrivate GSignondPluginProxyPrivate;
 
 struct _GSignondPluginProxy
 {
-    GObject parent_instance;
+    GSignondDisposable parent_instance;
     
     /* Private */
     GSignondPluginProxyPrivate *priv;
@@ -62,7 +63,7 @@ struct _GSignondPluginProxy
 
 struct _GSignondPluginProxyClass
 {
-    GObjectClass parent_class;
+    GSignondDisposableClass parent_class;
 };
 
 GType
index 563acce..e1a3e7e 100644 (file)
@@ -572,7 +572,7 @@ gsignond_plugin_remote_new (
             NULL, &cpid, &cin_fd, &cout_fd, &cerr_fd, &error);
     g_strfreev (argv);
     if (ret == FALSE || (kill(cpid, 0) != 0)) {
-        DBG ("failed to start plugind: ret(%d)", ret);
+        DBG ("failed to start plugind: error %s(%d)", error->message, ret);
         if (error) g_error_free (error);
         return NULL;
     }
index 8bf5683..4cac4e0 100644 (file)
@@ -73,6 +73,7 @@ setup_daemon (void)
     fail_if (g_setenv ("SSO_STORAGE_PATH", "/tmp/gsignond", TRUE) == FALSE);
     fail_if (g_setenv ("SSO_SECRET_PATH", "/tmp/gsignond", TRUE) == FALSE);
     fail_if (g_setenv ("SSO_KEYCHAIN_SYSCTX", exe_name, TRUE) == FALSE);
+    fail_if (g_setenv ("SSO_PLUGIN_TIMEOUT", "5", TRUE) == FALSE);
 
     DBG ("Programe name : %s\n", exe_name);
 
index 4cb8f97..7fb7403 100644 (file)
@@ -505,6 +505,127 @@ START_TEST (test_pluginproxyfactory_add)
 }
 END_TEST
 
+typedef struct {
+    GSignondPluginProxyFactory *factory;
+    GSignondPluginProxy *proxy;
+} ProxyTimeoutData;
+
+static gboolean
+_validate_new_proxy(gpointer userdata)
+{
+    ProxyTimeoutData *data = (ProxyTimeoutData *)userdata;
+    fail_if (data == NULL);
+
+    GSignondPluginProxy *proxy = gsignond_plugin_proxy_factory_get_plugin (data->factory, "ssotest");
+    fail_if (proxy == NULL);
+
+    fail_if (proxy == data->proxy, "expected new proxy object, but got cached object");
+    g_object_unref(proxy);
+
+    g_free (userdata);
+
+    _stop_mainloop();
+
+    return FALSE;
+}
+
+static gboolean
+_validate_cached_proxy (gpointer userdata)
+{
+    ProxyTimeoutData *data = (ProxyTimeoutData *)userdata;
+    fail_if (data == NULL);
+    
+    GSignondPluginProxy *proxy = gsignond_plugin_proxy_factory_get_plugin (data->factory, "ssotest");
+    fail_if (proxy == NULL);
+
+    fail_unless (proxy == data->proxy, "expected cached proxy object, but got new object");
+
+    g_object_unref (proxy);
+
+    g_timeout_add_seconds (2, _validate_new_proxy, userdata);
+
+    return FALSE;
+}
+
+START_TEST (test_pluginproxyfactory_proxy_timeout)
+{
+    DBG("test_pluginproxyfactory_proxy_timeout\n");
+    GSignondPluginProxyFactory *factory = NULL;
+    GSignondPluginProxy *proxy1 = NULL, *proxy2 = NULL;
+    GSignondConfig *config = NULL;
+
+    /* CASE 1: proxy timeout disabled */
+    g_setenv ("SSO_PLUGIN_TIMEOUT", "0", TRUE);
+  
+    config = gsignond_config_new();
+    fail_if(config == NULL);
+
+    factory = gsignond_plugin_proxy_factory_new ( config);
+    fail_if (factory == NULL);
+
+    proxy1 = gsignond_plugin_proxy_factory_get_plugin (factory, "ssotest");
+    fail_if (proxy1 == NULL);
+    g_object_unref (proxy1);
+
+    proxy2 = gsignond_plugin_proxy_factory_get_plugin (factory, "ssotest");
+    fail_if (proxy2 == NULL);
+
+    fail_unless (proxy1 == proxy2, "got new plugin proxy object, "
+                                   "where expected cached object(%p,%p)",
+                                    proxy1, proxy2);
+    g_object_unref (proxy2);
+
+    g_object_unref (config);
+    g_object_unref (factory);
+
+    /* CASE 2: proxy timeout enbled */ 
+    g_setenv ("SSO_PLUGIN_TIMEOUT", "1", TRUE);
+
+    config = gsignond_config_new();
+    fail_if(config == NULL);
+
+    factory = gsignond_plugin_proxy_factory_new (config);
+    fail_if (factory == NULL);
+
+    proxy1 = gsignond_plugin_proxy_factory_get_plugin (factory, "ssotest");
+    fail_if (proxy1 == NULL);
+    g_object_unref (proxy1);
+
+    ProxyTimeoutData *data = g_new0(ProxyTimeoutData, 1);
+    data->factory = factory;
+    data->proxy = proxy1;
+    g_timeout_add_seconds (2, _validate_new_proxy, (gpointer)data);
+
+    _run_mainloop ();
+
+    g_object_unref(config);
+    g_object_unref(factory);
+
+    /* CASE 3: proxy timeout enable - request recently closed plugin */
+    g_setenv ("SSO_PLUGIN_TIMEOUT", "2", TRUE);
+    config = gsignond_config_new ();
+    fail_if (config == NULL);
+
+    factory = gsignond_plugin_proxy_factory_new(config);
+    fail_if (factory == NULL);
+
+    proxy1 = gsignond_plugin_proxy_factory_get_plugin(factory, "ssotest");
+    fail_if (proxy1 == NULL);
+    g_object_unref (proxy1);
+
+    ProxyTimeoutData *data1 = g_new0(ProxyTimeoutData, 1);
+    data1->factory = factory;
+    data1->proxy = proxy1;
+
+    g_timeout_add_seconds (1, _validate_cached_proxy, (gpointer)data1);
+
+    _run_mainloop();
+
+    g_object_unref(config);
+    g_object_unref(factory);
+}
+END_TEST
+
 Suite* pluginproxy_suite (void)
 {
     Suite *s = suite_create ("Plugin proxy");
@@ -513,6 +634,7 @@ Suite* pluginproxy_suite (void)
     TCase *tc_core = tcase_create ("Tests");
     tcase_add_checked_fixture (tc_core, _setup, _teardown);
 
+    tcase_set_timeout (tc_core, 10);
     tcase_add_test (tc_core, test_pluginproxy_create);
     tcase_add_test (tc_core, test_pluginproxy_process);
     tcase_add_test (tc_core, test_pluginproxy_process_cancel);
@@ -521,6 +643,7 @@ Suite* pluginproxy_suite (void)
     tcase_add_test (tc_core, test_pluginproxyfactory_methods_and_mechanisms);
     tcase_add_test (tc_core, test_pluginproxyfactory_get);
     tcase_add_test (tc_core, test_pluginproxyfactory_add);
+    tcase_add_test (tc_core, test_pluginproxyfactory_proxy_timeout);
 
     suite_add_tcase (s, tc_core);
     return s;