Version 6 plugin loader (dynamic loading/unloading, static linking of plugins, easier...
authorHenning Rogge <hrogge@googlemail.com>
Wed, 1 Jul 2009 16:33:12 +0000 (18:33 +0200)
committerHenning Rogge <hrogge@googlemail.com>
Wed, 1 Jul 2009 16:33:12 +0000 (18:33 +0200)
Only txtinfo was converted to new plugin interface, the other will be done soon

Makefile
Makefile.inc
lib/txtinfo/src/olsrd_txtinfo.c
src/main.c
src/olsr_comport_txt.c
src/parser.c
src/plugin.h
src/plugin_loader.c
src/plugin_loader.h

index 7a97ce8..4736c89 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,9 @@ $(EXENAME):   $(OBJS) src/builddata.o
 ifeq ($(LD_HAS_DYN), yes)
                $(SHELL) olsrd-exports.sh $$(find src -name "*.h") > $(EXENAME).exports
 endif
-               $(CC) $(LDFLAGS) $(LDFLAGS_EXE) -o $@ $^ $(LIBS)
+# precompile plugins for static linking
+               set -e;for dir in $(STATIC_PLUGINS);do $(MAKECMD) -C lib/$$dir LIBDIR=$(LIBDIR);done
+               $(CC) $(LDFLAGS) $(LDFLAGS_EXE) -o $@ $^ $(STATIC_PLUGIN_OBJS) $(LIBS)
 
 CONFDIR = src/config
 include $(CONFDIR)/local.mk
index b6ea97a..3eda464 100644 (file)
@@ -18,6 +18,8 @@ REMOVE_LOG_ERROR ?= 0
 # you need a recent enough gcc and the libmudflap installed
 MUDFLAP ?= 0
 
+# enable static linking of plugins (list of plugin directory names) 
+STATIC_PLUGINS ?= txtinfo
 
 ######################
 #
@@ -96,7 +98,7 @@ ifndef CFLAGS
     ALL_WARNINGS +=    -Wwrite-strings
     ALL_WARNINGS +=    -Wbad-function-cast
     ALL_WARNINGS +=    -Wpointer-arith
-    ALL_WARNINGS +=    -Wcast-qual
+    # ALL_WARNINGS +=  -Wcast-qual
     ALL_WARNINGS +=    -Wshadow
     ALL_WARNINGS +=    -Wformat-2
     ALL_WARNINGS +=    -Wsequence-point
@@ -200,6 +202,10 @@ LDFLAGS += $(EXTRA_LDFLAGS)
 SRCS +=                $(wildcard src/common/*.c src/*.c)
 HDRS +=                $(wildcard src/common/*.h src/*.h)
 
+#get headers and object files for static plugins
+STATIC_PLUGIN_SRCS += $(foreach dir,$(STATIC_PLUGINS),$(wildcard lib/$(dir)/src/*.c))
+STATIC_PLUGIN_OBJS += $(STATIC_PLUGIN_SRCS:%.c=%.o)
+
 # OS detection
 ifeq ($(OS),Windows_NT)
   OS := win32
@@ -215,6 +221,11 @@ all: default_target
 include $(TOPDIR)/make/Makefile.$(OS)
 endif
 
+ifdef OLSRD_PLUGIN
+  # this must be run after the OS-specific makefile
+  CPPFLAGS +=  -DPLUGIN_FULLNAME="\"$(PLUGIN_FULLNAME)\""
+endif
+
 # one object for each source file
 OBJS +=                $(SRCS:%.c=%.o)
 
index eec560a..b13d9fd 100644 (file)
 #include "parser.h"
 #include "olsr_comport_txt.h"
 #include "common/autobuf.h"
+#include "plugin_loader.h"
+#include "plugin_util.h"
 
-#include "olsrd_txtinfo.h"
-
-#define PLUGIN_NAME    "OLSRD txtinfo plugin"
-#define PLUGIN_VERSION "0.2"
+#define PLUGIN_DESCR    "OLSRD txtinfo plugin"
 #define PLUGIN_AUTHOR   "Henning Rogge"
-#define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION " by " PLUGIN_AUTHOR
-#define PLUGIN_INTERFACE_VERSION 5
+
 
 struct debuginfo_cmd {
   const char *name;
@@ -70,8 +68,9 @@ struct debuginfo_cmd {
   struct olsr_txtcommand *normal, *csv;
 };
 
-static void txtinfo_new(void) __attribute__ ((constructor));
-static void txtinfo_delete(void) __attribute__ ((destructor));
+static int txtinfo_pre_init(void);
+int txtinfo_post_init(void);
+static int txtinfo_pre_cleanup(void);
 
 static enum olsr_txtcommand_result txtinfo_neigh(struct comport_connection *con, char *cmd, char *param);
 static enum olsr_txtcommand_result txtinfo_link(struct comport_connection *con,  char *cmd, char *param);
@@ -92,6 +91,8 @@ static const struct olsrd_plugin_parameters plugin_parameters[] = {
   {.name = IP_ACL_DEFAULTPOLICY_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_defaultPolicy,.data = &allowed_nets}
 };
 
+DEFINE_PLUGIN6(PLUGIN_DESCR, PLUGIN_AUTHOR, txtinfo_pre_init, txtinfo_post_init, txtinfo_pre_cleanup, NULL, true, plugin_parameters)
+
 /* command callbacks and names */
 static struct debuginfo_cmd commands[] = {
     {"neigh", &txtinfo_neigh, NULL, NULL},
@@ -102,29 +103,12 @@ static struct debuginfo_cmd commands[] = {
     {"mid", &txtinfo_mid, NULL, NULL},
 };
 
-int
-olsrd_plugin_interface_version(void)
-{
-  return PLUGIN_INTERFACE_VERSION;
-}
-
-void
-olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
-{
-  *params = plugin_parameters;
-  *size = ARRAYSIZE(plugin_parameters);
-}
-
-
 /**
  * Constructor of plugin, called before parameters are initialized
  */
-static void
-txtinfo_new(void)
+static int
+txtinfo_pre_init(void)
 {
-  /* Print plugin info to stdout */
-  OLSR_INFO(LOG_PLUGINS, "%s\n", MOD_DESC);
-
   ip_acl_init(&allowed_nets);
 
   /* always allow localhost */
@@ -137,13 +121,14 @@ txtinfo_new(void)
     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_loopback, 128, false);
     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_v4mapped_loopback, 128, false);
   }
+  return 0;
 }
 
 /**
  * Destructor of plugin
  */
-static void
-txtinfo_delete(void)
+static int
+txtinfo_pre_cleanup(void)
 {
   size_t i;
 
@@ -152,13 +137,14 @@ txtinfo_delete(void)
     olsr_com_remove_csv_txtcommand(commands[i].csv);
   }
   ip_acl_flush(&allowed_nets);
+  return 0;
 }
 
 /*
  * Initialization of plugin AFTER parameters have been read
  */
 int
-olsrd_plugin_init(void)
+txtinfo_post_init(void)
 {
   size_t i;
 
@@ -168,7 +154,7 @@ olsrd_plugin_init(void)
     commands[i].normal->acl = &allowed_nets;
     commands[i].csv->acl = &allowed_nets;
   }
-  return 1;
+  return 0;
 }
 
 /**
index 3f16dc3..984e863 100644 (file)
@@ -194,15 +194,6 @@ main(int argc, char *argv[])
   }
 #endif
 
-  /* initialize logging */
-  olsr_log_init();
-
-  /* initialize cookie system */
-  olsr_cookie_init();
-
-  /* Initialize timers and scheduler part */
-  olsr_init_timers();
-
   /* Set avl tree comparator */
   if (olsr_cnf->ipsize == 4) {
     avl_comp_default = avl_comp_ipv4;
@@ -216,6 +207,24 @@ main(int argc, char *argv[])
     avl_comp_prefix_origin_default = avl_comp_ipv6_prefix_origin;
   }
 
+  /* initialize logging */
+  olsr_log_init();
+
+  /* initialize cookie system */
+  olsr_cookie_init();
+
+  /* Initialize timers and scheduler part */
+  olsr_init_timers();
+
+  /* Initialisation of different tables to be used. */
+  olsr_init_tables();
+
+  /* initialize built in server services */
+  olsr_com_init();
+
+  /* Load plugins */
+  olsr_init_pluginsystem(true);
+
   /* Initialize net */
   init_net();
 
@@ -319,12 +328,6 @@ main(int argc, char *argv[])
   }
 #endif
 
-  /* Initialisation of different tables to be used. */
-  olsr_init_tables();
-
-  /* initialize built in server services */
-  olsr_com_init();
-
   /* daemon mode */
 #ifndef WIN32
   if (!olsr_cnf->no_fork) {
@@ -336,9 +339,6 @@ main(int argc, char *argv[])
   }
 #endif
 
-  /* Load plugins */
-  olsr_load_plugins();
-
   /* activate LQ algorithm */
   init_lq_handler();
 
@@ -497,7 +497,7 @@ olsr_shutdown(void)
   deinit_lq_handler();
 
   /* Closing plug-ins */
-  olsr_close_plugins();
+  olsr_destroy_pluginsystem();
 
   /* Remove active interfaces */
   for (iface = olsr_cnf->if_configs; iface != NULL; iface = iface->next) {
index 34e759a..c8e4c8d 100644 (file)
@@ -48,6 +48,7 @@
 #include "scheduler.h"
 #include "olsr_comport.h"
 #include "olsr_comport_txt.h"
+#include "plugin_loader.h"
 
 struct txt_repeat_data {
   struct timer_entry *timer;
@@ -74,7 +75,8 @@ static enum olsr_txtcommand_result olsr_txtcmd_timeout(
     struct comport_connection *con, char *cmd, char *param);
 static enum olsr_txtcommand_result olsr_txtcmd_version(
     struct comport_connection *con, char *cmd, char *param);
-
+static enum olsr_txtcommand_result olsr_txtcmd_plugin(
+    struct comport_connection *con, char *cmd, char *param);
 static enum olsr_txtcommand_result olsr_txtcmd_displayhelp(
     struct comport_connection *con, char *cmd, char *param);
 
@@ -87,7 +89,8 @@ static const char *txt_internal_names[] = {
   "csvoff",
   "repeat",
   "timeout",
-  "version"
+  "version",
+  "plugin"
 };
 
 static const char *txt_internal_help[] = {
@@ -99,6 +102,8 @@ static const char *txt_internal_help[] = {
   "repeat <interval> <command>: repeats a command every <interval> seconds\n",
   "timeout <interval>: set the timeout interval to <interval> seconds, 0 means no timeout\n"
   "displays the version of the olsrd\n"
+  "control olsr plugins dynamically, parameters are 'list', 'activate <plugin>', 'deactivate <plugin>', "
+    "'load <plugin>' and 'unload <plugin>'"
 };
 
 static olsr_txthandler txt_internal_handlers[] = {
@@ -109,7 +114,8 @@ static olsr_txthandler txt_internal_handlers[] = {
   olsr_txtcmd_csvoff,
   olsr_txtcmd_repeat,
   olsr_txtcmd_timeout,
-  olsr_txtcmd_version
+  olsr_txtcmd_version,
+  olsr_txtcmd_plugin
 };
 
 void olsr_com_init_txt(void) {
@@ -341,3 +347,90 @@ olsr_txtcmd_version(struct comport_connection *con, char *cmd __attribute__ ((un
       olsrd_version, build_date, build_host);
   return CONTINUE;
 }
+
+static enum olsr_txtcommand_result
+olsr_txtcmd_plugin(struct comport_connection *con, char *cmd, char *param) {
+  struct olsr_plugin *plugin;
+  char *para2 = NULL;
+  if (param == NULL || strcasecmp(param, "list") == 0) {
+    if (!con->is_csv && abuf_puts(&con->out, "Table:\n") < 0) {
+      return ABUF_ERROR;
+    }
+    OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin) {
+      if (abuf_appendf(&con->out, con->is_csv ? "%s,%s,%s": " %-30s\t%s\t%s\n",
+          plugin->p_name, plugin->active ? "active" : "", plugin->dlhandle == NULL ? "static" : "") < 0) {
+        return ABUF_ERROR;
+      }
+    } OLSR_FOR_ALL_PLUGIN_ENTRIES_END(plugin)
+    return CONTINUE;
+  }
+
+  para2 = strchr(param, ' ');
+  if (para2 == NULL) {
+    if (con->is_csv) {
+      abuf_appendf(&con->out, "Error, missing or unknown parameter\n");
+    }
+    return CONTINUE;
+  }
+  *para2++ = 0;
+
+  plugin = olsr_get_plugin(para2);
+  if (strcasecmp(param, "load") == 0) {
+    if (plugin != NULL) {
+      abuf_appendf(&con->out, "Plugin %s already loaded\n", para2);
+      return CONTINUE;
+    }
+    plugin = olsr_load_plugin(para2);
+    if (plugin != NULL) {
+      abuf_appendf(&con->out, "Plugin %s successfully loaded\n", para2);
+    }
+    else {
+      abuf_appendf(&con->out, "Could not load plugin %s\n", para2);
+    }
+    return CONTINUE;
+  }
+
+  if (plugin == NULL) {
+    if (con->is_csv) {
+      abuf_appendf(&con->out, "Error, could not find plugin '%s'.\n", para2);
+    }
+    return CONTINUE;
+  }
+  if (strcasecmp(param, "activate") == 0) {
+    if (plugin->active) {
+      abuf_appendf(&con->out, "Plugin %s already active\n", para2);
+    }
+    else if (olsr_activate_plugin(plugin)) {
+      abuf_appendf(&con->out, "Could not activate plugin %s\n", para2);
+    }
+    else {
+      abuf_appendf(&con->out, "Plugin %s successfully activated\n", para2);
+    }
+  }
+  else if (strcasecmp(param, "deactivate") == 0) {
+    if (!plugin->active) {
+      abuf_appendf(&con->out, "Plugin %s is not active\n", para2);
+    }
+    else if (olsr_deactivate_plugin(plugin)) {
+      abuf_appendf(&con->out, "Could not deactivate plugin %s\n", para2);
+    }
+    else {
+      abuf_appendf(&con->out, "Plugin %s successfully deactivated\n", para2);
+    }
+  }
+  else if (strcasecmp(param, "unload") == 0) {
+    if (plugin->dlhandle == NULL) {
+      abuf_appendf(&con->out, "Plugin %s is static and cannot be unloaded\n", para2);
+    }
+    else if (olsr_unload_plugin(plugin)) {
+      abuf_appendf(&con->out, "Could not unload plugin %s\n", para2);
+    }
+    else {
+      abuf_appendf(&con->out, "Plugin %s successfully unloaded\n", para2);
+    }
+  }
+  else {
+    abuf_appendf(&con->out, "Unknown command '%s %s %s'.\n", cmd, param, para2);
+  }
+  return CONTINUE;
+}
index d51822d..a90e882 100644 (file)
 
 static void parse_packet(struct olsr *, int, struct interface *, union olsr_ip_addr *);
 
-
-/* Sven-Ola: On very slow devices used in huge networks
- * the amount of lq_tc messages is so high, that the
- * recv() loop never ends. This is a small hack to end
- * the loop in this cases
- */
-
-static struct parse_function_entry *parse_functions;
-static struct preprocessor_function_entry *preprocessor_functions;
-static struct packetparser_function_entry *packetparser_functions;
+static struct parse_function_entry *parse_functions = NULL;
+static struct preprocessor_function_entry *preprocessor_functions = NULL;
+static struct packetparser_function_entry *packetparser_functions = NULL;
 
 /**
  *Initialize the parser.
index c850106..8c7ae41 100644 (file)
 #ifndef _PLUGIN_H
 #define _PLUGIN_H
 
+struct olsrd_plugin_parameters;
+
+#include "plugin_loader.h"
 
 /* Define the most recent version */
-#define MOST_RECENT_PLUGIN_INTERFACE_VERSION           5
-#define LAST_SUPPORTED_PLUGIN_INTERFACE_VERSION                4
+#define MOST_RECENT_PLUGIN_INTERFACE_VERSION           6
+#define LAST_SUPPORTED_PLUGIN_INTERFACE_VERSION                5
 
 
 /****************************************************************************
  *                Functions that the plugin MUST provide                    *
  ****************************************************************************/
-#if 1
+#if OLSR_PLUGIN
 
 /* We hide them from the compiler here to allow the plugins itself to declare them
  * as they also implement them if we activate -Wredundant-decls.
@@ -89,6 +92,13 @@ int olsrd_plugin_register_param(char *key, char *value);
 
 /* Interface version 5 */
 
+/**
+ * Delivers the (address of the) table and the size of the parameter description
+ */
+void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size);
+
+#endif
+
 typedef union {
   unsigned int ui;
   char *pc;
@@ -103,12 +113,6 @@ struct olsrd_plugin_parameters {
   set_plugin_parameter_addon addon;
 };
 
-/**
- * Delivers the (address of the) table and the size of the parameter description
- */
-void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size);
-
-#endif
 
 #endif /* _PLUGIN_H */
 
index 1666fd4..1562f91 100644 (file)
 #include "defs.h"
 #include "olsr.h"
 #include "olsr_logging.h"
+#include "common/avl.h"
+#include "common/list.h"
+#include "olsr_cookie.h"
 
 #include <dlfcn.h>
 #include <errno.h>
 #include <stdlib.h>
 
-
 /* Local functions */
-static int init_olsr_plugin(struct olsr_plugin *);
-static int olsr_load_dl(char *, struct plugin_param *);
-static int olsr_add_dl(struct olsr_plugin *);
+static struct olsr_plugin *olsr_load_legacy_plugin(char *, void *);
 
-static struct olsr_plugin *olsr_plugins = NULL;
+struct avl_tree plugin_tree;
+static bool plugin_tree_initialized = false;
 
+static struct olsr_cookie_info *plugin_mem_cookie = NULL;
 
 /**
- *Function that loads all registered plugins
+ * This function is called by the constructor of a plugin.
+ * because of this the first call has to initialize the list
+ * head.
  *
- *@return the number of plugins loaded
+ * @param pl_def pointer to plugin definition
  */
 void
-olsr_load_plugins(void)
-{
-  struct plugin_entry *entry = olsr_cnf->plugins;
-  int rv = 0;
-  OLSR_INFO(LOG_PLUGINS, "-- LOADING PLUGINS --\n");
-  for (entry = olsr_cnf->plugins; entry != NULL; entry = entry->next) {
-    if (olsr_load_dl(entry->name, entry->params) < 0) {
-      rv = 1;
-    }
+olsr_hookup_plugin(struct olsr_plugin *pl_def) {
+  fprintf(stderr, "hookup %s\n", pl_def->p_name);
+  if (!plugin_tree_initialized) {
+    avl_init(&plugin_tree, avl_comp_strcasecmp);
+    plugin_tree_initialized = true;
   }
-  if (rv != 0) {
-    OLSR_ERROR(LOG_PLUGINS, "-- PLUGIN LOADING FAILED! --\n");
-    olsr_exit(1);
-  }
-  OLSR_INFO(LOG_PLUGINS, "-- ALL PLUGINS LOADED! --\n\n");
+  pl_def->p_node.key = pl_def->p_name;
+  avl_insert(&plugin_tree, &pl_def->p_node, AVL_DUP_NO);
 }
 
 /**
- *Try to load a shared library and extract
- *the required information
- *
- *@param libname the name of the library(file)
+ * This function is called by the destructor of a plugin.
  *
- *@return negative on error
+ * @param pl_def pointer to plugin definition
  */
-static int
-olsr_load_dl(char *libname, struct plugin_param *params)
-{
-  struct olsr_plugin *plugin = olsr_malloc(sizeof(struct olsr_plugin), "Plugin entry");
-  int rv;
+void
+olsr_unhookup_plugin(struct olsr_plugin *pl_def) {
+  avl_delete(&plugin_tree, &pl_def->p_node);
+}
 
-  if (olsr_cnf->dlPath) {
-    char *path = olsr_malloc(strlen(olsr_cnf->dlPath) + strlen(libname) + 1, "Memory for absolute library path");
-    strcpy(path, olsr_cnf->dlPath);
-    strcat(path, libname);
-    OLSR_INFO(LOG_PLUGINS, "---------- LOADING LIBRARY %s from %s (%s)----------\n", libname, olsr_cnf->dlPath, path);
-    plugin->dlhandle = dlopen(path, RTLD_NOW);
-    free(path);
-  } else {
-    OLSR_INFO(LOG_PLUGINS, "---------- LOADING LIBRARY %s ----------\n", libname);
-    plugin->dlhandle = dlopen(libname, RTLD_NOW);
+struct olsr_plugin *olsr_get_plugin(char *libname) {
+  struct avl_node *node;
+  if ((node = avl_find(&plugin_tree, libname)) != NULL) {
+    return plugin_node2tree(node);
   }
-  if (plugin->dlhandle == NULL) {
-    const int save_errno = errno;
-    OLSR_ERROR(LOG_PLUGINS, "DL loading failed: \"%s\"!\n", dlerror());
-    free(plugin);
-    errno = save_errno;
-    return -1;
+  return NULL;
+}
+
+void
+olsr_init_pluginsystem(bool fail_fast) {
+  struct plugin_entry *entry;
+  struct olsr_plugin *plugin;
+
+  plugin_mem_cookie = olsr_alloc_cookie("Plugin handle", OLSR_COOKIE_TYPE_MEMORY);
+  olsr_cookie_set_memory_size(plugin_mem_cookie, sizeof(struct olsr_plugin));
+
+  /* could already be initialized */
+  if (!plugin_tree_initialized) {
+    avl_init(&plugin_tree, avl_comp_strcasecmp);
+    plugin_tree_initialized = true;
   }
 
-  rv = olsr_add_dl(plugin);
-  if (rv == -1) {
-    const int save_errno = errno;
-    dlclose(plugin->dlhandle);
-    free(plugin);
-    errno = save_errno;
-    OLSR_ERROR(LOG_PLUGINS, "---------- LIBRARY %s FAILED ----------\n\n", libname);
-    return -1;
+  OLSR_INFO(LOG_PLUGINS, "Activating configured plugins...\n");
+  /* first load anything requested but not already loaded */
+  for (entry = olsr_cnf->plugins; entry != NULL; entry = entry->next) {
+    if (olsr_load_plugin(entry->name) == NULL) {
+      if (fail_fast) {
+        OLSR_ERROR(LOG_PLUGINS, "Cannot load plugin %s.\n", entry->name);
+        olsr_exit(1);
+      }
+      OLSR_WARN(LOG_PLUGINS, "Cannot load plugin %s.\n", entry->name);
+    }
   }
 
-  plugin->params = params;
+  /* now hookup parameters to plugins */
+  for (entry = olsr_cnf->plugins; entry != NULL; entry = entry->next) {
+    plugin = olsr_get_plugin(entry->name);
+    if (plugin == NULL) {
+      if (fail_fast) {
+        OLSR_ERROR(LOG_PLUGINS, "Internal error in plugin storage tree, cannot find plugin %s\n", entry->name);
+        olsr_exit(1);
+      }
+      OLSR_WARN(LOG_PLUGINS, "Internal error in plugin storage tree, cannot find plugin %s\n", entry->name);
+    }
 
-  /* Initialize the plugin */
-  if (init_olsr_plugin(plugin) != 0) {
-    const int save_errno = errno;
-    dlclose(plugin->dlhandle);
-    free(plugin);
-    errno = save_errno;
-    OLSR_ERROR(LOG_PLUGINS, "---------- LIBRARY %s FAILED ----------\n\n", libname);
-    return -1;
+    plugin->params = entry->params;
   }
 
-  /* queue */
-  plugin->next = olsr_plugins;
-  olsr_plugins = plugin;
+  /* activate all plugins (configured and static linked ones) */
+  OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin) {
+    if (olsr_activate_plugin(plugin)) {
+      if (fail_fast) {
+        OLSR_ERROR(LOG_PLUGINS, "Error, cannot activate plugin %s.\n", entry->name);
+        olsr_exit(1);
+      }
+      OLSR_WARN(LOG_PLUGINS, "Error, cannot activate plugin %s.\n", entry->name);
+    }
+  } OLSR_FOR_ALL_PLUGIN_ENTRIES_END(plugin)
+  OLSR_INFO(LOG_PLUGINS, "All preconfigured plugins loaded.\n");
+}
 
-  OLSR_INFO(LOG_PLUGINS, "---------- LIBRARY %s LOADED ----------\n\n", libname);
-  return rv;
+void
+olsr_destroy_pluginsystem(void) {
+  struct olsr_plugin *plugin;
+
+  OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin) {
+    olsr_deactivate_plugin(plugin);
+    olsr_unload_plugin(plugin);
+  } OLSR_FOR_ALL_PLUGIN_ENTRIES_END(plugin)
 }
 
-static int
-olsr_add_dl(struct olsr_plugin *plugin)
-{
+static struct olsr_plugin *
+olsr_load_legacy_plugin(char *libname, void *dlhandle) {
   get_interface_version_func get_interface_version;
   get_plugin_parameters_func get_plugin_parameters;
+  plugin_init_func init_plugin;
+
   int plugin_interface_version = -1;
+  struct olsr_plugin *plugin = NULL;
 
   /* Fetch the interface version function, 3 different ways */
-  get_interface_version = dlsym(plugin->dlhandle, "olsrd_plugin_interface_version");
-  if (NULL != get_interface_version) {
-    plugin_interface_version = get_interface_version();
+  get_interface_version = dlsym(dlhandle, "olsrd_plugin_interface_version");
+  if (get_interface_version == NULL) {
+    OLSR_WARN(LOG_PLUGINS, "Warning, cannot determine plugin version of '%s'\n", libname);
+    return NULL;
   }
-  OLSR_DEBUG(LOG_PLUGINS, "Checking plugin interface version: %d - OK\n", plugin_interface_version);
 
-  if (plugin_interface_version < 5) {
+  plugin_interface_version = get_interface_version();
+
+  if (plugin_interface_version != 5) {
     /* old plugin interface */
-    OLSR_ERROR(LOG_PLUGINS, "YOU ARE USING AN OLD DEPRECATED PLUGIN INTERFACE!\n"
-               "DETECTED VERSION %d AND THE CURRENT VERSION IS %d\n"
-               "PLEASE UPGRADE YOUR PLUGIN!\n", plugin_interface_version, MOST_RECENT_PLUGIN_INTERFACE_VERSION);
-    return -1;
+    OLSR_ERROR(LOG_PLUGINS, "Failed to load plugin, version %d is too old\n",
+               plugin_interface_version);
+    return NULL;
   }
 
   /* Fetch the init function */
-  plugin->plugin_init = dlsym(plugin->dlhandle, "olsrd_plugin_init");
-  if (plugin->plugin_init == NULL) {
-    OLSR_ERROR(LOG_PLUGINS, "Trying to fetch plugin init function: FAILED: \"%s\"\n", dlerror());
-    return -1;
+  init_plugin = dlsym(dlhandle, "olsrd_plugin_init");
+  if (init_plugin == NULL) {
+    OLSR_WARN(LOG_PLUGINS, "Failed to fetch plugin init function: %s\n", dlerror());
+    return NULL;
   }
 
-
-  get_plugin_parameters = dlsym(plugin->dlhandle, "olsrd_get_plugin_parameters");
-  if (get_plugin_parameters != NULL) {
-    (*get_plugin_parameters) (&plugin->plugin_parameters, &plugin->plugin_parameters_size);
-  } else {
-    OLSR_ERROR(LOG_PLUGINS, "Trying to fetch parameter table and it's size: FAILED\n");
-    return -1;
+  get_plugin_parameters = dlsym(dlhandle, "olsrd_get_plugin_parameters");
+  if (get_plugin_parameters == NULL) {
+    OLSR_WARN(LOG_PLUGINS, "Failed to fetch plugin parameters: %s\n", dlerror());
+    return NULL;
   }
-  return 0;
-}
 
+  OLSR_DEBUG(LOG_PLUGINS, "Got plugin %s, version: %d - OK\n", libname, plugin_interface_version);
+
+  /* initialize plugin structure */
+  plugin = (struct olsr_plugin *)olsr_cookie_malloc(plugin_mem_cookie);
+  plugin->p_name = strdup(libname);
+  plugin->p_version = plugin_interface_version;
+  plugin->p_post_init = init_plugin;
+
+  plugin->p_node.key = plugin->p_name;
+  plugin->dlhandle = dlhandle;
+
+  /* get parameters */
+  get_plugin_parameters(&plugin->p_param, &plugin->p_param_cnt);
+
+  avl_insert(&plugin_tree, &plugin->p_node, AVL_DUP_NO);
+  return plugin;
+}
 
 /**
- *Initialize a loaded plugin
- *This includes sending information
- *from olsrd to the plugin and
- *register the functions from the plugin with olsrd
+ *Try to load a shared library
  *
- *@param entry the plugin to initialize
+ *@param libname the name of the library(file)
  *
- *@return -1 if there was an error
+ *@return dlhandle
  */
-static int
-init_olsr_plugin(struct olsr_plugin *entry)
+struct olsr_plugin *
+olsr_load_plugin(char *libname)
 {
-  int rv = 0;
+  void *dlhandle;
+  struct olsr_plugin *plugin;
+
+  /* see if the plugin is there */
+  if ((plugin = olsr_get_plugin(libname)) != NULL) {
+    return plugin;
+  }
+
+  /* attempt to load the plugin */
+  if (olsr_cnf->dlPath) {
+    char *path = olsr_malloc(strlen(olsr_cnf->dlPath) + strlen(libname) + 1, "Memory for absolute library path");
+    strcpy(path, olsr_cnf->dlPath);
+    strcat(path, libname);
+    OLSR_INFO(LOG_PLUGINS, "Loading plugin %s from %s\n", libname, path);
+    dlhandle = dlopen(path, RTLD_NOW);
+    free(path);
+  } else {
+    OLSR_INFO(LOG_PLUGINS, "Loading plugin %s\n", libname);
+    dlhandle = dlopen(libname, RTLD_NOW);
+  }
+  if (dlhandle == NULL) {
+    OLSR_ERROR(LOG_PLUGINS, "DL loading failed: \"%s\"!\n", dlerror());
+    return NULL;
+  }
+
+  /* version 6 plugins should be in the tree now*/
+  if ((plugin = olsr_get_plugin(libname)) != NULL) {
+    plugin->dlhandle = dlhandle;
+    return plugin;
+  }
+
+  /* try to load a legacy plugin */
+  return olsr_load_legacy_plugin(libname, dlhandle);
+}
+
+bool
+olsr_unload_plugin(struct olsr_plugin *plugin) {
+  bool legacy = false;
+
+  if (plugin->active) {
+    olsr_deactivate_plugin(plugin);
+  }
+
+  if (plugin->dlhandle == NULL) {
+    /* this is a static plugin, it cannot be unloaded */
+    return true;
+  }
+
+  OLSR_INFO(LOG_PLUGINS, "Unloading plugin %s\n", plugin->p_name);
+
+  /* remove first from tree */
+  avl_delete(&plugin_tree, &plugin->p_node);
+
+  legacy = plugin->p_version == 5;
+
+  /* cleanup */
+  if (plugin->dlhandle) {
+    dlclose(plugin->dlhandle);
+  }
+
+  /*
+   * legacy must be cached because it plugin memory will be gone after dlclose() for
+   * modern plugins
+   */
+  if (legacy) {
+    free(plugin->p_name);
+    olsr_cookie_free(plugin_mem_cookie, plugin);
+  }
+  return false;
+}
+
+bool olsr_activate_plugin(struct olsr_plugin *plugin) {
   struct plugin_param *params;
-  OLSR_INFO(LOG_PLUGINS, "Setting parameters of plugin...\n");
-  for (params = entry->params; params != NULL; params = params->next) {
-    OLSR_INFO(LOG_PLUGINS, "\"%s\"/\"%s\"... ", params->key, params->value);
-    if (entry->plugin_parameters_size != 0) {
-      unsigned int i;
-      int rc = 0;
-      for (i = 0; i < entry->plugin_parameters_size; i++) {
-        if (0 == entry->plugin_parameters[i].name[0] || 0 == strcasecmp(entry->plugin_parameters[i].name, params->key)) {
-          /* we have found it! */
-          rc = entry->plugin_parameters[i].set_plugin_parameter(params->value, entry->plugin_parameters[i].data,
-                                                                0 ==
-                                                                entry->plugin_parameters[i].
-                                                                name[0] ? (set_plugin_parameter_addon) params->key : entry->
-                                                                plugin_parameters[i].addon);
-          if (rc != 0) {
-            OLSR_ERROR(LOG_PLUGINS, "\nFatal error in plugin parameter \"%s\"/\"%s\"\n", params->key, params->value);
-            rv = -1;
-          }
-          break;
+  unsigned int i;
+
+  if (plugin->active) {
+    OLSR_DEBUG(LOG_PLUGINS, "Plugin %s is already active.\n", plugin->p_name);
+    return false;
+  }
+
+  if (plugin->p_pre_init != NULL) {
+    if (plugin->p_pre_init()) {
+      OLSR_WARN(LOG_PLUGINS, "Error, pre init failed for plugin %s\n", plugin->p_name);
+      return true;
+    }
+    OLSR_DEBUG(LOG_PLUGINS, "Pre initialization of plugin %s successful\n", plugin->p_name);
+  }
+
+  /* initialize parameters */
+  OLSR_INFO(LOG_PLUGINS, "Activating plugin %s\n", plugin->p_name);
+  for (params = plugin->params; params != NULL; params = params->next) {
+    OLSR_INFO_NH(LOG_PLUGINS, "    \"%s\" = \"%s\"... ", params->key, params->value);
+
+    for (i = 0; i < plugin->p_param_cnt; i++) {
+      if (0 == plugin->p_param[i].name[0] || 0 == strcasecmp(plugin->p_param[i].name, params->key)) {
+        /* we have found it! */
+        if (plugin->p_param[i].set_plugin_parameter(params->value, plugin->p_param[i].data,
+            0 == plugin->p_param[i].name[0] ? (set_plugin_parameter_addon) params->key : plugin->p_param[i].addon)) {
+          OLSR_DEBUG(LOG_PLUGINS, "Bad plugin parameter \"%s\" = \"%s\"... ", params->key, params->value);
+          return true;
         }
+        break;
       }
-      if (i >= entry->plugin_parameters_size) {
-        OLSR_INFO(LOG_PLUGINS, "Ignored parameter \"%s\"\n", params->key);
-      } else if (rc == 0) {
-        OLSR_INFO(LOG_PLUGINS, "%s: OK\n", params->key);
-      } else {
-        OLSR_ERROR(LOG_PLUGINS, "%s: FAILED\n", params->key);
-        rv = -1;
-      }
-    } else {
-      OLSR_ERROR(LOG_PLUGINS, "I don't know what to do with \"%s\"!\n", params->key);
-      rv = -1;
     }
+
+    if (i == plugin->p_param_cnt) {
+      OLSR_INFO_NH(LOG_PLUGINS, "    Ignored parameter \"%s\"\n", params->key);
+    }
+  }
+
+  if (plugin->p_post_init != NULL) {
+    if (plugin->p_post_init() != (plugin->p_version == 5 ? 1 : 0)) {
+      OLSR_WARN(LOG_PLUGINS, "Error, post init failed for plugin %s\n", plugin->p_name);
+      return true;
+    }
+    OLSR_DEBUG(LOG_PLUGINS, "Post initialization of plugin %s successful\n", plugin->p_name);
   }
+  plugin->active = true;
 
-  OLSR_INFO(LOG_PLUGINS, "Running plugin_init function...\n");
-  entry->plugin_init();
-  return rv;
+  if (plugin->p_author != NULL && plugin->p_descr != NULL) {
+    OLSR_INFO(LOG_PLUGINS, "Plugin '%s' (%s) by %s activated sucessfully\n",
+        plugin->p_descr, plugin->p_name, plugin->p_author);
+  }
+  else {
+    OLSR_INFO(LOG_PLUGINS, "%sPlugin '%s' activated sucessfully\n",
+        plugin->p_version != 6 ? "Legacy " : "", plugin->p_name);
+  }
+
+  return false;
 }
 
+bool olsr_deactivate_plugin(struct olsr_plugin *plugin) {
+  if (!plugin->active) {
+    OLSR_DEBUG(LOG_PLUGINS, "Plugin %s is not active.\n", plugin->p_name);
+    return false;
+  }
 
-/**
- *Close all loaded plugins
- */
-void
-olsr_close_plugins(void)
-{
-  struct olsr_plugin *entry;
-
-  OLSR_INFO(LOG_PLUGINS, "Closing plugins...\n");
-  while (olsr_plugins) {
-    entry = olsr_plugins;
-    olsr_plugins = entry->next;
-    dlclose(entry->dlhandle);
-    free(entry);
+  OLSR_INFO(LOG_PLUGINS, "Deactivating plugin %s\n", plugin->p_name);
+  if (plugin->p_pre_cleanup != NULL) {
+    if (plugin->p_pre_cleanup()) {
+      OLSR_DEBUG(LOG_PLUGINS, "Plugin %s cannot be deactivated, error in pre cleanup\n", plugin->p_name);
+      return true;
+    }
+    OLSR_DEBUG(LOG_PLUGINS, "Pre cleanup of plugin %s successful\n", plugin->p_name);
+  }
+
+  plugin->active = false;
+
+  if (plugin->p_post_cleanup != NULL) {
+    plugin->p_post_cleanup();
   }
+
+  return false;
 }
 
 /*
index 7a32e52..3825b0c 100644 (file)
 #include "plugin.h"
 #include "olsr_types.h"
 
-/* all */
-typedef int (*plugin_init_func) (void);
-typedef int (*get_interface_version_func) (void);
+#include "common/avl.h"
+#include "common/list.h"
+
+#define DEFINE_PLUGIN6(descr, author, pre_init, post_init, pre_cleanup, post_cleanup, deactivate, parameter) \
+static struct olsr_plugin olsr_internal_plugin_definition = { \
+  .p_name = (char*) PLUGIN_FULLNAME , .p_descr = (char*)descr, .p_author = (char*)author, \
+  .p_pre_init = pre_init, .p_post_init = post_init, .p_pre_cleanup = pre_cleanup, .p_post_cleanup = post_cleanup, \
+  .p_deactivate = deactivate, .p_version = 6, .p_param = parameter, .p_param_cnt = ARRAYSIZE(parameter) \
+}; \
+static void hookup_plugin_definition (void) __attribute__ ((constructor)); \
+static void hookup_plugin_definition (void) { \
+  olsr_hookup_plugin(&olsr_internal_plugin_definition); \
+}
 
 /* version 5 */
+typedef int (*plugin_init_func) (void);
+typedef int (*get_interface_version_func) (void);
 typedef void (*get_plugin_parameters_func) (const struct olsrd_plugin_parameters ** params, unsigned int *size);
 
 struct olsr_plugin {
-  /* The handle */
-  void *dlhandle;
+  struct avl_node p_node;
 
-  struct plugin_param *params;
-  int plugin_interface_version;
+  /* plugin information */
+  char *p_name;
+  char *p_descr;
+  char *p_author;
+  bool p_deactivate;    /* plugin can be deactivated */
+
+  /* function pointers */
+  int (*p_pre_init) (void);
+  int (*p_post_init) (void);
+  int (*p_pre_cleanup) (void);
+  void (*p_post_cleanup) (void);
 
-  plugin_init_func plugin_init;
+  /* plugin interface version */
+  int p_version;
 
-  /* version 5 */
-  const struct olsrd_plugin_parameters *plugin_parameters;
-  unsigned int plugin_parameters_size;
+  /* plugin list of possible arguments */
+  const struct olsrd_plugin_parameters *p_param;
 
-  struct olsr_plugin *next;
+  /* number of arguments */
+  unsigned int p_param_cnt;
+
+  /* internal olsr data */
+  void *dlhandle;
+  struct plugin_param *params;
+  bool active;
 };
 
-void olsr_load_plugins(void);
+AVLNODE2STRUCT(plugin_node2tree, struct olsr_plugin, p_node)
+
+#define OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin) \
+{ \
+  struct avl_node *plugin_node, *next_plugin_node; \
+  for (plugin_node = avl_walk_first(&plugin_tree); \
+    plugin_node; plugin_node = next_plugin_node) { \
+    next_plugin_node = avl_walk_next(plugin_node); \
+    plugin = plugin_node2tree(plugin_node);
+#define OLSR_FOR_ALL_PLUGIN_ENTRIES_END(plugin) }}
+
+struct olsr_plugin *EXPORT(olsr_get_plugin)(char *libname);
+
+void EXPORT(olsr_hookup_plugin) (struct olsr_plugin *plugin);
+void EXPORT(olsr_unhookup_plugin) (struct olsr_plugin *plugin);
+
+void EXPORT(olsr_init_pluginsystem)(bool);
+void EXPORT(olsr_destroy_pluginsystem)(void);
+
+struct olsr_plugin *EXPORT(olsr_load_plugin)(char *);
+bool EXPORT(olsr_unload_plugin)(struct olsr_plugin *);
 
-void olsr_close_plugins(void);
+bool EXPORT(olsr_activate_plugin)(struct olsr_plugin *);
+bool EXPORT(olsr_deactivate_plugin)(struct olsr_plugin *);
 
-int olsr_plugin_io(int, void *, size_t);
+extern struct avl_tree EXPORT(plugin_tree);
 
 #endif