diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7960579c8a..e64dcbb9f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -363,6 +363,8 @@ set(bro_SRCS 3rdparty/sqlite3.c plugin/Component.cc + plugin/ComponentManager.h + plugin/TaggedComponent.h plugin/Manager.cc plugin/Plugin.cc plugin/Macros.h diff --git a/src/DebugLogger.cc b/src/DebugLogger.cc index 380f21aa5f..dc557c4a0a 100644 --- a/src/DebugLogger.cc +++ b/src/DebugLogger.cc @@ -16,7 +16,8 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = { { "notifiers", 0, false }, { "main-loop", 0, false }, { "dpd", 0, false }, { "tm", 0, false }, { "logging", 0, false }, {"input", 0, false }, - { "threading", 0, false }, { "file_analysis", 0, false } + { "threading", 0, false }, { "file_analysis", 0, false }, + { "plugins", 0, false} }; DebugLogger::DebugLogger(const char* filename) diff --git a/src/DebugLogger.h b/src/DebugLogger.h index e293b326a8..c5744642f5 100644 --- a/src/DebugLogger.h +++ b/src/DebugLogger.h @@ -27,6 +27,7 @@ enum DebugStream { DBG_INPUT, // Input streams DBG_THREADING, // Threading system DBG_FILE_ANALYSIS, // File analysis + DBG_PLUGINS, NUM_DBGS // Has to be last }; diff --git a/src/RuleAction.cc b/src/RuleAction.cc index a13392ee40..ec57c96bd2 100644 --- a/src/RuleAction.cc +++ b/src/RuleAction.cc @@ -40,7 +40,7 @@ RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer) string str(arg_analyzer); string::size_type pos = str.find(':'); string arg = str.substr(0, pos); - analyzer = analyzer_mgr->GetAnalyzerTag(arg.c_str()); + analyzer = analyzer_mgr->GetComponentTag(arg.c_str()); if ( ! analyzer ) reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str()); @@ -48,7 +48,7 @@ RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer) if ( pos != string::npos ) { arg = str.substr(pos + 1); - child_analyzer = analyzer_mgr->GetAnalyzerTag(arg.c_str()); + child_analyzer = analyzer_mgr->GetComponentTag(arg.c_str()); if ( ! child_analyzer ) reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str()); @@ -60,11 +60,11 @@ RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer) void RuleActionAnalyzer::PrintDebug() { if ( ! child_analyzer ) - fprintf(stderr, "|%s|\n", analyzer_mgr->GetAnalyzerName(analyzer)); + fprintf(stderr, "|%s|\n", analyzer_mgr->GetComponentName(analyzer)); else fprintf(stderr, "|%s:%s|\n", - analyzer_mgr->GetAnalyzerName(analyzer), - analyzer_mgr->GetAnalyzerName(child_analyzer)); + analyzer_mgr->GetComponentName(analyzer), + analyzer_mgr->GetComponentName(child_analyzer)); } diff --git a/src/analyzer/Analyzer.cc b/src/analyzer/Analyzer.cc index ecd3c9f686..b8b739f3cb 100644 --- a/src/analyzer/Analyzer.cc +++ b/src/analyzer/Analyzer.cc @@ -70,12 +70,12 @@ void AnalyzerTimer::Init(Analyzer* arg_analyzer, analyzer_timer_func arg_timer, Ref(analyzer->Conn()); } -analyzer::ID Analyzer::id_counter = 0;; +analyzer::ID Analyzer::id_counter = 0; const char* Analyzer::GetAnalyzerName() const { assert(tag); - return analyzer_mgr->GetAnalyzerName(tag); + return analyzer_mgr->GetComponentName(tag); } void Analyzer::SetAnalyzerTag(const Tag& arg_tag) @@ -87,7 +87,7 @@ void Analyzer::SetAnalyzerTag(const Tag& arg_tag) bool Analyzer::IsAnalyzer(const char* name) { assert(tag); - return strcmp(analyzer_mgr->GetAnalyzerName(tag), name) == 0; + return strcmp(analyzer_mgr->GetComponentName(tag), name) == 0; } // Used in debugging output. @@ -98,7 +98,7 @@ static string fmt_analyzer(Analyzer* a) Analyzer::Analyzer(const char* name, Connection* conn) { - Tag tag = analyzer_mgr->GetAnalyzerTag(name); + Tag tag = analyzer_mgr->GetComponentTag(name); if ( ! tag ) reporter->InternalError("unknown analyzer name %s; mismatch with tag analyzer::Component?", name); @@ -494,7 +494,7 @@ Analyzer* Analyzer::FindChild(Tag arg_tag) Analyzer* Analyzer::FindChild(const char* name) { - Tag tag = analyzer_mgr->GetAnalyzerTag(name); + Tag tag = analyzer_mgr->GetComponentTag(name); return tag ? FindChild(tag) : 0; } diff --git a/src/analyzer/Component.cc b/src/analyzer/Component.cc index ded0a1a2d5..66ab2213bb 100644 --- a/src/analyzer/Component.cc +++ b/src/analyzer/Component.cc @@ -8,29 +8,26 @@ using namespace analyzer; -analyzer::Tag::type_t Component::type_counter = 0; - Component::Component(const char* arg_name, factory_callback arg_factory, Tag::subtype_t arg_subtype, bool arg_enabled, bool arg_partial) - : plugin::Component(plugin::component::ANALYZER) + : plugin::Component(plugin::component::ANALYZER), + plugin::TaggedComponent(arg_subtype) { name = copy_string(arg_name); canon_name = canonify_name(arg_name); factory = arg_factory; enabled = arg_enabled; partial = arg_partial; - - tag = analyzer::Tag(++type_counter, arg_subtype); } Component::Component(const Component& other) - : plugin::Component(Type()) + : plugin::Component(Type()), + plugin::TaggedComponent(other) { name = copy_string(other.name); canon_name = copy_string(other.canon_name); factory = other.factory; enabled = other.enabled; partial = other.partial; - tag = other.tag; } Component::~Component() @@ -39,11 +36,6 @@ Component::~Component() delete [] canon_name; } -analyzer::Tag Component::Tag() const - { - return tag; - } - void Component::Describe(ODesc* d) const { plugin::Component::Describe(d); @@ -63,13 +55,14 @@ void Component::Describe(ODesc* d) const Component& Component::operator=(const Component& other) { + plugin::TaggedComponent::operator=(other); + if ( &other != this ) { name = copy_string(other.name); factory = other.factory; enabled = other.enabled; partial = other.partial; - tag = other.tag; } return *this; diff --git a/src/analyzer/Component.h b/src/analyzer/Component.h index 9e12ed347e..9bc8b357d7 100644 --- a/src/analyzer/Component.h +++ b/src/analyzer/Component.h @@ -5,6 +5,7 @@ #include "Tag.h" #include "plugin/Component.h" +#include "plugin/TaggedComponent.h" #include "../config.h" #include "../util.h" @@ -21,7 +22,8 @@ class Analyzer; * A plugin can provide a specific protocol analyzer by registering this * analyzer component, describing the analyzer. */ -class Component : public plugin::Component { +class Component : public plugin::Component, + public plugin::TaggedComponent { public: typedef Analyzer* (*factory_callback)(Connection* conn); @@ -100,13 +102,6 @@ public: */ bool Enabled() const { return enabled; } - /** - * Returns the analyzer's tag. Note that this is automatically - * generated for each new Components, and hence unique across all of - * them. - */ - analyzer::Tag Tag() const; - /** * Enables or disables this analyzer. * @@ -128,11 +123,7 @@ private: const char* canon_name; // The analyzer's canonical name. factory_callback factory; // The analyzer's factory callback. bool partial; // True if the analyzer supports partial connections. - analyzer::Tag tag; // The automatically assigned analyzer tag. bool enabled; // True if the analyzer is enabled. - - // Global counter used to generate unique tags. - static analyzer::Tag::type_t type_counter; }; } diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 6eb162f204..82453aef06 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -60,10 +60,8 @@ bool Manager::ConnIndex::operator<(const ConnIndex& other) const } Manager::Manager() + : plugin::ComponentManager("Analyzer") { - tag_enum_type = new EnumType("Analyzer::Tag"); - ::ID* id = install_ID("Tag", "Analyzer", true, true); - add_type(id, tag_enum_type, 0, 0); } Manager::~Manager() @@ -91,14 +89,14 @@ void Manager::InitPreScript() std::list analyzers = plugin_mgr->Components(); for ( std::list::const_iterator i = analyzers.begin(); i != analyzers.end(); i++ ) - RegisterAnalyzerComponent(*i); + RegisterComponent(*i, "ANALYZER_"); // Cache these tags. - analyzer_backdoor = GetAnalyzerTag("BACKDOOR"); - analyzer_connsize = GetAnalyzerTag("CONNSIZE"); - analyzer_interconn = GetAnalyzerTag("INTERCONN"); - analyzer_stepping = GetAnalyzerTag("STEPPINGSTONE"); - analyzer_tcpstats = GetAnalyzerTag("TCPSTATS"); + analyzer_backdoor = GetComponentTag("BACKDOOR"); + analyzer_connsize = GetComponentTag("CONNSIZE"); + analyzer_interconn = GetComponentTag("INTERCONN"); + analyzer_stepping = GetComponentTag("STEPPINGSTONE"); + analyzer_tcpstats = GetComponentTag("TCPSTATS"); } void Manager::InitPostScript() @@ -109,8 +107,9 @@ void Manager::DumpDebug() { #ifdef DEBUG DBG_LOG(DBG_ANALYZER, "Available analyzers after bro_init():"); - for ( analyzer_map_by_name::const_iterator i = analyzers_by_name.begin(); i != analyzers_by_name.end(); i++ ) - DBG_LOG(DBG_ANALYZER, " %s (%s)", i->second->Name(), IsEnabled(i->second->Tag()) ? "enabled" : "disabled"); + list all_analyzers = GetComponents(); + for ( list::const_iterator i = all_analyzers.begin(); i != all_analyzers.end(); ++i ) + DBG_LOG(DBG_ANALYZER, " %s (%s)", (*i)->Name(), IsEnabled((*i)->Tag()) ? "enabled" : "disabled"); DBG_LOG(DBG_ANALYZER, ""); DBG_LOG(DBG_ANALYZER, "Analyzers by port:"); @@ -120,7 +119,7 @@ void Manager::DumpDebug() string s; for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) - s += string(GetAnalyzerName(*j)) + " "; + s += string(GetComponentName(*j)) + " "; DBG_LOG(DBG_ANALYZER, " %d/tcp: %s", i->first, s.c_str()); } @@ -130,7 +129,7 @@ void Manager::DumpDebug() string s; for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) - s += string(GetAnalyzerName(*j)) + " "; + s += string(GetComponentName(*j)) + " "; DBG_LOG(DBG_ANALYZER, " %d/udp: %s", i->first, s.c_str()); } @@ -142,25 +141,6 @@ void Manager::Done() { } -void Manager::RegisterAnalyzerComponent(Component* component) - { - const char* cname = component->CanonicalName(); - - if ( Lookup(cname) ) - reporter->FatalError("Analyzer %s defined more than once", cname); - - DBG_LOG(DBG_ANALYZER, "Registering analyzer %s (tag %s)", - component->Name(), component->Tag().AsString().c_str()); - - analyzers_by_name.insert(std::make_pair(cname, component)); - analyzers_by_tag.insert(std::make_pair(component->Tag(), component)); - analyzers_by_val.insert(std::make_pair(component->Tag().AsEnumVal()->InternalInt(), component)); - - // Install enum "Analyzer::ANALYZER_*" - string id = fmt("ANALYZER_%s", cname); - tag_enum_type->AddName("Analyzer", id.c_str(), component->Tag().AsEnumVal()->InternalInt(), true); - } - bool Manager::EnableAnalyzer(Tag tag) { Component* p = Lookup(tag); @@ -217,8 +197,9 @@ void Manager::DisableAllAnalyzers() { DBG_LOG(DBG_ANALYZER, "Disabling all analyzers"); - for ( analyzer_map_by_tag::const_iterator i = analyzers_by_tag.begin(); i != analyzers_by_tag.end(); i++ ) - i->second->SetEnabled(false); + list all_analyzers = GetComponents(); + for ( list::const_iterator i = all_analyzers.begin(); i != all_analyzers.end(); ++i ) + (*i)->SetEnabled(false); } bool Manager::IsEnabled(Tag tag) @@ -270,7 +251,7 @@ bool Manager::RegisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port tag_set* l = LookupPort(proto, port, true); #ifdef DEBUG - const char* name = GetAnalyzerName(tag); + const char* name = GetComponentName(tag); DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name, port, proto); #endif @@ -283,7 +264,7 @@ bool Manager::UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 po tag_set* l = LookupPort(proto, port, true); #ifdef DEBUG - const char* name = GetAnalyzerName(tag); + const char* name = GetComponentName(tag); DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name, port, proto); #endif @@ -302,7 +283,7 @@ Analyzer* Manager::InstantiateAnalyzer(Tag tag, Connection* conn) return 0; if ( ! c->Factory() ) - reporter->InternalError("analyzer %s cannot be instantiated dynamically", GetAnalyzerName(tag)); + reporter->InternalError("analyzer %s cannot be instantiated dynamically", GetComponentName(tag)); Analyzer* a = c->Factory()(conn); @@ -316,59 +297,10 @@ Analyzer* Manager::InstantiateAnalyzer(Tag tag, Connection* conn) Analyzer* Manager::InstantiateAnalyzer(const char* name, Connection* conn) { - Tag tag = GetAnalyzerTag(name); + Tag tag = GetComponentTag(name); return tag ? InstantiateAnalyzer(tag, conn) : 0; } -const char* Manager::GetAnalyzerName(Tag tag) - { - static const char* error = ""; - - if ( ! tag ) - return error; - - Component* c = Lookup(tag); - - if ( ! c ) - reporter->InternalError("request for name of unknown analyzer tag %s", tag.AsString().c_str()); - - return c->CanonicalName(); - } - -const char* Manager::GetAnalyzerName(Val* val) - { - return GetAnalyzerName(Tag(val->AsEnumVal())); - } - -analyzer::Tag Manager::GetAnalyzerTag(const char* name) - { - Component* c = Lookup(name); - return c ? c->Tag() : Tag(); - } - -EnumType* Manager::GetTagEnumType() - { - return tag_enum_type; - } - -Component* Manager::Lookup(const char* name) - { - analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name)); - return i != analyzers_by_name.end() ? i->second : 0; - } - -Component* Manager::Lookup(const Tag& tag) - { - analyzer_map_by_tag::const_iterator i = analyzers_by_tag.find(tag); - return i != analyzers_by_tag.end() ? i->second : 0; - } - -Component* Manager::Lookup(EnumVal* val) - { - analyzer_map_by_val::const_iterator i = analyzers_by_val.find(val->InternalInt()); - return i != analyzers_by_val.end() ? i->second : 0; - } - Manager::tag_set* Manager::LookupPort(TransportProto proto, uint32 port, bool add_if_not_found) { analyzer_map_by_port* m = 0; @@ -461,7 +393,7 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) root->AddChildAnalyzer(analyzer, false); DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled", - analyzer_mgr->GetAnalyzerName(*i)); + analyzer_mgr->GetComponentName(*i)); } } @@ -487,7 +419,7 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn) root->AddChildAnalyzer(analyzer, false); DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d", - analyzer_mgr->GetAnalyzerName(*j), resp_port); + analyzer_mgr->GetComponentName(*j), resp_port); } } } @@ -613,7 +545,7 @@ void Manager::ExpireScheduledAnalyzers() conns.erase(i); DBG_LOG(DBG_ANALYZER, "Expiring expected analyzer %s for connection %s", - analyzer_mgr->GetAnalyzerName(a->analyzer), + analyzer_mgr->GetComponentName(a->analyzer), fmt_conn_id(a->conn.orig, 0, a->conn.resp, a->conn.resp_p)); delete a; @@ -655,7 +587,7 @@ void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, TransportProto proto, const char* analyzer, double timeout) { - Tag tag = GetAnalyzerTag(analyzer); + Tag tag = GetComponentTag(analyzer); if ( tag != Tag() ) ScheduleAnalyzer(orig, resp, resp_p, proto, tag, timeout); diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index efae629971..d151709eda 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -26,6 +26,7 @@ #include "Analyzer.h" #include "Component.h" #include "Tag.h" +#include "plugin/ComponentManager.h" #include "../Dict.h" #include "../net_util.h" @@ -49,7 +50,7 @@ namespace analyzer { * classes. This allows to external analyzer code to potentially use a * different C++ standard library. */ -class Manager { +class Manager : public plugin::ComponentManager { public: /** * Constructor. @@ -231,42 +232,6 @@ public: */ Analyzer* InstantiateAnalyzer(const char* name, Connection* c); - /** - * Translates an analyzer tag into corresponding analyzer name. - * - * @param tag The analyzer tag. - * - * @return The name, or an empty string if the tag is invalid. - */ - const char* GetAnalyzerName(Tag tag); - - /** - * Translates an script-level analyzer tag into corresponding - * analyzer name. - * - * @param val The analyzer tag as an script-level enum value of type - * \c Analyzer::Tag. - * - * @return The name, or an empty string if the tag is invalid. - */ - const char* GetAnalyzerName(Val* val); - - /** - * Translates an analyzer name into the corresponding tag. - * - * @param name The name. - * - * @return The tag. If the name does not correspond to a valid - * analyzer, the returned tag will evaluate to false. - */ - Tag GetAnalyzerTag(const char* name); - - /** - * Returns the enum type that corresponds to the script-level type \c - * Analyzer::Tag. - */ - EnumType* GetTagEnumType(); - /** * Given the first packet of a connection, builds its initial * analyzer tree. @@ -350,18 +315,8 @@ public: private: typedef set tag_set; - typedef map analyzer_map_by_name; - typedef map analyzer_map_by_tag; - typedef map analyzer_map_by_val; typedef map analyzer_map_by_port; - void RegisterAnalyzerComponent(Component* component); // Takes ownership. - - Component* Lookup(const string& name); - Component* Lookup(const char* name); - Component* Lookup(const Tag& tag); - Component* Lookup(EnumVal* val); - tag_set* LookupPort(PortVal* val, bool add_if_not_found); tag_set* LookupPort(TransportProto proto, uint32 port, bool add_if_not_found); @@ -370,9 +325,6 @@ private: analyzer_map_by_port analyzers_by_port_tcp; analyzer_map_by_port analyzers_by_port_udp; - analyzer_map_by_name analyzers_by_name; - analyzer_map_by_tag analyzers_by_tag; - analyzer_map_by_val analyzers_by_val; Tag analyzer_backdoor; Tag analyzer_connsize; @@ -380,8 +332,6 @@ private: Tag analyzer_stepping; Tag analyzer_tcpstats; - EnumType* tag_enum_type; - //// Data structures to track analyzed scheduled for future connections. // The index for a scheduled connection. diff --git a/src/analyzer/Tag.h b/src/analyzer/Tag.h index 8ac151e4b5..d01c8902ee 100644 --- a/src/analyzer/Tag.h +++ b/src/analyzer/Tag.h @@ -6,6 +6,8 @@ #include "config.h" #include "util.h" #include "../Tag.h" +#include "plugin/TaggedComponent.h" +#include "plugin/ComponentManager.h" class EnumVal; @@ -87,7 +89,8 @@ public: protected: friend class analyzer::Manager; - friend class analyzer::Component; + friend class plugin::ComponentManager; + friend class plugin::TaggedComponent; /** * Constructor. diff --git a/src/analyzer/analyzer.bif b/src/analyzer/analyzer.bif index 4d70816075..ebf8083624 100644 --- a/src/analyzer/analyzer.bif +++ b/src/analyzer/analyzer.bif @@ -41,11 +41,11 @@ function Analyzer::__schedule_analyzer%(orig: addr, resp: addr, resp_p: port, function __name%(atype: Analyzer::Tag%) : string %{ - return new StringVal(analyzer_mgr->GetAnalyzerName(atype)); + return new StringVal(analyzer_mgr->GetComponentName(atype)); %} function __tag%(name: string%) : Analyzer::Tag %{ - analyzer::Tag t = analyzer_mgr->GetAnalyzerTag(name->CheckString()); + analyzer::Tag t = analyzer_mgr->GetComponentTag(name->CheckString()); return t.AsEnumVal()->Ref(); %} diff --git a/src/file_analysis/Analyzer.cc b/src/file_analysis/Analyzer.cc index d472f4c80c..e0b5011aa8 100644 --- a/src/file_analysis/Analyzer.cc +++ b/src/file_analysis/Analyzer.cc @@ -6,6 +6,6 @@ file_analysis::Analyzer::~Analyzer() { DBG_LOG(DBG_FILE_ANALYSIS, "Destroy file analyzer %s", - file_mgr->GetAnalyzerName(tag)); + file_mgr->GetComponentName(tag)); Unref(args); } diff --git a/src/file_analysis/AnalyzerSet.cc b/src/file_analysis/AnalyzerSet.cc index befb676c87..2dc4902314 100644 --- a/src/file_analysis/AnalyzerSet.cc +++ b/src/file_analysis/AnalyzerSet.cc @@ -42,7 +42,7 @@ bool AnalyzerSet::Add(file_analysis::Tag tag, RecordVal* args) if ( analyzer_map.Lookup(key) ) { DBG_LOG(DBG_FILE_ANALYSIS, "Instantiate analyzer %s skipped for file id" - " %s: already exists", file_mgr->GetAnalyzerName(tag), + " %s: already exists", file_mgr->GetComponentName(tag), file->GetID().c_str()); delete key; return true; @@ -82,7 +82,7 @@ bool AnalyzerSet::AddMod::Perform(AnalyzerSet* set) if ( set->analyzer_map.Lookup(key) ) { DBG_LOG(DBG_FILE_ANALYSIS, "Add analyzer %s skipped for file id" - " %s: already exists", file_mgr->GetAnalyzerName(a->Tag()), + " %s: already exists", file_mgr->GetComponentName(a->Tag()), a->GetFile()->GetID().c_str()); Abort(); @@ -108,12 +108,12 @@ bool AnalyzerSet::Remove(file_analysis::Tag tag, HashKey* key) if ( ! a ) { DBG_LOG(DBG_FILE_ANALYSIS, "Skip remove analyzer %s for file id %s", - file_mgr->GetAnalyzerName(tag), file->GetID().c_str()); + file_mgr->GetComponentName(tag), file->GetID().c_str()); return false; } DBG_LOG(DBG_FILE_ANALYSIS, "Remove analyzer %s for file id %s", - file_mgr->GetAnalyzerName(tag), + file_mgr->GetComponentName(tag), file->GetID().c_str()); delete a; @@ -155,7 +155,7 @@ file_analysis::Analyzer* AnalyzerSet::InstantiateAnalyzer(Tag tag, if ( ! a ) { reporter->Error("Failed file analyzer %s instantiation for file id %s", - file_mgr->GetAnalyzerName(tag), file->GetID().c_str()); + file_mgr->GetComponentName(tag), file->GetID().c_str()); return 0; } @@ -165,7 +165,7 @@ file_analysis::Analyzer* AnalyzerSet::InstantiateAnalyzer(Tag tag, void AnalyzerSet::Insert(file_analysis::Analyzer* a, HashKey* key) { DBG_LOG(DBG_FILE_ANALYSIS, "Add analyzer %s for file id %s", - file_mgr->GetAnalyzerName(a->Tag()), file->GetID().c_str()); + file_mgr->GetComponentName(a->Tag()), file->GetID().c_str()); analyzer_map.Insert(key, a); delete key; } diff --git a/src/file_analysis/Component.cc b/src/file_analysis/Component.cc index 8ddd9cceaf..9c47f2c75e 100644 --- a/src/file_analysis/Component.cc +++ b/src/file_analysis/Component.cc @@ -8,26 +8,22 @@ using namespace file_analysis; -file_analysis::Tag::type_t Component::type_counter = 0; - -Component::Component(const char* arg_name, factory_callback arg_factory, - file_analysis::Tag::subtype_t arg_subtype) - : plugin::Component(plugin::component::FILE_ANALYZER) +Component::Component(const char* arg_name, factory_callback arg_factory) + : plugin::Component(plugin::component::FILE_ANALYZER), + plugin::TaggedComponent() { name = copy_string(arg_name); canon_name = canonify_name(arg_name); factory = arg_factory; - - tag = file_analysis::Tag(++type_counter, arg_subtype); } Component::Component(const Component& other) - : plugin::Component(Type()) + : plugin::Component(Type()), + plugin::TaggedComponent(other) { name = copy_string(other.name); canon_name = copy_string(other.canon_name); factory = other.factory; - tag = other.tag; } Component::~Component() @@ -36,11 +32,6 @@ Component::~Component() delete [] canon_name; } -file_analysis::Tag Component::Tag() const - { - return tag; - } - void Component::Describe(ODesc* d) const { plugin::Component::Describe(d); @@ -58,11 +49,12 @@ void Component::Describe(ODesc* d) const Component& Component::operator=(const Component& other) { + plugin::TaggedComponent::operator=(other); + if ( &other != this ) { name = copy_string(other.name); factory = other.factory; - tag = other.tag; } return *this; diff --git a/src/file_analysis/Component.h b/src/file_analysis/Component.h index bd690bc081..4cf2dced60 100644 --- a/src/file_analysis/Component.h +++ b/src/file_analysis/Component.h @@ -5,6 +5,7 @@ #include "Tag.h" #include "plugin/Component.h" +#include "plugin/TaggedComponent.h" #include "Val.h" @@ -22,7 +23,8 @@ class Analyzer; * A plugin can provide a specific file analyzer by registering this * analyzer component, describing the analyzer. */ -class Component : public plugin::Component { +class Component : public plugin::Component, + public plugin::TaggedComponent { public: typedef Analyzer* (*factory_callback)(RecordVal* args, File* file); @@ -38,15 +40,8 @@ public: * from file_analysis::Analyzer. This is typically a static \c * Instatiate() method inside the class that just allocates and * returns a new instance. - * - * @param subtype A subtype associated with this component that - * further distinguishes it. The subtype will be integrated into - * the file_analysis::Tag that the manager associates with this analyzer, - * and analyzer instances can accordingly access it via - * file_analysis::Tag(). If not used, leave at zero. */ - Component(const char* name, factory_callback factory, - file_analysis::Tag::subtype_t subtype = 0); + Component(const char* name, factory_callback factory); /** * Copy constructor. @@ -79,13 +74,6 @@ public: */ factory_callback Factory() const { return factory; } - /** - * Returns the analyzer's tag. Note that this is automatically - * generated for each new Components, and hence unique across all of - * them. - */ - file_analysis::Tag Tag() const; - /** * Generates a human-readable description of the component's main * parameters. This goes into the output of \c "bro -NN". @@ -98,10 +86,6 @@ private: const char* name; // The analyzer's name. const char* canon_name; // The analyzer's canonical name. factory_callback factory; // The analyzer's factory callback. - file_analysis::Tag tag; // The automatically assigned analyzer tag. - - // Global counter used to generate unique tags. - static file_analysis::Tag::type_t type_counter; }; } diff --git a/src/file_analysis/File.cc b/src/file_analysis/File.cc index a27070174b..1197cd06f6 100644 --- a/src/file_analysis/File.cc +++ b/src/file_analysis/File.cc @@ -88,7 +88,7 @@ File::File(const string& file_id, Connection* conn, analyzer::Tag tag, if ( conn ) { // add source, connection, is_orig fields - SetSource(analyzer_mgr->GetAnalyzerName(tag)); + SetSource(analyzer_mgr->GetComponentName(tag)); val->Assign(is_orig_idx, new Val(is_orig, TYPE_BOOL)); UpdateConnectionFields(conn, is_orig); } diff --git a/src/file_analysis/FileTimer.cc b/src/file_analysis/FileTimer.cc index 575857fd15..6b1d70f136 100644 --- a/src/file_analysis/FileTimer.cc +++ b/src/file_analysis/FileTimer.cc @@ -14,7 +14,7 @@ FileTimer::FileTimer(double t, const string& id, double interval) void FileTimer::Dispatch(double t, int is_expire) { - File* file = file_mgr->Lookup(file_id); + File* file = file_mgr->LookupFile(file_id); if ( ! file ) return; diff --git a/src/file_analysis/Manager.cc b/src/file_analysis/Manager.cc index 243786b83a..b7f4335717 100644 --- a/src/file_analysis/Manager.cc +++ b/src/file_analysis/Manager.cc @@ -18,10 +18,8 @@ TableVal* Manager::disabled = 0; string Manager::salt; Manager::Manager() + : ComponentManager("Files") { - tag_enum_type = new EnumType("Files::Tag"); - ::ID* id = install_ID("Tag", "Files", true, true); - add_type(id, tag_enum_type, 0, 0); } Manager::~Manager() @@ -35,27 +33,7 @@ void Manager::InitPreScript() for ( std::list::const_iterator i = analyzers.begin(); i != analyzers.end(); ++i ) - RegisterAnalyzerComponent(*i); - } - -void Manager::RegisterAnalyzerComponent(Component* component) - { - const char* cname = component->CanonicalName(); - - if ( tag_enum_type->Lookup("Files", cname) != -1 ) - reporter->FatalError("File Analyzer %s defined more than once", cname); - - DBG_LOG(DBG_FILE_ANALYSIS, "Registering analyzer %s (tag %s)", - component->Name(), component->Tag().AsString().c_str()); - - analyzers_by_name.insert(std::make_pair(cname, component)); - analyzers_by_tag.insert(std::make_pair(component->Tag(), component)); - analyzers_by_val.insert(std::make_pair( - component->Tag().AsEnumVal()->InternalInt(), component)); - - string id = fmt("ANALYZER_%s", cname); - tag_enum_type->AddName("Files", id.c_str(), - component->Tag().AsEnumVal()->InternalInt(), true); + RegisterComponent(*i, "ANALYZER_"); } void Manager::InitPostScript() @@ -193,7 +171,7 @@ void Manager::SetSize(uint64 size, analyzer::Tag tag, Connection* conn, bool Manager::SetTimeoutInterval(const string& file_id, double interval) const { - File* file = Lookup(file_id); + File* file = LookupFile(file_id); if ( ! file ) return false; @@ -208,7 +186,7 @@ bool Manager::SetTimeoutInterval(const string& file_id, double interval) const bool Manager::AddAnalyzer(const string& file_id, file_analysis::Tag tag, RecordVal* args) const { - File* file = Lookup(file_id); + File* file = LookupFile(file_id); if ( ! file ) return false; @@ -219,7 +197,7 @@ bool Manager::AddAnalyzer(const string& file_id, file_analysis::Tag tag, bool Manager::RemoveAnalyzer(const string& file_id, file_analysis::Tag tag, RecordVal* args) const { - File* file = Lookup(file_id); + File* file = LookupFile(file_id); if ( ! file ) return false; @@ -257,7 +235,7 @@ File* Manager::GetFile(const string& file_id, Connection* conn, return rval; } -File* Manager::Lookup(const string& file_id) const +File* Manager::LookupFile(const string& file_id) const { IDMap::const_iterator it = id_map.find(file_id); @@ -269,7 +247,7 @@ File* Manager::Lookup(const string& file_id) const void Manager::Timeout(const string& file_id, bool is_terminating) { - File* file = Lookup(file_id); + File* file = LookupFile(file_id); if ( ! file ) return; @@ -370,59 +348,15 @@ bool Manager::IsDisabled(analyzer::Tag tag) Analyzer* Manager::InstantiateAnalyzer(Tag tag, RecordVal* args, File* f) const { - analyzer_map_by_tag::const_iterator it = analyzers_by_tag.find(tag); + Component* c = Lookup(tag); - if ( it == analyzers_by_tag.end() ) + if ( ! c ) reporter->InternalError("cannot instantiate unknown file analyzer: %s", tag.AsString().c_str()); - Component* c = it->second; - if ( ! c->Factory() ) reporter->InternalError("file analyzer %s cannot be instantiated " "dynamically", c->CanonicalName()); return c->Factory()(args, f); } - -const char* Manager::GetAnalyzerName(Val* v) const - { - return GetAnalyzerName(file_analysis::Tag(v->AsEnumVal())); - } - -const char* Manager::GetAnalyzerName(file_analysis::Tag tag) const - { - analyzer_map_by_tag::const_iterator it = analyzers_by_tag.find(tag); - - if ( it == analyzers_by_tag.end() ) - reporter->InternalError("cannot get name of unknown file analyzer: %s", - tag.AsString().c_str()); - - return it->second->CanonicalName(); - } - -file_analysis::Tag Manager::GetAnalyzerTag(const char* name) const - { - analyzer_map_by_name::const_iterator it = analyzers_by_name.find(name); - - if ( it == analyzers_by_name.end() ) - return file_analysis::Tag(); - - return it->second->Tag(); - } - -file_analysis::Tag Manager::GetAnalyzerTag(Val* v) const - { - analyzer_map_by_val::const_iterator it = - analyzers_by_val.find(v->AsEnumVal()->InternalInt()); - - if ( it == analyzers_by_val.end() ) - return file_analysis::Tag(); - - return it->second->Tag(); - } - -EnumType* Manager::GetTagEnumType() - { - return tag_enum_type; - } diff --git a/src/file_analysis/Manager.h b/src/file_analysis/Manager.h index 9a37042669..dcf33edc99 100644 --- a/src/file_analysis/Manager.h +++ b/src/file_analysis/Manager.h @@ -18,7 +18,8 @@ #include "File.h" #include "FileTimer.h" #include "Component.h" - +#include "Tag.h" +#include "plugin/ComponentManager.h" #include "analyzer/Tag.h" #include "file_analysis/file_analysis.bif.h" @@ -28,7 +29,7 @@ namespace file_analysis { /** * Main entry point for interacting with file analysis. */ -class Manager { +class Manager : public plugin::ComponentManager { public: /** @@ -210,48 +211,6 @@ public: */ Analyzer* InstantiateAnalyzer(Tag tag, RecordVal* args, File* f) const; - /** - * Translates a script-level file analyzer tag in to corresponding file - * analyzer name. - * @param v The enum val of a file analyzer. - * @return The human-readable name of the file analyzer. - */ - const char* GetAnalyzerName(Val* v) const; - - /** - * Translates a script-level file analyzer tag in to corresponding file - * analyzer name. - * @param tag The analyzer tag of a file analyzer. - * @return The human-readable name of the file analyzer. - */ - const char* GetAnalyzerName(file_analysis::Tag tag) const; - - /** - * Translates an analyzer name into the corresponding tag. - * - * @param name The name. - * - * @return The tag. If the name does not correspond to a valid - * analyzer, the returned tag will evaluate to false. - */ - file_analysis::Tag GetAnalyzerTag(const char* name) const; - - /** - * Translates an analyzer enum value into the corresponding tag. - * - * @param v the enum val of the file analyzer. - * - * @return The tag. If the val does not correspond to a valid - * analyzer, the returned tag will evaluate to false. - */ - file_analysis::Tag GetAnalyzerTag(Val* v) const; - - /** - * Returns the enum type that corresponds to the script-level type - * \c Files::Tag. - */ - EnumType* GetTagEnumType(); - protected: friend class FileTimer; @@ -285,7 +244,7 @@ protected: * @return the File object mapped to \a file_id, or a null pointer if no * mapping exists. */ - File* Lookup(const string& file_id) const; + File* LookupFile(const string& file_id) const; /** * Evaluate timeout policy for a file and remove the File object mapped to @@ -325,20 +284,10 @@ protected: static bool IsDisabled(analyzer::Tag tag); private: - typedef map analyzer_map_by_name; - typedef map analyzer_map_by_tag; - typedef map analyzer_map_by_val; - - void RegisterAnalyzerComponent(Component* component); IDMap id_map; /**< Map file ID to file_analysis::File records. */ IDSet ignored; /**< Ignored files. Will be finally removed on EOF. */ string current_file_id; /**< Hash of what get_file_handle event sets. */ - EnumType* tag_enum_type; /**< File analyzer tag type. */ - - analyzer_map_by_name analyzers_by_name; - analyzer_map_by_tag analyzers_by_tag; - analyzer_map_by_val analyzers_by_val; static TableVal* disabled; /**< Table of disabled analyzers. */ static string salt; /**< A salt added to file handles before hashing. */ diff --git a/src/file_analysis/Tag.h b/src/file_analysis/Tag.h index 85c20da5b5..aa38836403 100644 --- a/src/file_analysis/Tag.h +++ b/src/file_analysis/Tag.h @@ -6,12 +6,13 @@ #include "config.h" #include "util.h" #include "../Tag.h" +#include "plugin/TaggedComponent.h" +#include "plugin/ComponentManager.h" class EnumVal; namespace file_analysis { -class Manager; class Component; /** @@ -87,15 +88,15 @@ public: static Tag Error; protected: - friend class file_analysis::Manager; - friend class file_analysis::Component; + friend class plugin::ComponentManager; + friend class plugin::TaggedComponent; /** * Constructor. * * @param type The main type. Note that the \a file_analysis::Manager * manages the value space internally, so noone else should assign - * main tyoes. + * main types. * * @param subtype The sub type, which is left to an analyzer for * interpretation. By default it's set to zero. diff --git a/src/file_analysis/analyzer/data_event/DataEvent.cc b/src/file_analysis/analyzer/data_event/DataEvent.cc index 44498f41e1..cf2d7e52ec 100644 --- a/src/file_analysis/analyzer/data_event/DataEvent.cc +++ b/src/file_analysis/analyzer/data_event/DataEvent.cc @@ -12,7 +12,7 @@ using namespace file_analysis; DataEvent::DataEvent(RecordVal* args, File* file, EventHandlerPtr ce, EventHandlerPtr se) - : file_analysis::Analyzer(file_mgr->GetAnalyzerTag("DATA_EVENT"), + : file_analysis::Analyzer(file_mgr->GetComponentTag("DATA_EVENT"), args, file), chunk_event(ce), stream_event(se) { diff --git a/src/file_analysis/analyzer/extract/Extract.cc b/src/file_analysis/analyzer/extract/Extract.cc index 0de1402939..28b5cf5a63 100644 --- a/src/file_analysis/analyzer/extract/Extract.cc +++ b/src/file_analysis/analyzer/extract/Extract.cc @@ -9,7 +9,7 @@ using namespace file_analysis; Extract::Extract(RecordVal* args, File* file, const string& arg_filename) - : file_analysis::Analyzer(file_mgr->GetAnalyzerTag("EXTRACT"), args, file), + : file_analysis::Analyzer(file_mgr->GetComponentTag("EXTRACT"), args, file), filename(arg_filename) { fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666); diff --git a/src/file_analysis/analyzer/hash/Hash.cc b/src/file_analysis/analyzer/hash/Hash.cc index 12463df8bf..9829934301 100644 --- a/src/file_analysis/analyzer/hash/Hash.cc +++ b/src/file_analysis/analyzer/hash/Hash.cc @@ -10,7 +10,7 @@ using namespace file_analysis; Hash::Hash(RecordVal* args, File* file, HashVal* hv, const char* arg_kind) - : file_analysis::Analyzer(file_mgr->GetAnalyzerTag(to_upper(string(arg_kind)).c_str()), args, file), hash(hv), fed(false), kind(arg_kind) + : file_analysis::Analyzer(file_mgr->GetComponentTag(to_upper(arg_kind).c_str()), args, file), hash(hv), fed(false), kind(arg_kind) { hash->Init(); } diff --git a/src/file_analysis/file_analysis.bif b/src/file_analysis/file_analysis.bif index 7e07ddf6bb..0e904f298f 100644 --- a/src/file_analysis/file_analysis.bif +++ b/src/file_analysis/file_analysis.bif @@ -21,7 +21,7 @@ function Files::__add_analyzer%(file_id: string, tag: Files::Tag, args: any%): b using BifType::Record::Files::AnalyzerArgs; RecordVal* rv = args->AsRecordVal()->CoerceTo(AnalyzerArgs); bool result = file_mgr->AddAnalyzer(file_id->CheckString(), - file_mgr->GetAnalyzerTag(tag), rv); + file_mgr->GetComponentTag(tag), rv); Unref(rv); return new Val(result, TYPE_BOOL); %} @@ -32,7 +32,7 @@ function Files::__remove_analyzer%(file_id: string, tag: Files::Tag, args: any%) using BifType::Record::Files::AnalyzerArgs; RecordVal* rv = args->AsRecordVal()->CoerceTo(AnalyzerArgs); bool result = file_mgr->RemoveAnalyzer(file_id->CheckString(), - file_mgr->GetAnalyzerTag(tag) , rv); + file_mgr->GetComponentTag(tag) , rv); Unref(rv); return new Val(result, TYPE_BOOL); %} @@ -47,7 +47,7 @@ function Files::__stop%(file_id: string%): bool ## :bro:see:`Files::analyzer_name`. function Files::__analyzer_name%(tag: Files::Tag%) : string %{ - return new StringVal(file_mgr->GetAnalyzerName(tag)); + return new StringVal(file_mgr->GetComponentName(tag)); %} module GLOBAL; diff --git a/src/plugin/ComponentManager.h b/src/plugin/ComponentManager.h new file mode 100644 index 0000000000..16f9d80743 --- /dev/null +++ b/src/plugin/ComponentManager.h @@ -0,0 +1,248 @@ +#ifndef PLUGIN_COMPONENT_MANAGER_H +#define PLUGIN_COMPONENT_MANAGER_H + +#include +#include +#include + +#include "Type.h" +#include "ID.h" +#include "Var.h" +#include "Val.h" +#include "Reporter.h" + +namespace plugin { + +/** + * A class that manages tracking of plugin components (e.g. analyzers) and + * installs identifiers in the script-layer to identify them by a unique tag, + * (a script-layer enum value). + * + * @tparam T A ::Tag type or derivative. + * @tparam C A plugin::TaggedComponent type derivative. + */ +template +class ComponentManager { +public: + + /** + * Constructor creates a new enum type called a "Tag" to associate with + * a component. + * + * @param module The script-layer module in which to install the "Tag" ID + * representing an enum type. + */ + ComponentManager(const string& module); + + /** + * @return The script-layer module in which the component's "Tag" ID lives. + */ + const char* GetModule() const; + + /** + * @return A list of all registered components. + */ + list GetComponents() const; + + /** + * @return The enum type associated with the script-layer "Tag". + */ + EnumType* GetTagEnumType() const; + + /** + * Get a component name from its tag. + * + * @param tag A component's tag. + * @return The canonical component name. + */ + const char* GetComponentName(T tag) const; + + /** + * Get a component name from it's enum value. + * + * @param val A component's enum value. + * @return The canonical component name. + */ + const char* GetComponentName(Val* val) const; + + /** + * Get a component tag from its name. + * + * @param name A component's canonical name. + * @return The component's tag, or a tag representing an error if + * no such component assoicated with the name exists. + */ + T GetComponentTag(const string& name) const; + + /** + * Get a component tag from its enum value. + * + * @param v A component's enum value. + * @return The component's tag, or a tag representing an error if + * no such component assoicated with the value exists. + */ + T GetComponentTag(Val* v) const; + +protected: + + /** + * Add a component the internal maps used to keep track of it and create + * a script-layer ID for the component's enum value. + * + * @param component A component to track. + * @param prefix The script-layer ID associated with the component's enum + * value will be a concatenation of this prefix and the component's + * canonical name. + */ + void RegisterComponent(C* component, const string& prefix = ""); + + /** + * @param name The canonical name of a component. + * @return The component associated with the name or a null pointer if no + * such component exists. + */ + C* Lookup(const string& name) const; + + /** + * @param name A component tag. + * @return The component associated with the tag or a null pointer if no + * such component exists. + */ + C* Lookup(const T& tag) const; + + /** + * @param name A component's enum value. + * @return The component associated with the value or a null pointer if no + * such component exists. + */ + C* Lookup(EnumVal* val) const; + +private: + + string module; /**< Script layer module in which component tags live. */ + EnumType* tag_enum_type; /**< Enum type of component tags. */ + map components_by_name; + map components_by_tag; + map components_by_val; +}; + +template +ComponentManager::ComponentManager(const string& arg_module) + : module(arg_module) + { + tag_enum_type = new EnumType(module + "::Tag"); + ::ID* id = install_ID("Tag", module.c_str(), true, true); + add_type(id, tag_enum_type, 0, 0); + } + +template +const char* ComponentManager::GetModule() const + { + return module.c_str(); + } + +template +list ComponentManager::GetComponents() const + { + list rval; + typename map::const_iterator i; + + for ( i = components_by_tag.begin(); i != components_by_tag.end(); ++i ) + rval.push_back(i->second); + + return rval; + } + +template +EnumType* ComponentManager::GetTagEnumType() const + { + return tag_enum_type; + } + +template +const char* ComponentManager::GetComponentName(T tag) const + { + static const char* error = ""; + + if ( ! tag ) + return error; + + C* c = Lookup(tag); + + if ( ! c ) + reporter->InternalError("request for name of unknown component tag %s", + tag.AsString().c_str()); + + return c->CanonicalName(); + } + +template +const char* ComponentManager::GetComponentName(Val* val) const + { + return GetComponentName(T(val->AsEnumVal())); + } + +template +T ComponentManager::GetComponentTag(const string& name) const + { + C* c = Lookup(name); + return c ? c->Tag() : T(); + } + +template +T ComponentManager::GetComponentTag(Val* v) const + { + C* c = Lookup(v->AsEnumVal()); + return c ? c->Tag() : T(); + } + +template +C* ComponentManager::Lookup(const string& name) const + { + typename map::const_iterator i = + components_by_name.find(to_upper(name)); + return i != components_by_name.end() ? i->second : 0; + } + +template +C* ComponentManager::Lookup(const T& tag) const + { + typename map::const_iterator i = components_by_tag.find(tag); + return i != components_by_tag.end() ? i->second : 0; + } + +template +C* ComponentManager::Lookup(EnumVal* val) const + { + typename map::const_iterator i = + components_by_val.find(val->InternalInt()); + return i != components_by_val.end() ? i->second : 0; + } + +template +void ComponentManager::RegisterComponent(C* component, + const string& prefix) + { + const char* cname = component->CanonicalName(); + + if ( Lookup(cname) ) + reporter->FatalError("Component '%s::%s' defined more than once", + module.c_str(), cname); + + DBG_LOG(DBG_PLUGINS, "Registering component %s (tag %s)", + component->Name(), component->Tag().AsString().c_str()); + + components_by_name.insert(std::make_pair(cname, component)); + components_by_tag.insert(std::make_pair(component->Tag(), component)); + components_by_val.insert(std::make_pair( + component->Tag().AsEnumVal()->InternalInt(), component)); + + // Install an identfier for enum value + string id = fmt("%s%s", prefix.c_str(), cname); + tag_enum_type->AddName(module, id.c_str(), + component->Tag().AsEnumVal()->InternalInt(), true); + } + +} // namespace plugin + +#endif diff --git a/src/plugin/TaggedComponent.h b/src/plugin/TaggedComponent.h new file mode 100644 index 0000000000..99eab9f230 --- /dev/null +++ b/src/plugin/TaggedComponent.h @@ -0,0 +1,85 @@ +#ifndef PLUGIN_TAGGED_COMPONENT_H +#define PLUGIN_TAGGED_COMPONENT_H + +namespace plugin { + +/** + * A class which has a tag of a given type associated with it. + * + * @tparam T A ::Tag type or derivative. + */ +template +class TaggedComponent { +public: + + /** + * Constructor creates a unique tag value for this component. + * + * @param subtype A subtype associated with this component that + * further distinguishes it. The subtype will be integrated into + * the Tag that the manager associates with this component, + * and component instances can accordingly access it via Tag(). + * If not used, leave at zero. + */ + TaggedComponent(typename T::subtype_t subtype = 0); + + /** + * Copy constructor. + * + * @param other Another component from which to copy its tag value. + */ + TaggedComponent(const TaggedComponent& other); + + /** + * Assignment operator. + * + * @param other A component to assign. + * @return The assigned object. + */ + TaggedComponent& operator=(const TaggedComponent& other); + + /** + * @return The component's tag. + */ + T Tag() const; + +private: + + T tag; /**< The automatically assigned analyzer tag. */ + static typename T::type_t type_counter; /**< Used to generate globally + unique tags. */ +}; + +template +TaggedComponent::TaggedComponent(typename T::subtype_t subtype) + { + tag = T(++type_counter, subtype); + } + +template +TaggedComponent::TaggedComponent(const TaggedComponent& other) + { + tag = other.tag; + } + +template +TaggedComponent& +TaggedComponent::operator =(const TaggedComponent& other) + { + if ( &other != this ) + tag = other.tag; + + return *this; + } + +template +T TaggedComponent::Tag() const + { + return tag; + } + +template typename T::type_t TaggedComponent::type_counter(0); + +} // namespace plugin + +#endif