diff --git a/CMakeLists.txt b/CMakeLists.txt index c71762e112..e8ed7975b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,10 +31,12 @@ configure_file(bro-path-dev.in ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.sh "export BROPATH=`${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n" "export BROMAGIC=\"${BRO_MAGIC_SOURCE_PATH}\"\n" + "export BRO_PLUGIN_PATH=\"${CMAKE_CURRENT_BINARY_DIR}/src:${BRO_PLUGIN_INSTALL_PATH}\"\n" "export PATH=\"${CMAKE_CURRENT_BINARY_DIR}/src\":$PATH\n") file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.csh "setenv BROPATH `${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n" "setenv BROMAGIC \"${BRO_MAGIC_SOURCE_PATH}\"\n" + "setenv BRO_PLUGIN_PATH \"${CMAKE_CURRENT_BINARY_DIR}/src:${BRO_PLUGIN_INSTALL_PATH}\"\n" "setenv PATH \"${CMAKE_CURRENT_BINARY_DIR}/src\":$PATH\n") file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION LIMIT_COUNT 1) diff --git a/aux/bro-aux b/aux/bro-aux index 14457e3f22..4dafab5aa0 160000 --- a/aux/bro-aux +++ b/aux/bro-aux @@ -1 +1 @@ -Subproject commit 14457e3f222bd2678376e7bbbd15a1497df1828e +Subproject commit 4dafab5aa006173f80ae3fea4adb66117e574f6f diff --git a/aux/btest b/aux/btest index 26c3136d56..ce366206e3 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit 26c3136d56493017bc33c5a2f22ae393d585c2d9 +Subproject commit ce366206e3407e534a786ad572c342e9f9fef26b diff --git a/cmake b/cmake index 14141bc12b..37c0425715 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 14141bc12b7a904619101d2caa1b1eee8ec8fbb6 +Subproject commit 37c0425715e71fc175b4b9527443b8f0174f1292 diff --git a/doc/devel/plugins.rst b/doc/devel/plugins.rst index f00bbb4d2c..e9b8bf337c 100644 --- a/doc/devel/plugins.rst +++ b/doc/devel/plugins.rst @@ -98,20 +98,20 @@ option: That looks quite good, except for the dummy description that we should replace with something nicer so that users will know what our plugin -is about. We do this by editing the ``BRO_PLUGIN_DESCRIPTION`` line -in ``src/Plugin.cc``, like this: +is about. We do this by editing the ``config.description`` line in +``src/Plugin.cc``, like this: - # cat src/Plugin.cc - - #include - - BRO_PLUGIN_BEGIN(Demo, Rot13) - BRO_PLUGIN_VERSION(1); - BRO_PLUGIN_DESCRIPTION("Caesar cipher rotating a string's characters by 13 places."); - BRO_PLUGIN_BIF_FILE(consts); - BRO_PLUGIN_BIF_FILE(events); - BRO_PLUGIN_BIF_FILE(functions); - BRO_PLUGIN_END + [...] + plugin::Configuration Configure() + { + plugin::Configuration config; + config.name = "Demo::Rot13"; + config.description = "Caesar cipher rotating a string's characters by 13 places."; + config.version.major = 1; + config.version.minor = 0; + return config; + } + [...] # make [...] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8694264dcd..05def0f578 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,8 @@ include_directories(BEFORE set(bro_ALL_GENERATED_OUTPUTS CACHE INTERNAL "automatically generated files" FORCE) # This collects bif inputs that we'll load automatically. -set(bro_AUTO_BIFS CACHE INTERNAL "BIFs for automatic inclusion" FORCE) +set(bro_AUTO_BIFS CACHE INTERNAL "BIFs for automatic inclusion" FORCE) +set(bro_REGISTER_BIFS CACHE INTERNAL "BIFs for automatic registering" FORCE) # If TRUE, use CMake's object libraries for sub-directories instead of # static libraries. This requires CMake >= 2.8.8. @@ -164,8 +165,8 @@ if ( NOT bro_HAVE_OBJECT_LIBRARIES ) foreach (_plugin ${bro_PLUGIN_LIBS}) string(REGEX REPLACE "plugin-" "" _plugin "${_plugin}") string(REGEX REPLACE "-" "_" _plugin "${_plugin}") - set(_decl "namespace plugin { namespace ${_plugin} { class Plugin; extern Plugin __plugin; } };") - set(_use "i += (size_t)(&(plugin::${_plugin}::__plugin));") + set(_decl "namespace plugin { namespace ${_plugin} { class Plugin; extern Plugin plugin; } };") + set(_use "i += (size_t)(&(plugin::${_plugin}::plugin));") set(__BRO_DECL_PLUGINS "${__BRO_DECL_PLUGINS}${_decl}\n") set(__BRO_USE_PLUGINS "${__BRO_USE_PLUGINS}${_use}\n") endforeach() @@ -368,7 +369,6 @@ set(bro_SRCS plugin/TaggedComponent.h plugin/Manager.cc plugin/Plugin.cc - plugin/Macros.h nb_dns.c digest.h @@ -397,12 +397,14 @@ add_custom_target(generate_outputs_stage1) add_dependencies(generate_outputs_stage1 ${bro_ALL_GENERATED_OUTPUTS}) # Target to create the joint includes files that pull in the bif code. -bro_bif_create_includes(generate_outputs_stage2 ${CMAKE_CURRENT_BINARY_DIR} "${bro_AUTO_BIFS}") -add_dependencies(generate_outputs_stage2 generate_outputs_stage1) +bro_bif_create_includes(generate_outputs_stage2a ${CMAKE_CURRENT_BINARY_DIR} "${bro_AUTO_BIFS}") +bro_bif_create_register(generate_outputs_stage2b ${CMAKE_CURRENT_BINARY_DIR} "${bro_REGISTER_BIFS}") +add_dependencies(generate_outputs_stage2a generate_outputs_stage1) +add_dependencies(generate_outputs_stage2b generate_outputs_stage1) # Global target to trigger creation of autogenerated code. add_custom_target(generate_outputs) -add_dependencies(generate_outputs generate_outputs_stage2) +add_dependencies(generate_outputs generate_outputs_stage2a generate_outputs_stage2b) # Build __load__.bro files for standard *.bif.bro. bro_bif_create_loader(bif_loader ${CMAKE_BINARY_DIR}/scripts/base/bif) diff --git a/src/Func.cc b/src/Func.cc index f08cf095f0..16f6b4686d 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -606,6 +606,7 @@ void builtin_error(const char* msg, BroObj* arg) #include "strings.bif.func_def" #include "__all__.bif.cc" // Autogenerated for compiling in the bif_target() code. +#include "__all__.bif.register.cc" // Autogenerated for compiling in the bif_target() code. void init_builtin_funcs() { diff --git a/src/analyzer/protocol/http/CMakeLists.txt b/src/analyzer/protocol/http/CMakeLists.txt index d1fbed07f0..663d343eb3 100644 --- a/src/analyzer/protocol/http/CMakeLists.txt +++ b/src/analyzer/protocol/http/CMakeLists.txt @@ -8,4 +8,3 @@ bro_plugin_cc(HTTP.cc Plugin.cc) bro_plugin_bif(events.bif) bro_plugin_bif(functions.bif) bro_plugin_end() - diff --git a/src/analyzer/protocol/http/HTTP.h b/src/analyzer/protocol/http/HTTP.h index 8339e48e3b..7757b99f7f 100644 --- a/src/analyzer/protocol/http/HTTP.h +++ b/src/analyzer/protocol/http/HTTP.h @@ -9,7 +9,7 @@ #include "analyzer/protocol/mime/MIME.h" #include "binpac_bro.h" #include "IPAddr.h" -#include "events.bif.h" +#include "analyzer/protocol/http/events.bif.h" #include "HTTP.h" diff --git a/src/analyzer/protocol/http/functions.bif b/src/analyzer/protocol/http/functions.bif index 6db5e8b862..6ef6fecb81 100644 --- a/src/analyzer/protocol/http/functions.bif +++ b/src/analyzer/protocol/http/functions.bif @@ -1,6 +1,6 @@ %%{ -#include "protocol/http/HTTP.h" +#include "analyzer/protocol/http/HTTP.h" %%} ## Skips the data of the HTTP entity. diff --git a/src/builtin-func.l b/src/builtin-func.l index 63df96eb80..076d2bf99b 100644 --- a/src/builtin-func.l +++ b/src/builtin-func.l @@ -152,6 +152,7 @@ FILE* fp_bro_init = 0; FILE* fp_func_def = 0; FILE* fp_func_h = 0; FILE* fp_func_init = 0; +FILE* fp_func_register = 0; FILE* fp_netvar_h = 0; FILE* fp_netvar_def = 0; FILE* fp_netvar_init = 0; @@ -190,6 +191,7 @@ void init_alternative_mode() fp_func_h = open_output_file("h"); fp_func_def = open_output_file("cc"); fp_func_init = open_output_file("init.cc"); + fp_func_register = plugin ? open_output_file("register.cc") : NULL; fp_netvar_h = fp_func_h; fp_netvar_def = fp_func_def; @@ -207,6 +209,9 @@ void init_alternative_mode() fprintf(fp_func_h, "// %s\n\n", auto_gen_comment); fprintf(fp_func_init, "// %s\n\n", auto_gen_comment); + if ( fp_func_register ) + fprintf(fp_func_register, "// %s\n\n", auto_gen_comment); + static char guard[1024]; if ( getcwd(guard, sizeof(guard)) == NULL ) { @@ -240,20 +245,36 @@ void init_alternative_mode() strncpy(name, input_filename, sizeof(name)); char* dot = strchr(name, '.'); if ( dot ) - *dot = '\0'; + *dot = '\0'; - if ( plugin ) - { - fprintf(fp_func_init, "\n"); - fprintf(fp_func_init, "#include \n"); - fprintf(fp_func_init, "#include \n"); - fprintf(fp_func_init, "#include \"plugin/Plugin.h\"\n"); - fprintf(fp_func_init, "#include \"%s.h\"\n", input_filename); - fprintf(fp_func_init, "\n"); - fprintf(fp_func_init, "namespace plugin { namespace %s {\n", plugin); - fprintf(fp_func_init, "\n"); - fprintf(fp_func_init, "void __bif_%s_init(plugin::Plugin* plugin)\n", name); - fprintf(fp_func_init, "\t{\n"); + if ( plugin ) + { + static char plugin_canon[1024]; + strncpy(plugin_canon, plugin, sizeof(plugin_canon)); + char* colon = strstr(plugin_canon, "::"); + + if ( colon ) { + *colon = '_'; + memmove(colon + 1, colon + 2, plugin_canon + strlen(plugin_canon) - colon); + } + + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "#include \n"); + fprintf(fp_func_init, "#include \n"); + fprintf(fp_func_init, "#include \"plugin/Plugin.h\"\n"); + fprintf(fp_func_init, "#include \"%s.h\"\n", input_filename); + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "namespace plugin { namespace %s {\n", plugin_canon); + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "void __bif_%s_init(plugin::Plugin* plugin)\n", name); + fprintf(fp_func_init, "\t{\n"); + + fprintf(fp_func_register, "#include \"plugin/Manager.h\"\n"); + fprintf(fp_func_register, "\n"); + fprintf(fp_func_register, "namespace plugin { namespace %s {\n", plugin_canon); + fprintf(fp_func_register, "void __bif_%s_init(plugin::Plugin* plugin);\n", name); + fprintf(fp_func_register, "::plugin::__RegisterBif __register_bifs_%s_%s(\"%s\", __bif_%s_init);\n", plugin_canon, name, plugin, name); + fprintf(fp_func_register, "} }\n"); } } @@ -262,14 +283,15 @@ void finish_alternative_mode() fprintf(fp_func_h, "\n"); fprintf(fp_func_h, "#endif\n"); - if ( plugin ) - { - fprintf(fp_func_init, "\n"); - fprintf(fp_func_init, "\t}\n"); - fprintf(fp_func_init, "} }\n"); - fprintf(fp_func_init, "\n"); - } - } + if ( plugin ) + { + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "\t}\n"); + fprintf(fp_func_init, "} }\n"); + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "\n"); + } + } int main(int argc, char* argv[]) { @@ -364,6 +386,7 @@ void close_all_output_files(void) close_if_open(&fp_func_h); close_if_open(&fp_func_def); close_if_open(&fp_func_init); + close_if_open(&fp_func_register); if ( ! alternative_mode ) { @@ -389,6 +412,7 @@ void err_exit(void) remove_file("func_h"); remove_file("func_def"); remove_file("func_init"); + remove_file("func_register"); remove_file("netvar_h"); remove_file("netvar_def"); remove_file("netvar_init"); diff --git a/src/plugin/Macros.h b/src/plugin/Macros.h deleted file mode 100644 index 3657fb1e40..0000000000 --- a/src/plugin/Macros.h +++ /dev/null @@ -1,138 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -/** - * A set of macros wrapping internal logic for defining plugins and - * components. - */ - -#ifndef PLUGIN_MACROS_H -#define PLUGIN_MACROS_H - -#include "analyzer/Component.h" -#include "file_analysis/Component.h" - -/** - * The current plugin API version. Plugins that won't match this version will - * be rejected. - */ -#define BRO_PLUGIN_API_VERSION 1 - -/** - * Starts the definition of a new plugin. - * - * @param _ns: A namespace for the plugin. All plugins compiled in statically - * must use the reserved "Bro" namespace. External plugins should define - * their own namespace to avoid collisions. - * - * @param _name: The plugin's name. The combiniation of namespace and name - * must be unique across all loaded plugins. - */ -#define BRO_PLUGIN_BEGIN(_ns, _name) \ - namespace plugin { namespace _ns ## _ ## _name { \ - class Plugin : public plugin::Plugin { \ - protected: \ - void InitPreScript() \ - { \ - SetName(#_ns "::" #_name); \ - SetVersion(-1); \ - SetAPIVersion(BRO_PLUGIN_API_VERSION); \ - SetDynamicPlugin(! BRO_PLUGIN_INTERNAL_BUILD);\ - -/** - * Ends the definition of a plugin. - */ -#define BRO_PLUGIN_END \ - } \ - }; \ - \ - Plugin __plugin; \ - } } - -/** - * Provides a textual description for a plugin. - * - * @param d A string with the description. - */ -#define BRO_PLUGIN_DESCRIPTION(d) SetDescription(d) - -/** - * Defines a version of the plugin. The version is mostly informational for - * the user; if a plugin's functionality changes, the version should be - * increased. - * - * @param v An integer version. - */ -#define BRO_PLUGIN_VERSION(v) SetVersion(v) - -/** - * Enables a hook for the plugin. Once enabled, Bro will call the - * corresponding virtual function. - * - * @param h The \a HookType to able. - */ -#define BRO_PLUGIN_ENABLE_HOOK(h) EnableHook(h) - -/** - * Adds script-level items defined in a \c *.bif file to what the plugin - * provides. - * - * @param file A string with the name of \c *.bif file. When loaded, the - * plugin will make all items defined in the file available to Bro's script - * interpreter. - */ -#define BRO_PLUGIN_BIF_FILE(file) \ - extern void __bif_##file##_init(plugin::Plugin*); \ - __AddBifInitFunction(&__bif_##file##_init); - -/** - * Defines a component implementing a protocol analyzer. - * - * @param tag A string with the analyzer's tag. This must be unique across - * all loaded analyzers and will translate into a corresponding \c ANALYZER_* - * constant at the script-layer. - * - * @param cls The class that implements the analyzer. It must be derived - * (directly or indirectly) from analyzer::Analyzer. - */ -#define BRO_PLUGIN_ANALYZER(tag, cls) \ - AddComponent(new ::analyzer::Component(tag, ::analyzer::cls::InstantiateAnalyzer)); - -/** - * Defines a component implementing a file analyzer. - * - * @param tag A string with the analyzer's tag. This must be unique across - * all loaded analyzers and will translate into a corresponding \c ANALYZER_* - * constant at the script-layer. - * - * @param cls The class that implements the analyzer. It must be derived - * (directly or indirectly) from file_analysis::Analyzer. - */ -#define BRO_PLUGIN_FILE_ANALYZER(tag, cls) \ - AddComponent(new ::file_analysis::Component(tag, ::file_analysis::cls::Instantiate)); - -/** - * Defines a component implementing a protocol analyzer class that will - * not be instantiated dynamically. This is for two use-cases: (1) abstract - * analyzer base classes that aren't instantiated directly; and (2) analyzers - * that are only instantiated explicitly by other Bro components, but not - * dynamically by the manager based on their tag (e.g., the ZIP analyzer is - * attached by the HTTP analyzer when corresponding content is found). - * - * @param tag A string with the analyzer's tag. This must be unique across - * all loaded analyzers and will translate into a corresponding \c ANALYZER_* - * constant at the script-layer. - */ -#define BRO_PLUGIN_ANALYZER_BARE(tag) \ - AddComponent(new ::analyzer::Component(tag, 0)); - -/** - * Defines a component implementating a support analyzer. - * - * @param tag A string with the analyzer's tag. This must be unique across - * all loaded analyzers and will translate into a corresponding \c ANALYZER_* - * constant at the script-layer. - */ -#define BRO_PLUGIN_SUPPORT_ANALYZER(tag) \ - AddComponent(new ::analyzer::Component(tag, 0)); - -#endif diff --git a/src/plugin/Manager.cc b/src/plugin/Manager.cc index e5ec40f818..3450006695 100644 --- a/src/plugin/Manager.cc +++ b/src/plugin/Manager.cc @@ -83,8 +83,13 @@ void Manager::SearchDynamicPlugins(const std::string& dir) if ( name.empty() ) reporter->FatalError("empty plugin magic file %s", magic.c_str()); - // Record it, so that we can later activate it. + if ( dynamic_plugins.find(name) != dynamic_plugins.end() ) + { + DBG_LOG(DBG_PLUGINS, "Found already known plugin %s in %s, ignoring", name.c_str(), dir.c_str()); + return; + } + // Record it, so that we can later activate it. dynamic_plugins.insert(std::make_pair(name, dir)); DBG_LOG(DBG_PLUGINS, "Found plugin %s in %s", name.c_str(), dir.c_str()); @@ -124,6 +129,8 @@ void Manager::SearchDynamicPlugins(const std::string& dir) if ( st.st_mode & S_IFDIR ) SearchDynamicPlugins(path); } + + closedir(d); } bool Manager::ActivateDynamicPluginInternal(const std::string& name) @@ -202,6 +209,9 @@ bool Manager::ActivateDynamicPluginInternal(const std::string& name) if ( ! current_plugin ) reporter->FatalError("load plugin library %s did not instantiate a plugin", path); + current_plugin->SetDynamic(true); + current_plugin->DoConfigure(); + // We execute the pre-script initialization here; this in // fact could be *during* script initialization if we got // triggered via @load-plugin. @@ -267,11 +277,11 @@ static bool plugin_cmp(const Plugin* a, const Plugin* b) return a->Name() < b->Name(); } -bool Manager::RegisterPlugin(Plugin *plugin) +void Manager::RegisterPlugin(Plugin *plugin) { Manager::PluginsInternal()->push_back(plugin); - if ( current_dir.size() && current_sopath.size() ) + if ( current_dir.size() && current_sopath.size() ) // A dynamic plugin, record its location. plugin->SetPluginLocation(current_dir.c_str(), current_sopath.c_str()); @@ -279,7 +289,18 @@ bool Manager::RegisterPlugin(Plugin *plugin) PluginsInternal()->sort(plugin_cmp); current_plugin = plugin; - return true; + } + +void Manager::RegisterBifFile(const char* plugin, bif_init_func c) + { + bif_init_func_map* bifs = BifFilesInternal(); + + bif_init_func_map::iterator i = bifs->find(plugin); + + if ( i == bifs->end() ) + i = bifs->insert(std::make_pair(std::string(plugin), new bif_init_func_list())).first; + + i->second->push_back(c); } void Manager::InitPreScript() @@ -289,6 +310,7 @@ void Manager::InitPreScript() for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ ) { Plugin* plugin = *i; + plugin->DoConfigure(); plugin->InitPreScript(); } @@ -297,8 +319,18 @@ void Manager::InitPreScript() void Manager::InitBifs() { + bif_init_func_map* bifs = BifFilesInternal(); + for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ ) - (*i)->InitBifs(); + { + bif_init_func_map::const_iterator b = bifs->find((*i)->Name()); + + if ( b != bifs->end() ) + { + for ( bif_init_func_list::const_iterator j = b->second->begin(); j != b->second->end(); ++j ) + (**j)(*i); + } + } } void Manager::InitPostScript() @@ -339,6 +371,16 @@ Manager::plugin_list* Manager::PluginsInternal() return plugins; } +Manager::bif_init_func_map* Manager::BifFilesInternal() + { + static bif_init_func_map* bifs = 0; + + if ( ! bifs ) + bifs = new bif_init_func_map; + + return bifs; + } + static bool hook_cmp(std::pair a, std::pair b) { if ( a.first == b.first ) diff --git a/src/plugin/Manager.h b/src/plugin/Manager.h index 5c5c7430be..eb4b739963 100644 --- a/src/plugin/Manager.h +++ b/src/plugin/Manager.h @@ -20,12 +20,14 @@ namespace plugin { #define PLUGIN_HOOK_VOID(hook, method_call) \ if ( plugin_mgr->HavePluginForHook(plugin::hook) ) plugin_mgr->method_call; + /** * A singleton object managing all plugins. */ class Manager { public: + typedef void (*bif_init_func)(Plugin *); typedef std::list plugin_list; typedef Plugin::component_list component_list; @@ -218,7 +220,12 @@ public: * ownership, yet assumes the pointer will stay valid at least until * the Manager is destroyed. */ - static bool RegisterPlugin(Plugin* plugin); + static void RegisterPlugin(Plugin* plugin); + + /** + * Internal method that registers a bif file's init function for a plugin. + */ + static void RegisterBifFile(const char* plugin, bif_init_func c); private: bool ActivateDynamicPluginInternal(const std::string& name); @@ -251,6 +258,14 @@ private: // This is a static method so that plugins can register themselves // even before the manager exists. static plugin_list* PluginsInternal(); + + typedef std::list bif_init_func_list; + typedef std::map bif_init_func_map; + + // Returns a modifiable map of all bif files. This is a static method + // so that plugins can register their bifs even before the manager + // exists. + static bif_init_func_map* BifFilesInternal(); }; template @@ -274,6 +289,17 @@ std::list Manager::Components() const return result; } +/** + * Internal class used by bifcl-generated code to register its init functions at runtime. + */ +class __RegisterBif { +public: + __RegisterBif(const char* plugin, Manager::bif_init_func init) + { + Manager::RegisterBifFile(plugin, init); + } +}; + } /** diff --git a/src/plugin/Plugin.cc b/src/plugin/Plugin.cc index 000bb2af52..6bbcd57740 100644 --- a/src/plugin/Plugin.cc +++ b/src/plugin/Plugin.cc @@ -55,16 +55,7 @@ BifItem::~BifItem() Plugin::Plugin() { - name = ""; - description = ""; - - // These will be reset by the BRO_PLUGIN_* macros. - version = -9999; - api_version = -9999; dynamic = false; - base_dir = ""; - sopath = ""; - Manager::RegisterPlugin(this); } @@ -73,39 +64,29 @@ Plugin::~Plugin() Done(); } -const std::string& Plugin::Name() const +void Plugin::DoConfigure() { - return name; + config = Configure(); } -void Plugin::SetName(const std::string& arg_name) +const std::string& Plugin::Name() const { - name = arg_name; + return config.name; } const std::string& Plugin::Description() const { - return description; + return config.description; } -void Plugin::SetDescription(const std::string& arg_description) +VersionNumber Plugin::Version() const { - description = arg_description; - } - -int Plugin::Version() const - { - return dynamic ? version : 0; - } - -void Plugin::SetVersion(int arg_version) - { - version = arg_version; + return config.version; } int Plugin::APIVersion() const { - return api_version; + return config.api_version; } bool Plugin::DynamicPlugin() const @@ -123,22 +104,17 @@ const std::string& Plugin::PluginPath() const return sopath; } -void Plugin::SetAPIVersion(int arg_version) - { - api_version = arg_version; - } - -void Plugin::SetDynamicPlugin(bool arg_dynamic) - { - dynamic = arg_dynamic; - } - void Plugin::SetPluginLocation(const std::string& arg_dir, const std::string& arg_sopath) { base_dir = arg_dir; sopath = arg_sopath; } +void Plugin::SetDynamic(bool is_dynamic) + { + dynamic = is_dynamic; + } + void Plugin::InitPreScript() { } @@ -147,12 +123,6 @@ void Plugin::InitPostScript() { } -void Plugin::InitBifs() - { - for ( bif_init_func_list::const_iterator f = bif_inits.begin(); f != bif_inits.end(); f++ ) - (**f)(this); - } - Plugin::bif_item_list Plugin::BifItems() const { bif_item_list l1 = bif_items; @@ -193,11 +163,6 @@ bool Plugin::LoadBroFile(const std::string& file) return true; } -void Plugin::__AddBifInitFunction(bif_init_func c) - { - bif_inits.push_back(c); - } - void Plugin::AddBifItem(const std::string& name, BifItem::Type type) { BifItem bi(name, (BifItem::Type)type); @@ -254,24 +219,28 @@ void Plugin::HookUpdateNetworkTime(double network_time) void Plugin::Describe(ODesc* d) const { d->Add("Plugin: "); - d->Add(name); + d->Add(config.name); - if ( description.size() ) + if ( config.description.size() ) { d->Add(" - "); - d->Add(description); + d->Add(config.description); } if ( dynamic ) { - if ( version > 0 ) + d->Add(" (dynamic, "); + + if ( config.version ) { - d->Add(" (dynamic, version "); - d->Add(version); + d->Add("version "); + d->Add(config.version.major); + d->Add("."); + d->Add(config.version.minor); d->Add(")"); } else - d->Add(" (version not set)"); + d->Add("no version information)"); } else diff --git a/src/plugin/Plugin.h b/src/plugin/Plugin.h index 7da5a74c6f..5c3dd73b03 100644 --- a/src/plugin/Plugin.h +++ b/src/plugin/Plugin.h @@ -6,7 +6,9 @@ #include #include -#include "Macros.h" +#include "config.h" +#include "analyzer/Component.h" +#include "file_analysis/Component.h" class ODesc; class Func; @@ -14,8 +16,11 @@ class Event; namespace plugin { +#define BRO_PLUGIN_API_VERSION 2 + class Manager; class Component; +class Plugin; /** * Hook types that a plugin may define. Each label maps to the corresponding @@ -32,6 +37,45 @@ enum HookType { NUM_HOOKS, }; +/** + * Helper class to capture a plugin's version. A boolean operator evaluates + * to true if the version has been set. + */ +struct VersionNumber { + int major; //< Major version number; + int minor; //< Minor version number; + + VersionNumber() { major = minor = -1; } + + operator bool() const { return major >= 0 && minor >= 0; } +}; + +/** + * A class defining a plugin's static configuration parameters. + */ +class Configuration { +public: + std::string name; //< The plugin's name, including a namespace. Mandatory. + std::string description; //< A short textual description of the plugin. Mandatory. + VersionNumber version; //< THe plugin's version. Optional. + + Configuration(); + +private: + friend class Plugin; + int api_version; // Current BRO_PLUGIN_API_VERSION. Automatically set. + +}; + +// Note we inline this method here so that when plugins create an instance, +// *their* defaults will be used for the internal fields. +inline Configuration::Configuration() + { + name = ""; + description = ""; + api_version = BRO_PLUGIN_API_VERSION; + } + /** * A class describing an item defined in \c *.bif file. */ @@ -105,7 +149,7 @@ private: * Note that a plugin needs to explicitly register all the functionality it * provides. For components, it needs to call AddComponent(); for BiFs * AddBifItem(); and for hooks EnableHook() and then also implemennt the - * corresponding virtual method). + * corresponding virtual methods). * */ class Plugin { @@ -113,8 +157,6 @@ public: typedef std::list component_list; typedef std::list bif_item_list; typedef std::list > hook_list; - typedef std::list > bif_init_func_result; - typedef void (*bif_init_func)(Plugin *); /** * Constructor. @@ -141,7 +183,7 @@ public: * dynamically compiled plugins; for statically compiled ones, this * will always return 0. */ - int Version() const; + VersionNumber Version() const; /** * Returns true if this is a dynamically linked in plugin. @@ -180,6 +222,17 @@ public: */ bif_item_list BifItems() const; + /** + * A function called when the plugin is instantiated to query basic + * configuration parameters. + * + * The plugin must override this method and return a suitably + * initialized configuration object. + * + * @return A configuration describing the plugin. + */ + virtual Configuration Configure() { return Configuration(); } // TODO: Change to abstract method. + /** * First-stage initialization of the plugin called early during Bro's * startup, before scripts are parsed. This can be overridden by @@ -244,15 +297,15 @@ public: */ bool LoadBroFile(const std::string& file); - /** - * Internal function adding an entry point for registering - * auto-generated BiFs. - */ - void __AddBifInitFunction(bif_init_func c); - protected: friend class Manager; + /** + * Intializes the plugin's configutation. Called by the manager + * before anything else. + */ + void DoConfigure(); + /** * Registers and activates a component. * @@ -388,59 +441,6 @@ protected: // Methods that are used internally primarily. - /** - * Sets the plugins name. - * - * This is used primarily internally; plugin code should pass the - * name via the BRO_PLUGIN_BEGIN macro instead. - * - * @param name The name. Makes a copy internally. - */ - void SetName(const std::string& name); - - /** - * Sets the plugin's textual description. - * - * This is used primarily internally; plugin code should pass the - * name via the BRO_PLUGIN_DESCRIPTION macro instead. - * - * @param name The description. Makes a copy internally. - */ - void SetDescription(const std::string& descr); - - /** - * Sets the plugin's version. - * - * This is used primarily internally; plugin code should pass the - * name via the BRO_PLUGIN_VERSION macro instead. - * - * @param version The version. - */ - void SetVersion(int version); - - /** - * Sets the API version the plugin requires. - * BRO_PLUGIN_VERSION_BUILTIN indicates that it's a plugin linked in - * statically. - * - * This is used primarily internally; plugins automatically set - * either API version of the Bro they are compiled dynamically for, - * or BRO_PLUGIN_VERSION_BUILTIN if they are linked in statically. - * - * @param version The version. - */ - void SetAPIVersion(int version); - - /** - * Marks the plugin as statically or dynamically linked. - * - * This is used primarily internally; plugins automatically set this - * based on which way they are compiled. - * - * @param dynamic True if this is a dynamically linked plugin. - */ - void SetDynamicPlugin(bool dynamic); - /** * Sets the base directory and shared library path from which the * plugin was loaded. @@ -456,26 +456,25 @@ protected: */ void SetPluginLocation(const std::string& dir, const std::string& sopath); -private: /** - * Initializes the BiF items added with AddBifItem(). Internal method - * that will be called by the manager at the right time. + * Marks the plugin as dynamically loaded. + * + * This is used primarily internally; plugins will have this called + * by the manager. + * + * @param is_dynamic True if it's a dynamically loaded module. */ - void InitBifs(); + void SetDynamic(bool is_dynamic); - typedef std::list bif_init_func_list; +private: + Configuration config; - std::string name; - std::string description; - std::string base_dir; - std::string sopath; - int version; - int api_version; - bool dynamic; + std::string base_dir; // The plugin's base directory. + std::string sopath; // For dynamic plugins, the full path to the shared library. + bool dynamic; // True if a dynamic plugin. component_list components; bif_item_list bif_items; - bif_init_func_list bif_inits; }; } diff --git a/testing/btest/Baseline/core.plugins.analyzer/output b/testing/btest/Baseline/core.plugins.analyzer/output index deb8a7655d..c622fe5b9d 100644 --- a/testing/btest/Baseline/core.plugins.analyzer/output +++ b/testing/btest/Baseline/core.plugins.analyzer/output @@ -1,4 +1,4 @@ -Plugin: Demo::Foo - A Foo test analyzer (dynamic, version 1) +Plugin: Demo::Foo - A Foo test analyzer (dynamic, version 1.0) [Analyzer] Foo (ANALYZER_FOO, enabled) [Event] foo_message diff --git a/testing/btest/Baseline/core.plugins.test-plugin/output b/testing/btest/Baseline/core.plugins.test-plugin/output index ed76603b01..a5d50a6410 100644 --- a/testing/btest/Baseline/core.plugins.test-plugin/output +++ b/testing/btest/Baseline/core.plugins.test-plugin/output @@ -1,4 +1,4 @@ -Plugin: Demo::Foo - (dynamic, version 1) +Plugin: Demo::Foo - Caesar cipher rotating a string's characters by 13 places. (dynamic, version 1.0) [Event] plugin_event [Function] hello_plugin_world diff --git a/testing/btest/btest.cfg b/testing/btest/btest.cfg index 39b64f7c09..57a29e922d 100644 --- a/testing/btest/btest.cfg +++ b/testing/btest/btest.cfg @@ -10,6 +10,7 @@ PartFinalizer = btest-diff-rst BROPATH=`bash -c %(testbase)s/../../build/bro-path-dev` BROMAGIC=%(testbase)s/../../magic/database BRO_SEED_FILE=%(testbase)s/random.seed +BRO_PLUGIN_PATH= TZ=UTC LC_ALL=C BTEST_PATH=%(testbase)s/../../aux/btest diff --git a/testing/btest/core/plugins/analyzer-plugin/src/Foo.h b/testing/btest/core/plugins/analyzer-plugin/src/Foo.h index dfc50a9d76..fcd52b649b 100644 --- a/testing/btest/core/plugins/analyzer-plugin/src/Foo.h +++ b/testing/btest/core/plugins/analyzer-plugin/src/Foo.h @@ -19,7 +19,7 @@ public: virtual void Undelivered(int seq, int len, bool orig); virtual void EndpointEOF(bool is_orig); - static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn) + static analyzer::Analyzer* Instantiate(Connection* conn) { return new Foo_Analyzer(conn); } protected: diff --git a/testing/btest/core/plugins/analyzer-plugin/src/Plugin.cc b/testing/btest/core/plugins/analyzer-plugin/src/Plugin.cc index b37a60d148..970be28da8 100644 --- a/testing/btest/core/plugins/analyzer-plugin/src/Plugin.cc +++ b/testing/btest/core/plugins/analyzer-plugin/src/Plugin.cc @@ -3,10 +3,23 @@ #include "Foo.h" -BRO_PLUGIN_BEGIN(Demo, Foo) - BRO_PLUGIN_VERSION(1); - BRO_PLUGIN_DESCRIPTION("A Foo test analyzer"); - BRO_PLUGIN_ANALYZER("Foo", Foo::Foo_Analyzer); - BRO_PLUGIN_BIF_FILE(events); - BRO_PLUGIN_BIF_FILE(functions); -BRO_PLUGIN_END +namespace plugin { +namespace Demo_Foo { + +class Plugin : public plugin::Plugin { +public: + plugin::Configuration Configure() + { + AddComponent(new ::analyzer::Component("Foo", ::analyzer::Foo::Foo_Analyzer::Instantiate)); + + plugin::Configuration config; + config.name = "Demo::Foo"; + config.description = "A Foo test analyzer"; + config.version.major = 1; + config.version.minor = 0; + return config; + } +} plugin; + +} +}