plugin-loader: Optionally use load option in each plugin section to load plugins
authorTobias Brunner <tobias@strongswan.org>
Wed, 22 Jan 2014 14:29:45 +0000 (15:29 +0100)
committerTobias Brunner <tobias@strongswan.org>
Wed, 12 Feb 2014 13:34:33 +0000 (14:34 +0100)
This now works because all plugins use the same config namespace.

If <ns>.load_modular is true, the list of plugins to load is determined
via the value of the <ns>.plugins.<name>.load options.

Using includes the following is possible:

charon {
  load_modular = yes
  plugins {
    include strongswan.d/charon/*.conf
  }
}

charon-cmd {
  load_modular = yes
  plugins {
    include strongswan.d/charon-cmd/*.conf
  }
}

Where each .conf file would contain something like:

<name> {
  load = yes
  <option> = <value>
}

To increase the priority of individual plugins load = <priority> can be
used (the default is 1).  For instance, to use openssl instead of the
built-in crypto plugins set in strongswan.d/charon/openssl.conf:

openssl {
  load = 10
}

If two plugins have the same priority their order in the default plugin
list is preserved.  Plugins not found in that list are ordered
alphabetically before other plugins with the same priority.

man/strongswan.conf.5.in
src/libstrongswan/plugins/plugin_loader.c
src/libstrongswan/plugins/plugin_loader.h

index 7696540..02f910e 100644 (file)
@@ -290,6 +290,15 @@ Threshold in number of allocations for leaks to be reported (0 to report all)
 .BR charon.load
 Plugins to load in the IKEv2 daemon charon
 .TP
+.BR charon.load_modular " [no]"
+If enabled, the list of plugins to load is determined via the value of the
+charon.plugins.<name>.load options.  In addition to a simple boolean flag that
+option may take an integer value indicating the priority of a plugin, which
+would influence the order of a plugin in the plugin list (the default is 1).
+If two plugins have the same priority their order in the default plugin list
+is preserved. Enabled plugins not found in that list are ordered alphabetically
+before other plugins with the same priority.
+.TP
 .BR charon.max_packet " [10000]"
 Maximum packet size accepted by charon
 .TP
index c904323..08a8442 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2013 Tobias Brunner
+ * Copyright (C) 2010-2014 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -28,6 +28,7 @@
 #include <utils/debug.h>
 #include <library.h>
 #include <collections/hashtable.h>
+#include <collections/array.h>
 #include <collections/linked_list.h>
 #include <plugins/plugin.h>
 #include <utils/integrity_checker.h>
@@ -936,18 +937,146 @@ static bool find_plugin(char *path, char *name, char *buf, char **file)
        return FALSE;
 }
 
+/**
+ * Used to sort plugins by priority
+ */
+typedef struct {
+       /* name of the plugin */
+       char *name;
+       /* the plugins priority */
+       int prio;
+       /* default priority */
+       int def;
+} plugin_priority_t;
+
+static void plugin_priority_free(const plugin_priority_t *this, int idx,
+                                                                void *user)
+{
+       free(this->name);
+}
+
+/**
+ * Sort plugins and their priority by name
+ */
+static int plugin_priority_cmp_name(const plugin_priority_t *a,
+                                                                   const plugin_priority_t *b)
+{
+       return strcmp(a->name, b->name);
+}
+
+/**
+ * Sort plugins by decreasing priority or default priority then by name
+ */
+static int plugin_priority_cmp(const plugin_priority_t *a,
+                                                          const plugin_priority_t *b, void *user)
+{
+       int diff;
+
+       diff = b->prio - a->prio;
+       if (!diff)
+       {       /* the same priority, use default order */
+               diff = b->def - a->def;
+               if (!diff)
+               {       /* same default priority (i.e. both were not found in that list) */
+                       return strcmp(a->name, b->name);
+               }
+       }
+       return diff;
+}
+
+
+/**
+ * Determine the list of plugins to load via load option in each plugin's
+ * config section.
+ */
+static char *modular_pluginlist(char *list)
+{
+       enumerator_t *enumerator;
+       array_t *given, *final;
+       plugin_priority_t item, *current, found;
+       char *plugin, *plugins = NULL;
+       int i = 0, max_prio;
+
+       if (!lib->settings->get_bool(lib->settings, "%s.load_modular", FALSE,
+                                                                lib->ns))
+       {
+               return list;
+       }
+
+       given = array_create(sizeof(plugin_priority_t), 0);
+       final = array_create(sizeof(plugin_priority_t), 0);
+
+       enumerator = enumerator_create_token(list, " ", " ");
+       while (enumerator->enumerate(enumerator, &plugin))
+       {
+               item.name = strdup(plugin);
+               item.prio = i++;
+               array_insert(given, ARRAY_TAIL, &item);
+       }
+       enumerator->destroy(enumerator);
+       array_sort(given, (void*)plugin_priority_cmp_name, NULL);
+       /* the maximum priority used for plugins not found in this list */
+       max_prio = i + 1;
+
+       enumerator = lib->settings->create_section_enumerator(lib->settings,
+                                                                                                               "%s.plugins", lib->ns);
+       while (enumerator->enumerate(enumerator, &plugin))
+       {
+               item.prio = lib->settings->get_int(lib->settings,
+                                                               "%s.plugins.%s.load", 0, lib->ns, plugin);
+               if (!item.prio)
+               {
+                       if (!lib->settings->get_bool(lib->settings,
+                                                               "%s.plugins.%s.load", FALSE, lib->ns, plugin))
+                       {
+                               continue;
+                       }
+                       item.prio = 1;
+               }
+               item.name = plugin;
+               item.def = max_prio;
+               if (array_bsearch(given, &item, (void*)plugin_priority_cmp_name,
+                                                 &found) != -1)
+               {
+                       item.def = max_prio - found.prio;
+               }
+               array_insert(final, ARRAY_TAIL, &item);
+       }
+       enumerator->destroy(enumerator);
+       array_destroy_function(given, (void*)plugin_priority_free, NULL);
+
+       array_sort(final, (void*)plugin_priority_cmp, NULL);
+
+       enumerator = array_create_enumerator(final);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               char *prev = plugins;
+               if (asprintf(&plugins, "%s %s", plugins ?: "", current->name) < 0)
+               {
+                       plugins = prev;
+                       break;
+               }
+               free(prev);
+       }
+       enumerator->destroy(enumerator);
+       array_destroy(final);
+       return plugins;
+}
+
 METHOD(plugin_loader_t, load_plugins, bool,
        private_plugin_loader_t *this, char *list)
 {
        enumerator_t *enumerator;
-       char *default_path = NULL, *token;
+       char *default_path = NULL, *plugins, *token;
        bool critical_failed = FALSE;
 
 #ifdef PLUGINDIR
        default_path = PLUGINDIR;
 #endif /* PLUGINDIR */
 
-       enumerator = enumerator_create_token(list, " ", " ");
+       plugins = modular_pluginlist(list);
+
+       enumerator = enumerator_create_token(plugins, " ", " ");
        while (!critical_failed && enumerator->enumerate(enumerator, &token))
        {
                plugin_entry_t *entry;
@@ -1006,6 +1135,10 @@ METHOD(plugin_loader_t, load_plugins, bool,
                free(this->loaded_plugins);
                this->loaded_plugins = loaded_plugins_list(this);
        }
+       if (plugins != list)
+       {
+               free(plugins);
+       }
        return !critical_failed;
 }
 
index 164360c..08a759a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2013 Tobias Brunner
+ * Copyright (C) 2012-2014 Tobias Brunner
  * Copyright (C) 2007 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -67,6 +67,13 @@ struct plugin_loader_t {
         * for the plugins first, in the order they were added, then the default
         * path follows.
         *
+        * If <ns>.load_modular is enabled (where <ns> is lib->ns) the plugins to
+        * load are determined via a load option in their respective plugin config
+        * section e.g. <ns>.plugins.<plugin>.load = <priority|bool>.
+        * The oder is determined by the configured priority.  If two plugins have
+        * the same priority the order as seen in list is preserved.  Plugins not
+        * found in list are loaded first, in alphabetical order.
+        *
         * @note Even though this method could be called multiple times this is
         * currently not really supported in regards to plugin features and their
         * dependencies (in particular soft dependencies).