1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of gsignond
6 * Copyright (C) 2012-2014 Intel Corporation.
8 * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
31 #include "gsignond/gsignond-log.h"
32 #include "gsignond-plugin-proxy-factory.h"
33 #include "gsignond-plugin-remote.h"
35 G_DEFINE_TYPE (GSignondPluginProxyFactory, gsignond_plugin_proxy_factory, G_TYPE_OBJECT);
47 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
50 static gchar** _get_plugin_names_from_loader(const gchar* loader_path)
52 gchar* command_line = g_strdup_printf("%s --list-plugins", loader_path);
53 gchar* standard_output = NULL;
54 gchar* standard_error = NULL;
58 if (g_spawn_command_line_sync(command_line, &standard_output, &standard_error,
59 &exit_status, &error)) {
60 DBG("Loader %s returned plugin list %s", loader_path, standard_output);
61 gchar** plugin_list = g_strsplit(standard_output, "\n", 0);
63 g_free(standard_output);
64 g_free(standard_error);
67 DBG("Loader %s returned exit status %d, error %s", loader_path,
68 exit_status, error->message);
75 static void _add_plugins(GSignondPluginProxyFactory* self, const gchar* loader_path, gchar** plugins)
77 DBG ("Checking mechanisms of plugins provided by %s", loader_path);
78 gchar **plugin_iter = plugins;
79 while (*plugin_iter) {
80 GSignondPlugin* plugin = GSIGNOND_PLUGIN (
81 gsignond_plugin_remote_new (loader_path, *plugin_iter));
87 "mechanisms", &mechanisms,
89 if (g_strcmp0 (plugin_type, *plugin_iter) == 0) {
90 const gchar* loader = g_hash_table_lookup(self->methods_to_loader_paths,
92 // Do not replace plugins provided by gsignond-plugind with
94 if (loader && g_str_has_suffix(loader, "/gsignond-plugind")) {
95 DBG("Do not replace plugin %s with plugin provided by loader %s",
96 plugin_type, loader_path);
97 g_strfreev(mechanisms);
99 DBG("Adding plugin %s to plugin enumeration", plugin_type);
100 g_hash_table_insert(self->methods_to_mechanisms,
101 g_strdup(plugin_type), mechanisms);
102 g_hash_table_insert(self->methods_to_loader_paths,
103 g_strdup(plugin_type), g_strdup(loader_path));
106 DBG("Plugin returned type property %s, which does not match requested type %s",
107 plugin_type, *plugin_iter);
108 g_strfreev(mechanisms);
111 g_object_unref(plugin);
117 static void _insert_method(gchar* method, gchar*** method_iter_p)
119 *(*method_iter_p) = method;
124 static void _enumerate_plugins(GSignondPluginProxyFactory* self)
126 const gchar *loaders_path = GSIGNOND_PLUGINLOADERS_DIR;
128 const gchar* env_val = g_getenv("SSO_BIN_DIR");
130 loaders_path = env_val;
133 GDir* loaders_dir = g_dir_open(loaders_path, 0, NULL);
134 if (loaders_dir == NULL) {
135 WARN ("plugin directory empty");
139 DBG ("Getting lists of plugins from loaders in %s (factory=%p)", loaders_path, self);
141 const gchar* loader_name = g_dir_read_name(loaders_dir);
142 if (loader_name == NULL)
144 gchar* loader_path = g_build_filename(loaders_path, loader_name, NULL);
145 gchar** plugins = _get_plugin_names_from_loader(loader_path);
146 if (plugins != NULL) {
147 _add_plugins(self, loader_path, plugins);
152 g_dir_close(loaders_dir);
154 // make a flat list of available plugin types
155 int n_plugins = g_hash_table_size(self->methods_to_mechanisms);
156 self->methods = g_new0(gchar*, n_plugins + 1);
157 gchar **method_iter = self->methods;
159 GList* keys = g_hash_table_get_keys(self->methods_to_mechanisms);
160 g_list_foreach(keys, (GFunc)_insert_method, &method_iter);
166 gsignond_plugin_proxy_factory_constructor (GType gtype,
168 GObjectConstructParam *properties)
173 /* Always chain up to the parent constructor */
174 obj = G_OBJECT_CLASS (gsignond_plugin_proxy_factory_parent_class)->constructor (
175 gtype, n_properties, properties);
182 gsignond_plugin_proxy_factory_set_property (GObject *object,
187 GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (object);
191 g_assert (self->config == NULL);
192 self->config = g_value_dup_object (value);
195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
201 gsignond_plugin_proxy_factory_get_property (GObject *object,
206 GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (object);
211 g_value_set_object (value, self->config);
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
220 gsignond_plugin_proxy_factory_dispose (GObject *gobject)
222 GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (gobject);
225 g_object_unref (self->config);
229 /* Chain up to the parent class */
230 G_OBJECT_CLASS (gsignond_plugin_proxy_factory_parent_class)->dispose (gobject);
234 gsignond_plugin_proxy_factory_finalize (GObject *gobject)
236 GSignondPluginProxyFactory *self = GSIGNOND_PLUGIN_PROXY_FACTORY (gobject);
239 g_hash_table_destroy (self->plugins);
240 self->plugins = NULL;
242 if (self->methods_to_mechanisms) {
243 g_hash_table_destroy (self->methods_to_mechanisms);
244 self->methods_to_mechanisms = NULL;
246 if (self->methods_to_loader_paths) {
247 g_hash_table_destroy (self->methods_to_loader_paths);
248 self->methods_to_loader_paths = NULL;
251 g_free (self->methods);
252 self->methods = NULL;
255 /* Chain up to the parent class */
256 G_OBJECT_CLASS (gsignond_plugin_proxy_factory_parent_class)->finalize (gobject);
261 gsignond_plugin_proxy_factory_class_init (GSignondPluginProxyFactoryClass *klass)
263 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
265 gobject_class->constructor = gsignond_plugin_proxy_factory_constructor;
266 gobject_class->set_property = gsignond_plugin_proxy_factory_set_property;
267 gobject_class->get_property = gsignond_plugin_proxy_factory_get_property;
268 gobject_class->dispose = gsignond_plugin_proxy_factory_dispose;
269 gobject_class->finalize = gsignond_plugin_proxy_factory_finalize;
271 obj_properties[PROP_CONFIG] = g_param_spec_object ("config",
273 "Configuration object",
274 GSIGNOND_TYPE_CONFIG,
275 G_PARAM_CONSTRUCT_ONLY |
277 G_PARAM_STATIC_STRINGS);
280 g_object_class_install_properties (gobject_class,
286 gsignond_plugin_proxy_factory_init (GSignondPluginProxyFactory *self)
288 self->methods_to_mechanisms = g_hash_table_new_full((GHashFunc)g_str_hash,
289 (GEqualFunc)g_str_equal,
290 (GDestroyNotify)g_free,
291 (GDestroyNotify)g_strfreev);
293 self->methods_to_loader_paths = g_hash_table_new_full((GHashFunc)g_str_hash,
294 (GEqualFunc)g_str_equal,
295 (GDestroyNotify)g_free,
296 (GDestroyNotify)g_free);
298 self->plugins = g_hash_table_new_full ((GHashFunc)g_str_hash,
299 (GEqualFunc)g_str_equal,
300 (GDestroyNotify)g_free,
301 (GDestroyNotify)g_object_unref);
303 self->methods = NULL;
306 GSignondPluginProxyFactory*
307 gsignond_plugin_proxy_factory_new(GSignondConfig *config)
309 GSignondPluginProxyFactory* proxy = g_object_new(
310 GSIGNOND_TYPE_PLUGIN_PROXY_FACTORY,
317 _find_proxy_by_pointer (gpointer key, gpointer value, gpointer userdata)
319 if (userdata == value) {
327 _remove_dead_proxy (gpointer data, GObject *dead_proxy)
329 GSignondPluginProxyFactory *factory = GSIGNOND_PLUGIN_PROXY_FACTORY(data);
331 g_hash_table_foreach_steal (factory->plugins,
332 _find_proxy_by_pointer, dead_proxy);
337 _proxy_toggle_ref_cb (gpointer userdata, GObject *proxy, gboolean is_last_ref)
339 /* start/stop timeout timer */
340 gsignond_disposable_set_auto_dispose (GSIGNOND_DISPOSABLE (proxy), is_last_ref);
342 if (is_last_ref) g_object_weak_ref (proxy, _remove_dead_proxy, userdata);
343 else g_object_weak_unref (proxy, _remove_dead_proxy, userdata);
347 gsignond_plugin_proxy_factory_get_plugin(GSignondPluginProxyFactory* factory,
348 const gchar* plugin_type)
350 g_return_val_if_fail (factory && GSIGNOND_IS_PLUGIN_PROXY_FACTORY(factory), NULL);
351 g_return_val_if_fail (plugin_type, NULL);
353 GSignondPluginProxy* proxy = NULL;
355 if (factory->methods == NULL) {
356 _enumerate_plugins (factory);
359 if (g_hash_table_lookup(factory->methods_to_mechanisms, plugin_type) == NULL) {
360 DBG("Plugin not known %s", plugin_type);
364 proxy = g_hash_table_lookup(factory->plugins, plugin_type);
366 DBG("get existing plugin %s -> %p", plugin_type, proxy);
371 proxy = gsignond_plugin_proxy_new(g_hash_table_lookup(factory->methods_to_loader_paths, plugin_type), plugin_type,
372 gsignond_config_get_integer (factory->config, GSIGNOND_CONFIG_PLUGIN_TIMEOUT));
376 g_hash_table_insert(factory->plugins, g_strdup (plugin_type), proxy);
377 DBG("get new plugin %s -> %p", plugin_type, proxy);
378 g_object_add_toggle_ref(G_OBJECT(proxy), _proxy_toggle_ref_cb, factory);
384 gsignond_plugin_proxy_factory_get_plugin_types(
385 GSignondPluginProxyFactory* factory)
387 if (factory->methods == NULL) {
388 _enumerate_plugins (factory);
390 return (const gchar**)factory->methods;
394 gsignond_plugin_proxy_factory_get_plugin_mechanisms(
395 GSignondPluginProxyFactory* factory, const gchar* plugin_type)
397 g_return_val_if_fail(factory->methods_to_mechanisms, NULL);
399 if (factory->methods == NULL) {
400 _enumerate_plugins (factory);
403 return g_hash_table_lookup(factory->methods_to_mechanisms, plugin_type);