mirror of
https://github.com/zeek/zeek.git
synced 2025-10-03 07:08:19 +00:00
212 lines
5.1 KiB
C++
212 lines
5.1 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "AnalyzerSet.h"
|
|
#include "File.h"
|
|
#include "Analyzer.h"
|
|
#include "Manager.h"
|
|
#include "CompHash.h"
|
|
#include "Val.h"
|
|
#include "file_analysis/file_analysis.bif.h"
|
|
|
|
using namespace file_analysis;
|
|
|
|
static void analyzer_del_func(void* v)
|
|
{
|
|
file_analysis::Analyzer* a = (file_analysis::Analyzer*)v;
|
|
|
|
a->Done();
|
|
delete a;
|
|
}
|
|
|
|
AnalyzerSet::AnalyzerSet(File* arg_file) : file(arg_file)
|
|
{
|
|
auto t = make_intrusive<TypeList>();
|
|
t->Append(file_mgr->GetTagType());
|
|
t->Append(zeek::BifType::Record::Files::AnalyzerArgs);
|
|
analyzer_hash = new CompositeHash(std::move(t));
|
|
analyzer_map.SetDeleteFunc(analyzer_del_func);
|
|
}
|
|
|
|
AnalyzerSet::~AnalyzerSet()
|
|
{
|
|
while ( ! mod_queue.empty() )
|
|
{
|
|
Modification* mod = mod_queue.front();
|
|
mod->Abort();
|
|
delete mod;
|
|
mod_queue.pop();
|
|
}
|
|
|
|
delete analyzer_hash;
|
|
}
|
|
|
|
Analyzer* AnalyzerSet::Find(const file_analysis::Tag& tag,
|
|
IntrusivePtr<RecordVal> args)
|
|
{
|
|
auto key = GetKey(tag, std::move(args));
|
|
Analyzer* rval = analyzer_map.Lookup(key.get());
|
|
return rval;
|
|
}
|
|
|
|
bool AnalyzerSet::Add(const file_analysis::Tag& tag, IntrusivePtr<RecordVal> args)
|
|
{
|
|
auto key = GetKey(tag, args);
|
|
|
|
if ( analyzer_map.Lookup(key.get()) )
|
|
{
|
|
DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Instantiate analyzer %s skipped: already exists",
|
|
file->GetID().c_str(),
|
|
file_mgr->GetComponentName(tag).c_str());
|
|
|
|
return true;
|
|
}
|
|
|
|
file_analysis::Analyzer* a = InstantiateAnalyzer(tag, std::move(args));
|
|
|
|
if ( ! a )
|
|
return false;
|
|
|
|
Insert(a, std::move(key));
|
|
|
|
return true;
|
|
}
|
|
|
|
Analyzer* AnalyzerSet::QueueAdd(const file_analysis::Tag& tag,
|
|
IntrusivePtr<RecordVal> args)
|
|
{
|
|
auto key = GetKey(tag, args);
|
|
file_analysis::Analyzer* a = InstantiateAnalyzer(tag, std::move(args));
|
|
|
|
if ( ! a )
|
|
return nullptr;
|
|
|
|
mod_queue.push(new AddMod(a, std::move(key)));
|
|
|
|
return a;
|
|
}
|
|
|
|
bool AnalyzerSet::AddMod::Perform(AnalyzerSet* set)
|
|
{
|
|
if ( set->analyzer_map.Lookup(key.get()) )
|
|
{
|
|
DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Add analyzer %s skipped: already exists",
|
|
a->GetFile()->GetID().c_str(),
|
|
file_mgr->GetComponentName(a->Tag()).c_str());
|
|
|
|
Abort();
|
|
return true;
|
|
}
|
|
|
|
set->Insert(a, std::move(key));
|
|
|
|
return true;
|
|
}
|
|
|
|
void AnalyzerSet::AddMod::Abort()
|
|
{
|
|
delete a;
|
|
}
|
|
|
|
bool AnalyzerSet::Remove(const file_analysis::Tag& tag,
|
|
IntrusivePtr<RecordVal> args)
|
|
{
|
|
return Remove(tag, GetKey(tag, std::move(args)));
|
|
}
|
|
|
|
bool AnalyzerSet::Remove(const file_analysis::Tag& tag,
|
|
std::unique_ptr<HashKey> key)
|
|
{
|
|
auto a = (file_analysis::Analyzer*) analyzer_map.Remove(key.get());
|
|
|
|
if ( ! a )
|
|
{
|
|
DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Skip remove analyzer %s",
|
|
file->GetID().c_str(), file_mgr->GetComponentName(tag).c_str());
|
|
return false;
|
|
}
|
|
|
|
DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Remove analyzer %s",
|
|
file->GetID().c_str(),
|
|
file_mgr->GetComponentName(tag).c_str());
|
|
|
|
a->Done();
|
|
|
|
// We don't delete the analyzer object right here because the remove
|
|
// operation may execute at a time when it can still be accessed.
|
|
// Instead we let the file know to delete the analyzer later.
|
|
file->DoneWithAnalyzer(a);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AnalyzerSet::QueueRemove(const file_analysis::Tag& tag,
|
|
IntrusivePtr<RecordVal> args)
|
|
{
|
|
auto key = GetKey(tag, std::move(args));
|
|
auto rval = analyzer_map.Lookup(key.get());
|
|
mod_queue.push(new RemoveMod(tag, std::move(key)));
|
|
return rval;
|
|
}
|
|
|
|
bool AnalyzerSet::RemoveMod::Perform(AnalyzerSet* set)
|
|
{
|
|
return set->Remove(tag, std::move(key));
|
|
}
|
|
|
|
std::unique_ptr<HashKey> AnalyzerSet::GetKey(const file_analysis::Tag& t,
|
|
IntrusivePtr<RecordVal> args) const
|
|
{
|
|
auto lv = make_intrusive<ListVal>(TYPE_ANY);
|
|
lv->Append(t.AsVal());
|
|
lv->Append(std::move(args));
|
|
auto key = analyzer_hash->MakeHashKey(*lv, true);
|
|
|
|
if ( ! key )
|
|
reporter->InternalError("AnalyzerArgs type mismatch");
|
|
|
|
return key;
|
|
}
|
|
|
|
file_analysis::Analyzer* AnalyzerSet::InstantiateAnalyzer(const Tag& tag,
|
|
IntrusivePtr<RecordVal> args) const
|
|
{
|
|
auto a = file_mgr->InstantiateAnalyzer(tag, std::move(args), file);
|
|
|
|
if ( ! a )
|
|
{
|
|
reporter->Error("[%s] Failed file analyzer %s instantiation",
|
|
file->GetID().c_str(),
|
|
file_mgr->GetComponentName(tag).c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
void AnalyzerSet::Insert(file_analysis::Analyzer* a,
|
|
std::unique_ptr<HashKey> key)
|
|
{
|
|
DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Add analyzer %s",
|
|
file->GetID().c_str(), file_mgr->GetComponentName(a->Tag()).c_str());
|
|
analyzer_map.Insert(key.get(), a);
|
|
|
|
a->Init();
|
|
}
|
|
|
|
void AnalyzerSet::DrainModifications()
|
|
{
|
|
if ( mod_queue.empty() )
|
|
return;
|
|
|
|
DBG_LOG(DBG_FILE_ANALYSIS, "[%s] Start analyzer mod queue flush",
|
|
file->GetID().c_str());
|
|
do
|
|
{
|
|
Modification* mod = mod_queue.front();
|
|
mod->Perform(this);
|
|
delete mod;
|
|
mod_queue.pop();
|
|
} while ( ! mod_queue.empty() );
|
|
DBG_LOG(DBG_FILE_ANALYSIS, "[%s] End flushing analyzer mod queue.",
|
|
file->GetID().c_str());
|
|
}
|