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

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