Deprecate Plugin::HookCallFunction(), replace with HookFunctionCall()

This also changes the argument type of Func::operator() to zeek::Args*
to allow plugins to be able to alter function arguments in place as
was previously documented.
This commit is contained in:
Jon Siwek 2020-05-22 21:01:38 -07:00
parent 46c5dea733
commit 272db640aa
27 changed files with 417 additions and 77 deletions

5
NEWS
View file

@ -106,6 +106,11 @@ Removed Functionality
Deprecated Functionality Deprecated Functionality
------------------------ ------------------------
- The ``plugin::Plugin::HookCallFunction()`` method is deprecated. Note
that compilers will not emit a deprecation warning, but the replacement
method to now use is called ``HookFunctionCall`` and uses ``IntrusivePtr``
arguments and return value.
- The ``Func::Call(val_list*, ...)`` method is now deprecated. Use operator() - The ``Func::Call(val_list*, ...)`` method is now deprecated. Use operator()
instead which takes a ``zeek::Args`` (``std::vector<IntrusivePtr<Val>>``). instead which takes a ``zeek::Args`` (``std::vector<IntrusivePtr<Val>>``).
There's also a variadic template for operator() that forwards all arguments There's also a variadic template for operator() that forwards all arguments

View file

@ -43,7 +43,7 @@ bool Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
try try
{ {
discard_packet = check_ip->operator()(args)->AsBool(); discard_packet = check_ip->operator()(&args)->AsBool();
} }
catch ( InterpreterException& e ) catch ( InterpreterException& e )
@ -98,7 +98,7 @@ bool Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
try try
{ {
discard_packet = check_tcp->operator()(args)->AsBool(); discard_packet = check_tcp->operator()(&args)->AsBool();
} }
catch ( InterpreterException& e ) catch ( InterpreterException& e )
@ -122,7 +122,7 @@ bool Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
try try
{ {
discard_packet = check_udp->operator()(args)->AsBool(); discard_packet = check_udp->operator()(&args)->AsBool();
} }
catch ( InterpreterException& e ) catch ( InterpreterException& e )
@ -142,7 +142,7 @@ bool Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
try try
{ {
discard_packet = check_icmp->operator()(args)->AsBool(); discard_packet = check_icmp->operator()(&args)->AsBool();
} }
catch ( InterpreterException& e ) catch ( InterpreterException& e )

View file

@ -56,7 +56,7 @@ void Event::Dispatch(bool no_remote)
try try
{ {
handler->Call(args, no_remote); handler->Call(&args, no_remote);
} }
catch ( InterpreterException& e ) catch ( InterpreterException& e )

View file

@ -44,7 +44,7 @@ const IntrusivePtr<FuncType>& EventHandler::GetType(bool check_export)
return type; return type;
} }
void EventHandler::Call(const zeek::Args& vl, bool no_remote) void EventHandler::Call(zeek::Args* vl, bool no_remote)
{ {
#ifdef PROFILE_BRO_FUNCTIONS #ifdef PROFILE_BRO_FUNCTIONS
DEBUG_MSG("Event: %s\n", Name()); DEBUG_MSG("Event: %s\n", Name());
@ -59,12 +59,12 @@ void EventHandler::Call(const zeek::Args& vl, bool no_remote)
{ {
// Send event in form [name, xs...] where xs represent the arguments. // Send event in form [name, xs...] where xs represent the arguments.
broker::vector xs; broker::vector xs;
xs.reserve(vl.size()); xs.reserve(vl->size());
bool valid_args = true; bool valid_args = true;
for ( auto i = 0u; i < vl.size(); ++i ) for ( auto i = 0u; i < vl->size(); ++i )
{ {
auto opt_data = bro_broker::val_to_data(vl[i].get()); auto opt_data = bro_broker::val_to_data((*vl)[i].get());
if ( opt_data ) if ( opt_data )
xs.emplace_back(std::move(*opt_data)); xs.emplace_back(std::move(*opt_data));
@ -101,7 +101,7 @@ void EventHandler::Call(const zeek::Args& vl, bool no_remote)
local->operator()(vl); local->operator()(vl);
} }
void EventHandler::NewEvent(const zeek::Args& vl) void EventHandler::NewEvent(zeek::Args* vl)
{ {
if ( ! new_event ) if ( ! new_event )
return; return;
@ -132,8 +132,8 @@ void EventHandler::NewEvent(const zeek::Args& vl)
if ( fdefault ) if ( fdefault )
rec->Assign(2, std::move(fdefault)); rec->Assign(2, std::move(fdefault));
if ( i < static_cast<int>(vl.size()) && vl[i] ) if ( i < static_cast<int>(vl->size()) && (*vl)[i] )
rec->Assign(3, vl[i]); rec->Assign(3, (*vl)[i]);
vargs->Assign(i, std::move(rec)); vargs->Assign(i, std::move(rec));
} }

View file

@ -45,7 +45,7 @@ public:
auto_publish.erase(topic); auto_publish.erase(topic);
} }
void Call(const zeek::Args& vl, bool no_remote = false); void Call(zeek::Args* vl, bool no_remote = false);
// Returns true if there is at least one local or remote handler. // Returns true if there is at least one local or remote handler.
explicit operator bool() const; explicit operator bool() const;
@ -66,7 +66,7 @@ public:
bool GenerateAlways() { return generate_always; } bool GenerateAlways() { return generate_always; }
private: private:
void NewEvent(const zeek::Args& vl); // Raise new_event() meta event. void NewEvent(zeek::Args* vl); // Raise new_event() meta event.
std::string name; std::string name;
IntrusivePtr<Func> local; IntrusivePtr<Func> local;

View file

@ -4133,7 +4133,8 @@ IntrusivePtr<Val> CallExpr::Eval(Frame* f) const
if ( f ) if ( f )
f->SetCall(this); f->SetCall(this);
ret = funcv->operator()(*v, f); auto& args = *v;
ret = funcv->operator()(&args, f);
if ( f ) if ( f )
f->SetCall(current_call); f->SetCall(current_call);

View file

@ -214,13 +214,13 @@ void Func::CopyStateInto(Func* other) const
other->unique_id = unique_id; other->unique_id = unique_id;
} }
void Func::CheckPluginResult(bool hooked, const IntrusivePtr<Val>& hook_result, void Func::CheckPluginResult(bool handled, const IntrusivePtr<Val>& hook_result,
function_flavor flavor) const function_flavor flavor) const
{ {
// Helper function factoring out this code from BroFunc:Call() for // Helper function factoring out this code from BroFunc:Call() for
// better readability. // better readability.
if ( ! hooked ) if ( ! handled )
{ {
if ( hook_result ) if ( hook_result )
reporter->InternalError("plugin set processed flag to false but actually returned a value"); reporter->InternalError("plugin set processed flag to false but actually returned a value");
@ -297,9 +297,12 @@ bool BroFunc::IsPure() const
} }
Val* Func::Call(val_list* args, Frame* parent) const Val* Func::Call(val_list* args, Frame* parent) const
{ return operator()(zeek::val_list_to_args(*args), parent).release(); }; {
auto zargs = zeek::val_list_to_args(*args);
return operator()(&zargs, parent).release();
};
IntrusivePtr<Val> BroFunc::operator()(const zeek::Args& args, Frame* parent) const IntrusivePtr<Val> BroFunc::operator()(zeek::Args* args, Frame* parent) const
{ {
#ifdef PROFILE_BRO_FUNCTIONS #ifdef PROFILE_BRO_FUNCTIONS
DEBUG_MSG("Function: %s\n", Name()); DEBUG_MSG("Function: %s\n", Name());
@ -309,13 +312,13 @@ IntrusivePtr<Val> BroFunc::operator()(const zeek::Args& args, Frame* parent) con
if ( sample_logger ) if ( sample_logger )
sample_logger->FunctionSeen(this); sample_logger->FunctionSeen(this);
auto [hooked, hook_result] = PLUGIN_HOOK_WITH_RESULT(HOOK_CALL_FUNCTION, auto [handled, hook_result] = PLUGIN_HOOK_WITH_RESULT(HOOK_CALL_FUNCTION,
HookCallFunction(this, parent, args), HookCallFunction(this, parent, args),
empty_hook_result); empty_hook_result);
CheckPluginResult(hooked, hook_result, Flavor()); CheckPluginResult(handled, hook_result, Flavor());
if ( hooked ) if ( handled )
return hook_result; return hook_result;
if ( bodies.empty() ) if ( bodies.empty() )
@ -325,7 +328,7 @@ IntrusivePtr<Val> BroFunc::operator()(const zeek::Args& args, Frame* parent) con
return Flavor() == FUNC_FLAVOR_HOOK ? val_mgr->True() : nullptr; return Flavor() == FUNC_FLAVOR_HOOK ? val_mgr->True() : nullptr;
} }
auto f = make_intrusive<Frame>(frame_size, this, &args); auto f = make_intrusive<Frame>(frame_size, this, args);
if ( closure ) if ( closure )
f->CaptureClosure(closure, outer_ids); f->CaptureClosure(closure, outer_ids);
@ -339,12 +342,12 @@ IntrusivePtr<Val> BroFunc::operator()(const zeek::Args& args, Frame* parent) con
g_frame_stack.push_back(f.get()); // used for backtracing g_frame_stack.push_back(f.get()); // used for backtracing
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr; const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
call_stack.emplace_back(CallInfo{call_expr, this, args}); call_stack.emplace_back(CallInfo{call_expr, this, *args});
if ( g_trace_state.DoTrace() ) if ( g_trace_state.DoTrace() )
{ {
ODesc d; ODesc d;
DescribeDebug(&d, &args); DescribeDebug(&d, args);
g_trace_state.LogTrace("%s called: %s\n", g_trace_state.LogTrace("%s called: %s\n",
GetType()->FlavorString().c_str(), d.Description()); GetType()->FlavorString().c_str(), d.Description());
@ -360,16 +363,16 @@ IntrusivePtr<Val> BroFunc::operator()(const zeek::Args& args, Frame* parent) con
body.stmts->GetLocationInfo()); body.stmts->GetLocationInfo());
// Fill in the rest of the frame with the function's arguments. // Fill in the rest of the frame with the function's arguments.
for ( auto j = 0u; j < args.size(); ++j ) for ( auto j = 0u; j < args->size(); ++j )
{ {
Val* arg = args[j].get(); Val* arg = (*args)[j].get();
if ( f->NthElement(j) != arg ) if ( f->NthElement(j) != arg )
// Either not yet set, or somebody reassigned the frame slot. // Either not yet set, or somebody reassigned the frame slot.
f->SetElement(j, arg->Ref()); f->SetElement(j, arg->Ref());
} }
f->Reset(args.size()); f->Reset(args->size());
try try
{ {
@ -607,7 +610,7 @@ bool BuiltinFunc::IsPure() const
return is_pure; return is_pure;
} }
IntrusivePtr<Val> BuiltinFunc::operator()(const zeek::Args& args, Frame* parent) const IntrusivePtr<Val> BuiltinFunc::operator()(zeek::Args* args, Frame* parent) const
{ {
#ifdef PROFILE_BRO_FUNCTIONS #ifdef PROFILE_BRO_FUNCTIONS
DEBUG_MSG("Function: %s\n", Name()); DEBUG_MSG("Function: %s\n", Name());
@ -617,26 +620,26 @@ IntrusivePtr<Val> BuiltinFunc::operator()(const zeek::Args& args, Frame* parent)
if ( sample_logger ) if ( sample_logger )
sample_logger->FunctionSeen(this); sample_logger->FunctionSeen(this);
auto [hooked, hook_result] = PLUGIN_HOOK_WITH_RESULT(HOOK_CALL_FUNCTION, auto [handled, hook_result] = PLUGIN_HOOK_WITH_RESULT(HOOK_CALL_FUNCTION,
HookCallFunction(this, parent, args), HookCallFunction(this, parent, args),
empty_hook_result); empty_hook_result);
CheckPluginResult(hooked, hook_result, FUNC_FLAVOR_FUNCTION); CheckPluginResult(handled, hook_result, FUNC_FLAVOR_FUNCTION);
if ( hooked ) if ( handled )
return hook_result; return hook_result;
if ( g_trace_state.DoTrace() ) if ( g_trace_state.DoTrace() )
{ {
ODesc d; ODesc d;
DescribeDebug(&d, &args); DescribeDebug(&d, args);
g_trace_state.LogTrace("\tBuiltin Function called: %s\n", d.Description()); g_trace_state.LogTrace("\tBuiltin Function called: %s\n", d.Description());
} }
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr; const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
call_stack.emplace_back(CallInfo{call_expr, this, args}); call_stack.emplace_back(CallInfo{call_expr, this, *args});
auto result = std::move(func(parent, &args).rval); auto result = std::move(func(parent, args).rval);
call_stack.pop_back(); call_stack.pop_back();
if ( result && g_trace_state.DoTrace() ) if ( result && g_trace_state.DoTrace() )

View file

@ -60,7 +60,7 @@ public:
* @param parent the frame from which the function is being called. * @param parent the frame from which the function is being called.
* @return the return value of the function call. * @return the return value of the function call.
*/ */
virtual IntrusivePtr<Val> operator()(const zeek::Args& args, virtual IntrusivePtr<Val> operator()(zeek::Args* args,
Frame* parent = nullptr) const = 0; Frame* parent = nullptr) const = 0;
/** /**
@ -72,7 +72,10 @@ public:
IntrusivePtr<Val>>, IntrusivePtr<Val>>,
IntrusivePtr<Val>> IntrusivePtr<Val>>
operator()(Args&&... args) const operator()(Args&&... args) const
{ return operator()(zeek::Args{std::forward<Args>(args)...}); } {
auto zargs = zeek::Args{std::forward<Args>(args)...};
return operator()(&zargs);
}
// Add a new event handler to an existing function (event). // Add a new event handler to an existing function (event).
virtual void AddBody(IntrusivePtr<Stmt> new_body, id_list* new_inits, virtual void AddBody(IntrusivePtr<Stmt> new_body, id_list* new_inits,
@ -110,7 +113,7 @@ protected:
void CopyStateInto(Func* other) const; void CopyStateInto(Func* other) const;
// Helper function for checking result of plugin hook. // Helper function for checking result of plugin hook.
void CheckPluginResult(bool hooked, const IntrusivePtr<Val>& hook_result, void CheckPluginResult(bool handled, const IntrusivePtr<Val>& hook_result,
function_flavor flavor) const; function_flavor flavor) const;
std::vector<Body> bodies; std::vector<Body> bodies;
@ -129,7 +132,7 @@ public:
~BroFunc() override; ~BroFunc() override;
bool IsPure() const override; bool IsPure() const override;
IntrusivePtr<Val> operator()(const zeek::Args& args, Frame* parent) const override; IntrusivePtr<Val> operator()(zeek::Args* args, Frame* parent) const override;
/** /**
* Adds adds a closure to the function. Closures are cloned and * Adds adds a closure to the function. Closures are cloned and
@ -225,7 +228,7 @@ public:
~BuiltinFunc() override; ~BuiltinFunc() override;
bool IsPure() const override; bool IsPure() const override;
IntrusivePtr<Val> operator()(const zeek::Args& args, Frame* parent) const override; IntrusivePtr<Val> operator()(zeek::Args* args, Frame* parent) const override;
built_in_func TheFunc() const { return func; } built_in_func TheFunc() const { return func; }
void Describe(ODesc* d) const override; void Describe(ODesc* d) const override;

View file

@ -181,7 +181,7 @@ bool RuleConditionEval::DoMatch(Rule* rule, RuleEndpointState* state,
try try
{ {
auto val = id->GetVal()->AsFunc()->operator()(args); auto val = id->GetVal()->AsFunc()->operator()(&args);
result = val && val->AsBool(); result = val && val->AsBool();
} }

View file

@ -1879,7 +1879,7 @@ IntrusivePtr<Val> TableVal::Default(const IntrusivePtr<Val>& index)
try try
{ {
result = f->operator()(vl); result = f->operator()(&vl);
} }
catch ( InterpreterException& e ) catch ( InterpreterException& e )
@ -2088,7 +2088,7 @@ void TableVal::CallChangeFunc(const Val* index,
vl.emplace_back(old_value); vl.emplace_back(old_value);
in_change_func = true; in_change_func = true;
f->operator()(vl); f->operator()(&vl);
} }
catch ( InterpreterException& e ) catch ( InterpreterException& e )
{ {
@ -2545,7 +2545,7 @@ double TableVal::CallExpireFunc(IntrusivePtr<ListVal> idx)
vl.emplace_back(std::move(idx)); vl.emplace_back(std::move(idx));
} }
auto result = f->operator()(vl); auto result = f->operator()(&vl);
if ( result ) if ( result )
secs = result->AsInterval(); secs = result->AsInterval();

View file

@ -188,7 +188,7 @@ function Cluster::publish_rr%(pool: Pool, key: string, ...%): bool
topic_func = global_scope()->Find("Cluster::rr_topic")->GetVal()->AsFunc(); topic_func = global_scope()->Find("Cluster::rr_topic")->GetVal()->AsFunc();
zeek::Args vl{{NewRef{}, pool}, {NewRef{}, key}}; zeek::Args vl{{NewRef{}, pool}, {NewRef{}, key}};
auto topic = topic_func->operator()(vl); auto topic = topic_func->operator()(&vl);
if ( ! topic->AsString()->Len() ) if ( ! topic->AsString()->Len() )
return val_mgr->False(); return val_mgr->False();
@ -225,7 +225,7 @@ function Cluster::publish_hrw%(pool: Pool, key: any, ...%): bool
topic_func = global_scope()->Find("Cluster::hrw_topic")->GetVal()->AsFunc(); topic_func = global_scope()->Find("Cluster::hrw_topic")->GetVal()->AsFunc();
zeek::Args vl{{NewRef{}, pool}, {NewRef{}, key}}; zeek::Args vl{{NewRef{}, pool}, {NewRef{}, key}};
auto topic = topic_func->operator()(vl); auto topic = topic_func->operator()(&vl);
if ( ! topic->AsString()->Len() ) if ( ! topic->AsString()->Len() )
return val_mgr->False(); return val_mgr->False();

View file

@ -1768,7 +1768,7 @@ bool Manager::CallPred(Func* pred_func, const int numvals, ...) const
va_end(lP); va_end(lP);
auto v = pred_func->operator()(vl); auto v = pred_func->operator()(&vl);
if ( v ) if ( v )
result = v->AsBool(); result = v->AsBool();

View file

@ -24,7 +24,7 @@ static bool call_option_handlers_and_set_value(StringVal* name, const IntrusiveP
if ( add_loc ) if ( add_loc )
vl.emplace_back(NewRef{}, location); vl.emplace_back(NewRef{}, location);
val = handler_function->operator()(vl); // consumed by next call. val = handler_function->operator()(&vl); // consumed by next call.
if ( ! val ) if ( ! val )
{ {

View file

@ -624,43 +624,35 @@ int Manager::HookLoadFile(const Plugin::LoadType type, const string& file, const
std::pair<bool, IntrusivePtr<Val>> std::pair<bool, IntrusivePtr<Val>>
Manager::HookCallFunction(const Func* func, Frame* parent, Manager::HookCallFunction(const Func* func, Frame* parent,
const zeek::Args& vecargs) const zeek::Args* vecargs) const
{ {
HookArgumentList args; HookArgumentList args;
std::optional<val_list> vargs; val_list vargs;
if ( HavePluginForHook(META_HOOK_PRE) ) if ( HavePluginForHook(META_HOOK_PRE) )
{ {
vargs = val_list(vecargs.size()); vargs.resize(vecargs->size());
for ( const auto& v : vecargs ) for ( const auto& v : *vecargs )
vargs->push_back(v.get()); vargs.push_back(v.get());
args.push_back(HookArgument(func)); args.push_back(HookArgument(func));
args.push_back(HookArgument(parent)); args.push_back(HookArgument(parent));
args.push_back(HookArgument(&vargs.value())); args.push_back(HookArgument(&vargs));
MetaHookPre(HOOK_CALL_FUNCTION, args); MetaHookPre(HOOK_CALL_FUNCTION, args);
} }
hook_list* l = hooks[HOOK_CALL_FUNCTION]; hook_list* l = hooks[HOOK_CALL_FUNCTION];
std::pair<bool, Val*> rval{false, nullptr}; std::pair<bool, IntrusivePtr<Val>> rval{false, nullptr};
if ( l ) if ( l )
{ {
if ( ! vargs )
{
vargs = val_list(vecargs.size());
for ( const auto& v : vecargs )
vargs->push_back(v.get());
}
for ( hook_list::iterator i = l->begin(); i != l->end(); ++i ) for ( hook_list::iterator i = l->begin(); i != l->end(); ++i )
{ {
Plugin* p = (*i).second; Plugin* p = (*i).second;
rval = p->HookCallFunction(func, parent, &vargs.value()); rval = p->HookFunctionCall(func, parent, vecargs);
if ( rval.first ) if ( rval.first )
break; break;
@ -668,9 +660,10 @@ Manager::HookCallFunction(const Func* func, Frame* parent,
} }
if ( HavePluginForHook(META_HOOK_POST) ) if ( HavePluginForHook(META_HOOK_POST) )
MetaHookPost(HOOK_CALL_FUNCTION, args, HookArgument(rval)); MetaHookPost(HOOK_CALL_FUNCTION, args,
HookArgument(std::make_pair(rval.first, rval.second.get())));
return {rval.first, {AdoptRef{}, rval.second}}; return rval;
} }
bool Manager::HookQueueEvent(Event* event) const bool Manager::HookQueueEvent(Event* event) const

View file

@ -256,7 +256,7 @@ public:
* the method returns null. * the method returns null.
*/ */
std::pair<bool, IntrusivePtr<Val>> std::pair<bool, IntrusivePtr<Val>>
HookCallFunction(const Func* func, Frame* parent, const zeek::Args& args) const; HookCallFunction(const Func* func, Frame* parent, zeek::Args* args) const;
/** /**
* Hook that filters the queuing of an event. * Hook that filters the queuing of an event.

View file

@ -151,6 +151,17 @@ void HookArgument::Describe(ODesc* d) const
d->Add("<null>"); d->Add("<null>");
break; break;
case ARG_LIST:
if ( arg.args)
{
d->Add("(");
describe_vals(*arg.args, d);
d->Add(")");
}
else
d->Add("<null>");
break;
case VOID: case VOID:
d->Add("<void>"); d->Add("<void>");
break; break;
@ -364,6 +375,26 @@ int Plugin::HookLoadFile(const LoadType type, const std::string& file, const std
return -1; return -1;
} }
std::pair<bool, IntrusivePtr<Val>>
Plugin::HookFunctionCall(const Func* func, Frame* parent,
zeek::Args* args)
{
val_list vlargs(args->size());
for ( auto& v : *args )
vlargs.push_back(v.release());
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
auto [handled, result] = HookCallFunction(func, parent, &vlargs);
#pragma GCC diagnostic pop
for ( auto i = 0u; i < args->size(); ++i )
(*args)[i] = {AdoptRef{}, vlargs[i]};
return {handled, {AdoptRef{}, result}};
}
std::pair<bool, Val*> Plugin::HookCallFunction(const Func* func, Frame *parent, val_list* args) std::pair<bool, Val*> Plugin::HookCallFunction(const Func* func, Frame *parent, val_list* args)
{ {
std::pair<bool, Val*> result(false, NULL); std::pair<bool, Val*> result(false, NULL);

View file

@ -8,6 +8,7 @@
#include "zeek-config.h" #include "zeek-config.h"
#include "logging/WriterBackend.h" #include "logging/WriterBackend.h"
#include "ZeekArgs.h"
// Increase this when making incompatible changes to the plugin API. Note // Increase this when making incompatible changes to the plugin API. Note
// that the constant is never used in C code. It's picked up on by CMake. // that the constant is never used in C code. It's picked up on by CMake.
@ -177,7 +178,8 @@ public:
*/ */
enum Type { enum Type {
BOOL, DOUBLE, EVENT, FRAME, FUNC, FUNC_RESULT, INT, STRING, VAL, BOOL, DOUBLE, EVENT, FRAME, FUNC, FUNC_RESULT, INT, STRING, VAL,
VAL_LIST, VOID, VOIDP, WRITER_INFO, CONN, THREAD_FIELDS, LOCATION VAL_LIST, VOID, VOIDP, WRITER_INFO, CONN, THREAD_FIELDS, LOCATION,
ARG_LIST
}; };
/** /**
@ -260,6 +262,11 @@ public:
*/ */
explicit HookArgument(const Location* location) { type = LOCATION; arg.loc = location; } explicit HookArgument(const Location* location) { type = LOCATION; arg.loc = location; }
/**
* Constructor with a zeek::Args argument.
*/
explicit HookArgument(const zeek::Args* args) { type = ARG_LIST; arg.args = args; }
/** /**
* Returns the value for a boolen argument. The argument's type must * Returns the value for a boolen argument. The argument's type must
* match accordingly. * match accordingly.
@ -338,6 +345,11 @@ public:
*/ */
const val_list* AsValList() const { assert(type == VAL_LIST); return arg.vals; } const val_list* AsValList() const { assert(type == VAL_LIST); return arg.vals; }
/**
* Returns the value as a zeek::Args.
*/
const zeek::Args* AsArgList() const { assert(type == ARG_LIST); return arg.args; }
/** /**
* Returns the value for a vod pointer argument. The argument's type * Returns the value for a vod pointer argument. The argument's type
* must match accordingly. * must match accordingly.
@ -368,6 +380,7 @@ private:
int int_; int int_;
const Val* val; const Val* val;
const val_list* vals; const val_list* vals;
const zeek::Args* args;
const void* voidp; const void* voidp;
const logging::WriterBackend::WriterInfo* winfo; const logging::WriterBackend::WriterInfo* winfo;
const Location* loc; const Location* loc;
@ -664,12 +677,15 @@ protected:
* in place as long as it ensures matching types and correct reference * in place as long as it ensures matching types and correct reference
* counting. * counting.
* *
* @return If the plugin handled the call, a std::pair<bool, Val*> with the * @return If the plugin handled the call, a pair with the first member
* processed flag set to true, and a value set on the object with * set to true, and a Val representing the result value to pass back to the
* a+1 reference count containing the result value to pass back to the * interpreter. If the plugin did not handle the call, it must return a
* interpreter. If the plugin did not handle the call, it must * pair with the first member set to 'false' and null result value.
* return a pair with the processed flag set to 'false'.
*/ */
virtual std::pair<bool, IntrusivePtr<Val>>
HookFunctionCall(const Func* func, Frame* parent, zeek::Args* args);
[[deprecated("Remove in v4.1. Use HookFunctionCall()")]]
virtual std::pair<bool, Val*> HookCallFunction(const Func* func, Frame *parent, val_list* args); virtual std::pair<bool, Val*> HookCallFunction(const Func* func, Frame *parent, val_list* args);
/** /**

View file

@ -0,0 +1,4 @@
1590206064.237264 MetaHookPre CallFunction(foo, <frame>, (1, 2, 3, yo))
1590206064.237264 | HookFunctionCall foo(1, 2, 3, yo)
1590206064.237264 MetaHookPost CallFunction(foo, <frame>, (1, 2, 3, yo)) -> <no result>
foo, 42, 2, 3, yo

View file

@ -0,0 +1,4 @@
1590205948.002795 MetaHookPre CallFunction(foo, <frame>, (1, 2, 3, yo))
1590205948.002795 | HookCallFunction foo(1, 2, 3, yo)
1590205948.002795 MetaHookPost CallFunction(foo, <frame>, (1, 2, 3, yo)) -> <no result>
foo, 13, 2, 3, yo

View file

@ -0,0 +1,86 @@
#include "Plugin.h"
#include <Val.h>
#include <Func.h>
#include <Event.h>
#include <Conn.h>
#include <Desc.h>
#include <threading/Formatter.h>
namespace plugin { namespace Demo_Hooks { Plugin plugin; } }
using namespace plugin::Demo_Hooks;
plugin::Configuration Plugin::Configure()
{
EnableHook(HOOK_CALL_FUNCTION);
EnableHook(META_HOOK_PRE);
EnableHook(META_HOOK_POST);
plugin::Configuration config;
config.name = "Demo::Hooks";
config.description = "Exercises all plugin hooks";
config.version.major = 1;
config.version.minor = 0;
config.version.patch = 0;
return config;
}
static void describe_hook_args(const plugin::HookArgumentList& args, ODesc* d)
{
bool first = true;
for ( plugin::HookArgumentList::const_iterator i = args.begin(); i != args.end(); i++ )
{
if ( ! first )
d->Add(", ");
i->Describe(d);
first = false;
}
}
std::pair<bool, IntrusivePtr<Val>> Plugin::HookFunctionCall(const Func* func,
Frame* frame,
zeek::Args* args)
{
ODesc d;
d.SetShort();
HookArgument(func).Describe(&d);
HookArgument(args).Describe(&d);
fprintf(stderr, "%.6f %-15s %s\n", network_time, "| HookFunctionCall",
d.Description());
if ( streq(func->Name(), "foo") )
{
auto& vl = *args;
vl[0] = val_mgr->Count(42);
}
return {};
}
void Plugin::MetaHookPre(HookType hook, const HookArgumentList& args)
{
ODesc d;
d.SetShort();
describe_hook_args(args, &d);
fprintf(stderr, "%.6f %-15s %s(%s)\n", network_time, " MetaHookPre",
hook_name(hook), d.Description());
}
void Plugin::MetaHookPost(HookType hook, const HookArgumentList& args, HookArgument result)
{
ODesc d1;
d1.SetShort();
describe_hook_args(args, &d1);
ODesc d2;
d2.SetShort();
result.Describe(&d2);
fprintf(stderr, "%.6f %-15s %s(%s) -> %s\n", network_time, " MetaHookPost",
hook_name(hook), d1.Description(),
d2.Description());
}

View file

@ -0,0 +1,27 @@
#pragma once
#include <plugin/Plugin.h>
namespace plugin {
namespace Demo_Hooks {
class Plugin : public ::plugin::Plugin
{
protected:
std::pair<bool, IntrusivePtr<Val>> HookFunctionCall(const Func* func,
Frame* frame,
zeek::Args* args) override;
void MetaHookPre(HookType hook, const HookArgumentList& args) override;
void MetaHookPost(HookType hook, const HookArgumentList& args, HookArgument result) override;
// Overridden from plugin::Plugin.
plugin::Configuration Configure() override;
};
extern Plugin plugin;
}
}

View file

@ -0,0 +1,17 @@
# @TEST-EXEC: ${DIST}/aux/zeek-aux/plugin-support/init-plugin -u . Demo Hooks
# @TEST-EXEC: cp -r %DIR/func-hook-plugin/* .
# @TEST-EXEC: ./configure --zeek-dist=${DIST} && make
# @TEST-EXEC: ZEEK_PLUGIN_ACTIVATE="Demo::Hooks" ZEEK_PLUGIN_PATH=`pwd` zeek -b %INPUT 2>&1 | grep foo >output
# @TEST-EXEC: btest-diff output
@unload base/misc/version
function foo(a: count, b: count, c: count, s: string)
{
print "foo", a, b, c, s;
}
event zeek_init()
{
foo(1, 2, 3, "yo");
}

View file

@ -0,0 +1,105 @@
#include "Plugin.h"
#include <Val.h>
#include <Func.h>
#include <Event.h>
#include <Conn.h>
#include <Desc.h>
#include <threading/Formatter.h>
namespace plugin { namespace Demo_Hooks { Plugin plugin; } }
using namespace plugin::Demo_Hooks;
plugin::Configuration Plugin::Configure()
{
EnableHook(HOOK_CALL_FUNCTION);
EnableHook(META_HOOK_PRE);
EnableHook(META_HOOK_POST);
plugin::Configuration config;
config.name = "Demo::Hooks";
config.description = "Exercises all plugin hooks";
config.version.major = 1;
config.version.minor = 0;
config.version.patch = 0;
return config;
}
static void describe_hook_args(const plugin::HookArgumentList& args, ODesc* d)
{
bool first = true;
for ( plugin::HookArgumentList::const_iterator i = args.begin(); i != args.end(); i++ )
{
if ( ! first )
d->Add(", ");
i->Describe(d);
first = false;
}
}
std::pair<bool, Val*> Plugin::HookCallFunction(const Func* func, Frame* frame, val_list* args)
{
ODesc d;
d.SetShort();
HookArgument(func).Describe(&d);
HookArgument(args).Describe(&d);
fprintf(stderr, "%.6f %-15s %s\n", network_time, "| HookCallFunction",
d.Description());
if ( streq(func->Name(), "foo") )
{
auto& vl = *args;
Unref(vl[0]);
vl[0] = val_mgr->Count(13).release();
}
return {};
}
/* std::pair<bool, IntrusivePtr<Val>> Plugin::HookFunctionCall(const Func* func, */
/* Frame* frame, */
/* zeek::Args* args) */
/* { */
/* ODesc d; */
/* d.SetShort(); */
/* HookArgument(func).Describe(&d); */
/* HookArgument(args).Describe(&d); */
/* fprintf(stderr, "%.6f %-15s %s\n", network_time, "| HookFunctionCall", */
/* d.Description()); */
/* if ( streq(func->Name(), "foo") ) */
/* { */
/* auto& vl = *args; */
/* vl[0] = val_mgr->Count(42); */
/* } */
/* return {}; */
/* } */
void Plugin::MetaHookPre(HookType hook, const HookArgumentList& args)
{
ODesc d;
d.SetShort();
describe_hook_args(args, &d);
fprintf(stderr, "%.6f %-15s %s(%s)\n", network_time, " MetaHookPre",
hook_name(hook), d.Description());
}
void Plugin::MetaHookPost(HookType hook, const HookArgumentList& args, HookArgument result)
{
ODesc d1;
d1.SetShort();
describe_hook_args(args, &d1);
ODesc d2;
d2.SetShort();
result.Describe(&d2);
fprintf(stderr, "%.6f %-15s %s(%s) -> %s\n", network_time, " MetaHookPost",
hook_name(hook), d1.Description(),
d2.Description());
}

View file

@ -0,0 +1,28 @@
#pragma once
#include <plugin/Plugin.h>
namespace plugin {
namespace Demo_Hooks {
class Plugin : public ::plugin::Plugin
{
protected:
std::pair<bool, Val*> HookCallFunction(const Func* func, Frame* frame, val_list* args) override;
/* std::pair<bool, IntrusivePtr<Val>> HookFunctionCall(const Func* func, */
/* Frame* frame, */
/* zeek::Args* args) override; */
void MetaHookPre(HookType hook, const HookArgumentList& args) override;
void MetaHookPost(HookType hook, const HookArgumentList& args, HookArgument result) override;
// Overridden from plugin::Plugin.
plugin::Configuration Configure() override;
};
extern Plugin plugin;
}
}

View file

@ -0,0 +1,17 @@
# @TEST-EXEC: ${DIST}/aux/zeek-aux/plugin-support/init-plugin -u . Demo Hooks
# @TEST-EXEC: cp -r %DIR/legacy-func-hook-plugin/* .
# @TEST-EXEC: ./configure --zeek-dist=${DIST} && make
# @TEST-EXEC: ZEEK_PLUGIN_ACTIVATE="Demo::Hooks" ZEEK_PLUGIN_PATH=`pwd` zeek -b %INPUT 2>&1 | grep foo >output
# @TEST-EXEC: btest-diff output
@unload base/misc/version
function foo(a: count, b: count, c: count, s: string)
{
print "foo", a, b, c, s;
}
event zeek_init()
{
foo(1, 2, 3, "yo");
}