Internal refactoring of how plugin components are tagged/managed.

Made some class templates for code that seemed duplicated between
file/protocol tags and managers.  Seems like it helps a bit and
hopefully can be also be used to transition other things that have
enum value "tags" (e.g. logging writers, input readers) to the
plugin system.
This commit is contained in:
Jon Siwek 2013-08-01 10:35:47 -05:00
parent 9bd7a65071
commit 99c89b42d7
26 changed files with 432 additions and 366 deletions

View file

@ -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

View file

@ -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)

View file

@ -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
};

View file

@ -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));
}

View file

@ -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;
}

View file

@ -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<analyzer::Tag>(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<analyzer::Tag>(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<analyzer::Tag>::operator=(other);
if ( &other != this )
{
name = copy_string(other.name);
factory = other.factory;
enabled = other.enabled;
partial = other.partial;
tag = other.tag;
}
return *this;

View file

@ -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<analyzer::Tag> {
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;
};
}

View file

@ -60,10 +60,8 @@ bool Manager::ConnIndex::operator<(const ConnIndex& other) const
}
Manager::Manager()
: plugin::ComponentManager<analyzer::Tag, analyzer::Component>("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<Component*> analyzers = plugin_mgr->Components<Component>();
for ( std::list<Component*>::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<Component*> all_analyzers = GetComponents();
for ( list<Component*>::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<Component*> all_analyzers = GetComponents();
for ( list<Component*>::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 = "<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);

View file

@ -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<Tag, Component> {
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> tag_set;
typedef map<string, Component*> analyzer_map_by_name;
typedef map<Tag, Component*> analyzer_map_by_tag;
typedef map<int, Component*> analyzer_map_by_val;
typedef map<uint32, tag_set*> 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.

View file

@ -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<Tag, Component>;
friend class plugin::TaggedComponent<Tag>;
/**
* Constructor.

View file

@ -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();
%}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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<file_analysis::Tag>()
{
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<file_analysis::Tag>(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<file_analysis::Tag>::operator=(other);
if ( &other != this )
{
name = copy_string(other.name);
factory = other.factory;
tag = other.tag;
}
return *this;

View file

@ -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<file_analysis::Tag> {
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;
};
}

View file

@ -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);
}

View file

@ -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;

View file

@ -18,10 +18,8 @@ TableVal* Manager::disabled = 0;
string Manager::salt;
Manager::Manager()
: ComponentManager<file_analysis::Tag, file_analysis::Component>("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<Component*>::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;
}

View file

@ -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<Tag, Component> {
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<string, Component*> analyzer_map_by_name;
typedef map<file_analysis::Tag, Component*> analyzer_map_by_tag;
typedef map<int, Component*> 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. */

View file

@ -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<Tag, Component>;
friend class plugin::TaggedComponent<Tag>;
/**
* 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.

View file

@ -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)
{

View file

@ -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);

View file

@ -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();
}

View file

@ -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;

View file

@ -0,0 +1,248 @@
#ifndef PLUGIN_COMPONENT_MANAGER_H
#define PLUGIN_COMPONENT_MANAGER_H
#include <map>
#include <list>
#include <string>
#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 T, class C>
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<C*> 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<string, C*> components_by_name;
map<T, C*> components_by_tag;
map<int, C*> components_by_val;
};
template <class T, class C>
ComponentManager<T, C>::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 <class T, class C>
const char* ComponentManager<T, C>::GetModule() const
{
return module.c_str();
}
template <class T, class C>
list<C*> ComponentManager<T, C>::GetComponents() const
{
list<C*> rval;
typename map<T, C*>::const_iterator i;
for ( i = components_by_tag.begin(); i != components_by_tag.end(); ++i )
rval.push_back(i->second);
return rval;
}
template <class T, class C>
EnumType* ComponentManager<T, C>::GetTagEnumType() const
{
return tag_enum_type;
}
template <class T, class C>
const char* ComponentManager<T, C>::GetComponentName(T tag) const
{
static const char* error = "<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 <class T, class C>
const char* ComponentManager<T, C>::GetComponentName(Val* val) const
{
return GetComponentName(T(val->AsEnumVal()));
}
template <class T, class C>
T ComponentManager<T, C>::GetComponentTag(const string& name) const
{
C* c = Lookup(name);
return c ? c->Tag() : T();
}
template <class T, class C>
T ComponentManager<T, C>::GetComponentTag(Val* v) const
{
C* c = Lookup(v->AsEnumVal());
return c ? c->Tag() : T();
}
template <class T, class C>
C* ComponentManager<T, C>::Lookup(const string& name) const
{
typename map<string, C*>::const_iterator i =
components_by_name.find(to_upper(name));
return i != components_by_name.end() ? i->second : 0;
}
template <class T, class C>
C* ComponentManager<T, C>::Lookup(const T& tag) const
{
typename map<T, C*>::const_iterator i = components_by_tag.find(tag);
return i != components_by_tag.end() ? i->second : 0;
}
template <class T, class C>
C* ComponentManager<T, C>::Lookup(EnumVal* val) const
{
typename map<int, C*>::const_iterator i =
components_by_val.find(val->InternalInt());
return i != components_by_val.end() ? i->second : 0;
}
template <class T, class C>
void ComponentManager<T, C>::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

View file

@ -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 T>
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 <class T>
TaggedComponent<T>::TaggedComponent(typename T::subtype_t subtype)
{
tag = T(++type_counter, subtype);
}
template <class T>
TaggedComponent<T>::TaggedComponent(const TaggedComponent<T>& other)
{
tag = other.tag;
}
template <class T>
TaggedComponent<T>&
TaggedComponent<T>::operator =(const TaggedComponent<T>& other)
{
if ( &other != this )
tag = other.tag;
return *this;
}
template <class T>
T TaggedComponent<T>::Tag() const
{
return tag;
}
template <class T> typename T::type_t TaggedComponent<T>::type_counter(0);
} // namespace plugin
#endif