Teach Option::set to unwrap Broker::Data values

This commit is contained in:
Jon Siwek 2018-05-31 12:45:44 -05:00
parent 5bb72d2972
commit 3679b0d963
5 changed files with 81 additions and 29 deletions

View file

@ -5,6 +5,36 @@ module Option;
%%{ %%{
#include "NetVar.h" #include "NetVar.h"
#include "broker/Data.h"
static bool call_option_handlers_and_set_value(StringVal* name, ID* i, Val* val,
StringVal* location)
{
val->Ref();
if ( i->HasOptionHandlers() )
{
for ( auto handler_function : i->GetOptionHandlers() )
{
val_list vl(2);
vl.append(name->Ref());
vl.append(val);
if ( handler_function->FType()->AsFuncType()->ArgTypes()->Types()->length() == 3 )
vl.append(location->Ref());
val = handler_function->Call(&vl); // consumed by next call.
if ( ! val )
{
// Someone messed up, don't change value and just return
return false;
}
}
}
// clone to prevent changes
i->SetVal(val->Clone());
Unref(val); // Either ref'd once or function call result.
return true;
}
%%} %%}
## Set an option to a new value. This change will also cause the option change ## Set an option to a new value. This change will also cause the option change
@ -41,36 +71,32 @@ function Option::set%(ID: string, val: any, location: string &default=""%): bool
return new Val(0, TYPE_BOOL); return new Val(0, TYPE_BOOL);
} }
if ( same_type(val->Type(), bro_broker::DataVal::ScriptDataType()) )
{
auto dv = static_cast<bro_broker::DataVal*>(val->AsRecordVal()->Lookup(0));
auto val_from_data = dv->castTo(i->Type());
if ( ! val_from_data )
{
builtin_error(fmt("Incompatible type for set of ID '%s': got broker data '%s', need '%s'",
ID->CheckString(), dv->data.get_type_name(), type_name(i->Type()->Tag())));
return new Val(0, TYPE_BOOL);
}
auto rval = call_option_handlers_and_set_value(ID, i, val_from_data, location);
Unref(val_from_data);
return new Val(rval, TYPE_BOOL);
}
if ( ! same_type(i->Type(), val->Type()) ) if ( ! same_type(i->Type(), val->Type()) )
{ {
builtin_error(fmt("Incompatible type for set of ID '%s': got '%s', need '%s'", builtin_error(fmt("Incompatible type for set of ID '%s': got '%s', need '%s'",
ID->CheckString(), type_name(val->Type()->Tag()), type_name(i->Type()->Tag()))); ID->CheckString(), type_name(val->Type()->Tag()), type_name(i->Type()->Tag())));
}
val->Ref();
if ( i->HasOptionHandlers() )
{
for ( auto handler_function : i->GetOptionHandlers() )
{
val_list vl(2);
vl.append(ID->Ref());
vl.append(val);
if ( handler_function->FType()->AsFuncType()->ArgTypes()->Types()->length() == 3 )
vl.append(location->Ref());
val = handler_function->Call(&vl); // consumed by next call.
if ( ! val )
{
// Someone messed up, don't change value and just return
return new Val(0, TYPE_BOOL); return new Val(0, TYPE_BOOL);
} }
}
}
// clone to prevent changes auto rval = call_option_handlers_and_set_value(ID, i, val, location);
i->SetVal(val->Clone()); return new Val(rval, TYPE_BOOL);
Unref(val); // Either ref'd once or function call result.
return new Val(1, TYPE_BOOL);
%} %}
## Set a change handler for an option. The change handler will be ## Set a change handler for an option. The change handler will be

View file

@ -0,0 +1,2 @@
option changed, testport, 44/tcp,
option changed, teststring, b, comment

View file

@ -0,0 +1,4 @@
option changed, testport, 44/tcp,
option changed, teststring, b, comment
option changed, testport, 44/tcp,
option changed, teststring, b, comment

View file

@ -0,0 +1,2 @@
option changed, testport, 44/tcp,
option changed, teststring, b, comment

View file

@ -2,7 +2,10 @@
# @TEST-EXEC: sleep 1 # @TEST-EXEC: sleep 1
# @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT # @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT
# @TEST-EXEC: btest-bg-run worker-2 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro %INPUT # @TEST-EXEC: btest-bg-run worker-2 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro %INPUT
# @TEST-EXEC: btest-bg-wait 10 # @TEST-EXEC: btest-bg-wait 15
# @TEST-EXEC: btest-diff manager-1/.stdout
# @TEST-EXEC: btest-diff worker-1/.stdout
# @TEST-EXEC: btest-diff worker-2/.stdout
@load base/frameworks/config @load base/frameworks/config
@ -24,10 +27,6 @@ export {
global n = 0; global n = 0;
event bro_init() &priority=5
{
}
event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string) event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string)
{ {
terminate(); terminate();
@ -46,8 +45,27 @@ event ready_for_data()
Config::set_value("testport", 44/tcp); Config::set_value("testport", 44/tcp);
Config::set_value("teststring", "b", "comment"); Config::set_value("teststring", "b", "comment");
} }
@endif @endif
event die()
{
terminate();
}
function option_changed(ID: string, new_value: any, location: string): any
{
print "option changed", ID, new_value, location;
schedule 5sec { die() };
return new_value;
}
event bro_init() &priority=5
{
Option::set_change_handler("testport", option_changed, -100);
Option::set_change_handler("teststring", option_changed, -100);
}
@if ( Cluster::local_node_type() == Cluster::MANAGER ) @if ( Cluster::local_node_type() == Cluster::MANAGER )
global peer_count = 0; global peer_count = 0;