diff --git a/src/EventHandler.cc b/src/EventHandler.cc index 2f0a19ccc0..0f25d63ba8 100644 --- a/src/EventHandler.cc +++ b/src/EventHandler.cc @@ -13,6 +13,7 @@ EventHandler::EventHandler(const char* arg_name) type = 0; error_handler = false; enabled = true; + generate_always = false; } EventHandler::~EventHandler() @@ -23,7 +24,9 @@ EventHandler::~EventHandler() EventHandler::operator bool() const { - return enabled && ((local && local->HasBodies()) || receivers.length()); + return enabled && ((local && local->HasBodies()) + || receivers.length() + || generate_always); } FuncType* EventHandler::FType() diff --git a/src/EventHandler.h b/src/EventHandler.h index e84f635175..de93d4ec33 100644 --- a/src/EventHandler.h +++ b/src/EventHandler.h @@ -43,6 +43,11 @@ public: void SetEnable(bool arg_enable) { enabled = arg_enable; } + // Flags the event as interesting even if there is no body defined. In + // particular, this will then still pass the event on to plugins. + void SetGenerateAlways() { generate_always = true; } + bool GenerateAlways() { return generate_always; } + // We don't serialize the handler(s) itself here, but // just the reference to it. bool Serialize(SerialInfo* info) const; @@ -57,6 +62,7 @@ private: bool used; // this handler is indeed used somewhere bool enabled; bool error_handler; // this handler reports error messages. + bool generate_always; declare(List, SourceID); typedef List(SourceID) receiver_list; diff --git a/src/Obj.cc b/src/Obj.cc index 33aaa8f44e..6f8a06d45f 100644 --- a/src/Obj.cc +++ b/src/Obj.cc @@ -7,6 +7,7 @@ #include "Obj.h" #include "Serializer.h" #include "File.h" +#include "plugin/Manager.h" Location no_location("", 0, 0, 0, 0); Location start_location("", 0, 0, 0, 0); @@ -92,6 +93,11 @@ int BroObj::suppress_errors = 0; BroObj::~BroObj() { + if ( notify_plugins ) + { + PLUGIN_HOOK_VOID(HOOK_BRO_OBJ_DTOR, HookBroObjDtor(this)); + } + delete location; } diff --git a/src/Obj.h b/src/Obj.h index be0d91b398..59a1589afa 100644 --- a/src/Obj.h +++ b/src/Obj.h @@ -92,6 +92,7 @@ public: { ref_cnt = 1; in_ser_cache = false; + notify_plugins = false; // A bit of a hack. We'd like to associate location // information with every object created when parsing, @@ -151,6 +152,9 @@ public: // extend compound objects such as statement lists. virtual void UpdateLocationEndInfo(const Location& end); + // Enable notification of plugins when this objects gets destroyed. + void NotifyPluginsOnDtor() { notify_plugins = true; } + int RefCnt() const { return ref_cnt; } // Helper class to temporarily suppress errors @@ -181,6 +185,7 @@ private: friend inline void Ref(BroObj* o); friend inline void Unref(BroObj* o); + bool notify_plugins; int ref_cnt; // If non-zero, do not print runtime errors. Useful for diff --git a/src/plugin/Manager.cc b/src/plugin/Manager.cc index 4fd895c232..d85ce92a81 100644 --- a/src/plugin/Manager.cc +++ b/src/plugin/Manager.cc @@ -443,6 +443,16 @@ void Manager::DisableHook(HookType hook, Plugin* plugin) } } +void Manager::RequestEvent(EventHandlerPtr handler, Plugin* plugin) + { + DBG_LOG(DBG_PLUGINS, "Plugin %s requested event %s", Name(), handler->Name()); + handler->GenerateAlways(); + } + +void Manager::RequestBroObjDtor(BroObj* obj, Plugin* plugin) + { + } + int Manager::HookLoadFile(const string& file) { HookArgumentList args; @@ -522,7 +532,7 @@ bool Manager::HookQueueEvent(Event* event) const { Plugin* p = (*i).second; - if ( p->HookQueueEvent(event) ) + if ( p->HookQueueEvent(event) ) { result = true; break; @@ -577,6 +587,29 @@ void Manager::HookUpdateNetworkTime(double network_time) const MetaHookPost(HOOK_UPDATE_NETWORK_TIME, args, HookArgument()); } +void Manager::HookBroObjDtor(void* obj) const + { + HookArgumentList args; + + if ( HavePluginForHook(META_HOOK_PRE) ) + { + args.push_back(obj); + MetaHookPre(HOOK_BRO_OBJ_DTOR, args); + } + + hook_list* l = hooks[HOOK_BRO_OBJ_DTOR]; + + for ( hook_list::iterator i = l->begin(); l && i != l->end(); i++ ) + { + Plugin* p = (*i).second; + p->HookBroObjDtor(obj); + } + + if ( HavePluginForHook(META_HOOK_POST) ) + MetaHookPost(HOOK_BRO_OBJ_DTOR, args, HookArgument()); + + } + void Manager::MetaHookPre(HookType hook, const HookArgumentList& args) const { hook_list* l = hooks[HOOK_CALL_FUNCTION]; diff --git a/src/plugin/Manager.h b/src/plugin/Manager.h index 1f1d3a772d..881255d022 100644 --- a/src/plugin/Manager.h +++ b/src/plugin/Manager.h @@ -15,7 +15,7 @@ namespace plugin { // Macros that trigger a plugin hook. We put this into macros to short-cut // the code for the most common case that no plugin defines the hook. #define PLUGIN_HOOK_WITH_RESULT(hook, method_call, default_result) \ - (plugin_mgr->HavePluginForHook(plugin::hook) ? plugin_mgr->method_call : (default_result)) + (plugin_mgr->HavePluginForHook(::plugin::hook) ? plugin_mgr->method_call : (default_result)) #define PLUGIN_HOOK_VOID(hook, method_call) \ if ( plugin_mgr->HavePluginForHook(plugin::hook) ) plugin_mgr->method_call; @@ -160,6 +160,27 @@ public: */ void DisableHook(HookType hook, Plugin* plugin); + /** + * Register interest in an event. The event will then be raised, and + * hence passed to the plugin, even if there no handler defined. + * + * @param handler The event being interested in. + * + * @param plugin The plugin expressing interest. + */ + void RequestEvent(EventHandlerPtr handler, Plugin* plugin); + + /** + * Register interest in the destruction of a BroObj instance. When + * Bro's reference counting triggers the objects destructor to run, + * the \a HookBroObjDtor will be called. + * + * @param handler The object being interested in. + * + * @param plugin The plugin expressing interest. + */ + void RequestBroObjDtor(BroObj* obj, Plugin* plugin); + // Hook entry functions. /** @@ -208,10 +229,16 @@ public: void HookUpdateNetworkTime(double network_time) const; /** - * Hooks that informs plugins that the event queue is being drained. + * Hook that informs plugins that the event queue is being drained. */ void HookDrainEvents() const; + /** + * Hook that informs plugins that an BroObj is being destroyed. Will be + * called only for objects that a plugin has expressed interest in. + */ + void HookBroObjDtor(void* obj) const; + /** * Internal method that registers a freshly instantiated plugin with * the manager. diff --git a/src/plugin/Plugin.cc b/src/plugin/Plugin.cc index b0aac907d9..a622d3638d 100644 --- a/src/plugin/Plugin.cc +++ b/src/plugin/Plugin.cc @@ -22,6 +22,7 @@ const char* plugin::hook_name(HookType h) "QueueEvent", "DrainEvents", "UpdateNetworkTime", + "BroObjDtor", // MetaHooks "MetaHookPre", "MetaHookPost", @@ -32,6 +33,13 @@ const char* plugin::hook_name(HookType h) return hook_names[int(h)]; } +Configuration::Configuration() + { + name = ""; + description = ""; + api_version = BRO_PLUGIN_API_VERSION; + } + BifItem::BifItem(const std::string& arg_id, Type arg_type) { id = arg_id; @@ -119,6 +127,10 @@ void HookArgument::Describe(ODesc* d) const case VOID: d->Add(""); break; + + case VOIDP: + d->Add(""); + break; } } @@ -262,6 +274,16 @@ void Plugin::DisableHook(HookType hook) plugin_mgr->DisableHook(hook, this); } +void Plugin::RequestEvent(EventHandlerPtr handler) + { + plugin_mgr->RequestEvent(handler, this); + } + +void Plugin::RequestBroObjDtor(BroObj* obj) + { + plugin_mgr->RequestBroObjDtor(obj, this); + } + int Plugin::HookLoadFile(const std::string& file) { return -1; @@ -285,6 +307,10 @@ void Plugin::HookUpdateNetworkTime(double network_time) { } +void Plugin::HookBroObjDtor(void* obj) + { + } + void Plugin::MetaHookPre(HookType hook, const HookArgumentList& args) { } diff --git a/src/plugin/Plugin.h b/src/plugin/Plugin.h index 2490a3e8ad..ccd18db86e 100644 --- a/src/plugin/Plugin.h +++ b/src/plugin/Plugin.h @@ -33,6 +33,7 @@ enum HookType { HOOK_QUEUE_EVENT, HOOK_DRAIN_EVENTS, HOOK_UPDATE_NETWORK_TIME, + HOOK_BRO_OBJ_DTOR, // Meta hooks. META_HOOK_PRE, @@ -69,19 +70,11 @@ public: std::string description; //< A short textual description of the plugin. Mandatory. VersionNumber version; //< THe plugin's version. Optional. - Configuration() - { - // Note we inline this method here so that when plugins create an instance, - // *their* defaults will be used for the internal fields. - name = ""; - description = ""; - api_version = BRO_PLUGIN_API_VERSION; - } + Configuration(); private: friend class Plugin; int api_version; // Current BRO_PLUGIN_API_VERSION. Automatically set. - }; /** @@ -141,7 +134,7 @@ class HookArgument { public: enum Type { - BOOL, DOUBLE, EVENT, FUNC, INT, STRING, VAL, VAL_LIST, VOID + BOOL, DOUBLE, EVENT, FUNC, INT, STRING, VAL, VAL_LIST, VOID, VOIDP, }; HookArgument() { type = VOID; } @@ -153,6 +146,7 @@ public: HookArgument(const std::string& a) { type = STRING; arg_string = a; } HookArgument(const Val* a) { type = VAL; arg.val = a; } HookArgument(const val_list* a) { type = VAL_LIST; arg.vals = a; } + HookArgument(void* p) { type = VOIDP; arg.voidp = p; } bool AsBool() const { assert(type == BOOL); return arg.bool_; } double AsDouble() const { assert(type == DOUBLE); return arg.double_; } @@ -162,6 +156,7 @@ public: const std::string& AsString() const { assert(type == STRING); return arg_string; } const Val* AsVal() const { assert(type == VAL); return arg.val; } const val_list* AsValList() const { assert(type == VAL_LIST); return arg.vals; } + const void* AsVoidPtr() const { assert(type == VOIDP); return arg.voidp; } Type GetType() const { return type; } void Describe(ODesc* d) const; @@ -176,6 +171,7 @@ private: int int_; const Val* val; const val_list* vals; + const void* voidp; } arg; std::string arg_string; // Outside union because it has dtor. @@ -406,6 +402,23 @@ protected: */ hook_list EnabledHooks() const; + /** + * Register interest in an event. The event will then be raised, and + * hence passed to the plugin, even if there no handler defined. + * + * @param handler The object being interested in. + */ + void RequestEvent(EventHandlerPtr handler); + + /** + * Register interest in the destruction of a BroObj instance. When + * Bro's reference counting triggers the objects destructor to run, + * the \a HookBroObjDtor will be called. + * + * @param handler The object being interested in. + */ + void RequestBroObjDtor(BroObj* obj); + /** * Virtual method that can be overriden by derived class to provide * information about further script-level elements that the plugin @@ -496,6 +509,18 @@ protected: */ virtual void HookUpdateNetworkTime(double network_time); + /** + * Hook for destruction of objects registerd with + * RequestBroObjDtor(). When Bro's reference counting triggers the + * objects destructor to run, this method will be run. It may also + * run for other objects that this plugin has not registered for. + * + * @param obj A pointer to the object being destroyed. Note that the + * object is already considered invalid and the pointer must not be + * dereferenced. + */ + virtual void HookBroObjDtor(void* obj); + // Meta hooks. /**