broker integration: add bifs to inspect/manipulate broker data

i.e. script-layer functions to convert between bro values and broker
values; mostly for use w/ Bro's data store interface (coming soon).
This commit is contained in:
Jon Siwek 2015-01-29 10:42:48 -06:00
parent 0537711fd4
commit d2ea87735a
10 changed files with 1154 additions and 40 deletions

View file

@ -19,4 +19,9 @@ export {
name: string &optional; # nil for invalid event/args.
args: vector of Comm::Data;
};
type Comm::TableItem : record {
key: Comm::Data;
val: Comm::Data;
};
}

View file

@ -123,6 +123,19 @@ void Reporter::ExprRuntimeError(const Expr* expr, const char* fmt, ...)
throw InterpreterException();
}
void Reporter::RuntimeError(const Location* location, const char* fmt, ...)
{
++errors;
PushLocation(location);
va_list ap;
va_start(ap, fmt);
FILE* out = errors_to_stderr ? stderr : 0;
DoLog("runtime error", reporter_error, out, 0, 0, true, true, "", fmt, ap);
va_end(ap);
PopLocation();
throw InterpreterException();
}
void Reporter::InternalError(const char* fmt, ...)
{
va_list ap;

View file

@ -73,6 +73,10 @@ public:
// function will not return but raise an InterpreterException.
void ExprRuntimeError(const Expr* expr, const char* fmt, ...);
// Report a runtime error in evaluating a Bro script expression. This
// function will not return but raise an InterpreterException.
void RuntimeError(const Location* location, const char* fmt, ...);
// Report a traffic weirdness, i.e., an unexpected protocol situation
// that may lead to incorrectly processing a connnection.
void Weird(const char* name); // Raises net_weird().

View file

@ -4,6 +4,10 @@
using namespace std;
OpaqueType* comm::opaque_of_data_type;
OpaqueType* comm::opaque_of_set_iterator;
OpaqueType* comm::opaque_of_table_iterator;
OpaqueType* comm::opaque_of_vector_iterator;
OpaqueType* comm::opaque_of_record_iterator;
static broker::port::protocol to_broker_port_proto(TransportProto tp)
{
@ -20,7 +24,7 @@ static broker::port::protocol to_broker_port_proto(TransportProto tp)
}
}
static TransportProto to_bro_port_proto(broker::port::protocol tp)
TransportProto comm::to_bro_port_proto(broker::port::protocol tp)
{
switch ( tp ) {
case broker::port::protocol::tcp:
@ -70,7 +74,7 @@ struct val_converter {
return nullptr;
}
result_type operator()(const std::string& a)
result_type operator()(std::string& a)
{
switch ( type->Tag() ) {
case TYPE_STRING:
@ -103,7 +107,7 @@ struct val_converter {
}
}
result_type operator()(const broker::address& a)
result_type operator()(broker::address& a)
{
if ( type->Tag() == TYPE_ADDR )
{
@ -114,7 +118,7 @@ struct val_converter {
return nullptr;
}
result_type operator()(const broker::subnet& a)
result_type operator()(broker::subnet& a)
{
if ( type->Tag() == TYPE_SUBNET )
{
@ -125,15 +129,15 @@ struct val_converter {
return nullptr;
}
result_type operator()(const broker::port& a)
result_type operator()(broker::port& a)
{
if ( type->Tag() == TYPE_PORT )
return new PortVal(a.number(), to_bro_port_proto(a.type()));
return new PortVal(a.number(), comm::to_bro_port_proto(a.type()));
return nullptr;
}
result_type operator()(const broker::time_point& a)
result_type operator()(broker::time_point& a)
{
if ( type->Tag() == TYPE_TIME )
return new Val(a.value, TYPE_TIME);
@ -141,7 +145,7 @@ struct val_converter {
return nullptr;
}
result_type operator()(const broker::time_duration& a)
result_type operator()(broker::time_duration& a)
{
if ( type->Tag() == TYPE_INTERVAL )
return new Val(a.value, TYPE_INTERVAL);
@ -149,7 +153,7 @@ struct val_converter {
return nullptr;
}
result_type operator()(const broker::enum_value& a)
result_type operator()(broker::enum_value& a)
{
if ( type->Tag() == TYPE_ENUM )
{
@ -175,12 +179,13 @@ struct val_converter {
for ( auto& item : a )
{
broker::vector composite_key;
auto indices = broker::get<broker::vector>(item);
if ( ! indices )
{
Unref(rval);
return nullptr;
composite_key.emplace_back(move(item));
indices = &composite_key;
}
auto expected_index_types = tt->Indices()->Types();
@ -226,12 +231,13 @@ struct val_converter {
for ( auto& item : a )
{
broker::vector composite_key;
auto indices = broker::get<broker::vector>(item.first);
if ( ! indices )
{
Unref(rval);
return nullptr;
composite_key.emplace_back(move(item.first));
indices = &composite_key;
}
auto expected_index_types = tt->Indices()->Types();
@ -341,7 +347,7 @@ Val* comm::data_to_val(broker::data d, BroType* type)
return broker::visit(val_converter{type}, d);
}
broker::util::optional<broker::data> comm::val_to_data(const Val* v)
broker::util::optional<broker::data> comm::val_to_data(Val* v)
{
switch ( v->Type()->Tag() ) {
case TYPE_BOOL:
@ -388,7 +394,7 @@ broker::util::optional<broker::data> comm::val_to_data(const Val* v)
{
auto enum_type = v->Type()->AsEnumType();
auto enum_name = enum_type->Lookup(v->AsEnum());
return {broker::enum_value(enum_name ? "<unknown enum>" : enum_name)};
return {broker::enum_value(enum_name ? enum_name : "<unknown enum>")};
}
case TYPE_STRING:
{
@ -433,7 +439,9 @@ broker::util::optional<broker::data> comm::val_to_data(const Val* v)
auto entry = table->NextEntry(k, c);
auto vl = table_val->RecoverIndex(k);
iter_guard ig(k, vl);
broker::vector key;
broker::vector composite_key;
composite_key.reserve(vl->Length());
for ( auto k = 0; k < vl->Length(); ++k )
{
@ -442,9 +450,16 @@ broker::util::optional<broker::data> comm::val_to_data(const Val* v)
if ( ! key_part )
return {};
key.emplace_back(move(*key_part));
composite_key.emplace_back(move(*key_part));
}
broker::data key;
if ( composite_key.size() == 1 )
key = move(composite_key[0]);
else
key = move(composite_key);
if ( is_set )
broker::get<broker::set>(rval)->emplace(move(key));
else
@ -521,7 +536,7 @@ broker::util::optional<broker::data> comm::val_to_data(const Val* v)
return {};
}
RecordVal* comm::make_data_val(const Val* v)
RecordVal* comm::make_data_val(Val* v)
{
auto rval = new RecordVal(BifType::Record::Comm::Data);
auto data = val_to_data(v);
@ -531,3 +546,120 @@ RecordVal* comm::make_data_val(const Val* v)
return rval;
}
RecordVal* comm::make_data_val(broker::data d)
{
auto rval = new RecordVal(BifType::Record::Comm::Data);
rval->Assign(0, new DataVal(move(d)));
return rval;
}
struct data_type_getter {
using result_type = EnumVal*;
result_type operator()(bool a)
{
return new EnumVal(BifEnum::Comm::BOOL,
BifType::Enum::Comm::DataType);
}
result_type operator()(uint64_t a)
{
return new EnumVal(BifEnum::Comm::COUNT,
BifType::Enum::Comm::DataType);
}
result_type operator()(int64_t a)
{
return new EnumVal(BifEnum::Comm::INT,
BifType::Enum::Comm::DataType);
}
result_type operator()(double a)
{
return new EnumVal(BifEnum::Comm::DOUBLE,
BifType::Enum::Comm::DataType);
}
result_type operator()(const std::string& a)
{
return new EnumVal(BifEnum::Comm::STRING,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::address& a)
{
return new EnumVal(BifEnum::Comm::ADDR,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::subnet& a)
{
return new EnumVal(BifEnum::Comm::SUBNET,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::port& a)
{
return new EnumVal(BifEnum::Comm::PORT,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::time_point& a)
{
return new EnumVal(BifEnum::Comm::TIME,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::time_duration& a)
{
return new EnumVal(BifEnum::Comm::INTERVAL,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::enum_value& a)
{
return new EnumVal(BifEnum::Comm::ENUM,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::set& a)
{
return new EnumVal(BifEnum::Comm::SET,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::table& a)
{
return new EnumVal(BifEnum::Comm::TABLE,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::vector& a)
{
return new EnumVal(BifEnum::Comm::VECTOR,
BifType::Enum::Comm::DataType);
}
result_type operator()(const broker::record& a)
{
return new EnumVal(BifEnum::Comm::RECORD,
BifType::Enum::Comm::DataType);
}
};
EnumVal* comm::get_data_type(RecordVal* v, Frame* frame)
{
return broker::visit(data_type_getter{}, opaque_field_to_data(v, frame));
}
broker::data& comm::opaque_field_to_data(RecordVal* v, Frame* f)
{
Val* d = v->Lookup(0);
if ( ! d )
reporter->RuntimeError(f->GetCall()->GetLocationInfo(),
"Comm::Data's opaque field is not set");
return static_cast<DataVal*>(d)->data;
}

View file

@ -3,14 +3,27 @@
#include <broker/data.hh>
#include "Val.h"
#include "Reporter.h"
#include "Frame.h"
#include "Expr.h"
namespace comm {
extern OpaqueType* opaque_of_data_type;
extern OpaqueType* opaque_of_set_iterator;
extern OpaqueType* opaque_of_table_iterator;
extern OpaqueType* opaque_of_vector_iterator;
extern OpaqueType* opaque_of_record_iterator;
RecordVal* make_data_val(const Val* v);
TransportProto to_bro_port_proto(broker::port::protocol tp);
broker::util::optional<broker::data> val_to_data(const Val* v);
RecordVal* make_data_val(Val* v);
RecordVal* make_data_val(broker::data d);
EnumVal* get_data_type(RecordVal* v, Frame* frame);
broker::util::optional<broker::data> val_to_data(Val* v);
Val* data_to_val(broker::data d, BroType* type);
@ -21,9 +34,147 @@ public:
: OpaqueVal(comm::opaque_of_data_type), data(std::move(arg_data))
{}
void ValDescribe(ODesc* d) const override
{
d->Add("broker::data{");
d->Add(broker::to_string(data));
d->Add("}");
}
broker::data data;
};
struct type_name_getter {
using result_type = const char*;
result_type operator()(bool a)
{ return "bool"; }
result_type operator()(uint64_t a)
{ return "uint64_t"; }
result_type operator()(int64_t a)
{ return "int64_t"; }
result_type operator()(double a)
{ return "double"; }
result_type operator()(const std::string& a)
{ return "string"; }
result_type operator()(const broker::address& a)
{ return "address"; }
result_type operator()(const broker::subnet& a)
{ return "subnet"; }
result_type operator()(const broker::port& a)
{ return "port"; }
result_type operator()(const broker::time_point& a)
{ return "time"; }
result_type operator()(const broker::time_duration& a)
{ return "interval"; }
result_type operator()(const broker::enum_value& a)
{ return "enum"; }
result_type operator()(const broker::set& a)
{ return "set"; }
result_type operator()(const broker::table& a)
{ return "table"; }
result_type operator()(const broker::vector& a)
{ return "vector"; }
result_type operator()(const broker::record& a)
{ return "record"; }
};
broker::data& opaque_field_to_data(RecordVal* v, Frame* f);
template <typename T>
T& require_data_type(broker::data& d, TypeTag tag, Frame* f)
{
auto ptr = broker::get<T>(d);
if ( ! ptr )
reporter->RuntimeError(f->GetCall()->GetLocationInfo(),
"data is of type '%s' not of type '%s'",
broker::visit(type_name_getter{}, d),
type_name(tag));
return *ptr;
}
template <typename T>
inline T& require_data_type(RecordVal* v, TypeTag tag, Frame* f)
{
return require_data_type<T>(opaque_field_to_data(v, f), tag, f);
}
template <typename T>
inline Val* refine(RecordVal* v, TypeTag tag, Frame* f)
{
return new Val(require_data_type<T>(v, tag, f), tag);
}
// Copying data in to iterator vals is not the fastest approach, but safer...
class SetIterator : public OpaqueVal {
public:
SetIterator(RecordVal* v, TypeTag tag, Frame* f)
: OpaqueVal(comm::opaque_of_set_iterator),
dat(require_data_type<broker::set>(v, TYPE_TABLE, f)),
it(dat.begin())
{}
broker::set dat;
broker::set::iterator it;
};
class TableIterator : public OpaqueVal {
public:
TableIterator(RecordVal* v, TypeTag tag, Frame* f)
: OpaqueVal(comm::opaque_of_table_iterator),
dat(require_data_type<broker::table>(v, TYPE_TABLE, f)),
it(dat.begin())
{}
broker::table dat;
broker::table::iterator it;
};
class VectorIterator : public OpaqueVal {
public:
VectorIterator(RecordVal* v, TypeTag tag, Frame* f)
: OpaqueVal(comm::opaque_of_vector_iterator),
dat(require_data_type<broker::vector>(v, TYPE_VECTOR, f)),
it(dat.begin())
{}
broker::vector dat;
broker::vector::iterator it;
};
class RecordIterator : public OpaqueVal {
public:
RecordIterator(RecordVal* v, TypeTag tag, Frame* f)
: OpaqueVal(comm::opaque_of_record_iterator),
dat(require_data_type<broker::record>(v, TYPE_VECTOR, f)),
it(dat.fields.begin())
{}
broker::record dat;
decltype(broker::record::fields)::iterator it;
};
} // namespace comm
#endif // BRO_COMM_DATA_H

View file

@ -22,7 +22,7 @@ bool comm::Manager::InitPreScript()
return true;
}
static int require_field(const RecordType* rt, const char* name)
static int require_field(RecordType* rt, const char* name)
{
auto rval = rt->FieldOffset(name);
@ -43,6 +43,10 @@ bool comm::Manager::InitPostScript()
log_id_type = internal_type("Log::ID")->AsEnumType();
comm::opaque_of_data_type = new OpaqueType("Comm::Data");
comm::opaque_of_set_iterator = new OpaqueType("Comm::SetIterator");
comm::opaque_of_table_iterator = new OpaqueType("Comm::TableIterator");
comm::opaque_of_vector_iterator = new OpaqueType("Comm::VectorIterator");
comm::opaque_of_record_iterator = new OpaqueType("Comm::RecordIterator");
vector_of_data_type = new VectorType(internal_type("Comm::Data")->Ref());
auto res = broker::init();
@ -110,7 +114,7 @@ bool comm::Manager::Disconnect(const string& addr, uint16_t port)
return rval;
}
bool comm::Manager::Print(string topic, string msg, const Val* flags)
bool comm::Manager::Print(string topic, string msg, Val* flags)
{
endpoint->send(move(topic), broker::message{move(msg)}, GetFlags(flags));
return true;
@ -122,8 +126,7 @@ bool comm::Manager::Event(std::string topic, broker::message msg, int flags)
return true;
}
bool comm::Manager::Log(const EnumVal* stream, const RecordVal* columns,
int flags)
bool comm::Manager::Log(EnumVal* stream, RecordVal* columns, int flags)
{
auto stream_name = stream->Type()->AsEnumType()->Lookup(stream->AsEnum());
@ -150,8 +153,7 @@ bool comm::Manager::Log(const EnumVal* stream, const RecordVal* columns,
return true;
}
bool comm::Manager::Event(std::string topic, const RecordVal* args,
const Val* flags)
bool comm::Manager::Event(std::string topic, RecordVal* args, Val* flags)
{
if ( ! args->Lookup(0) )
return false;
@ -165,7 +167,7 @@ bool comm::Manager::Event(std::string topic, const RecordVal* args,
for ( auto i = 0u; i < vv->Size(); ++i )
{
auto val = vv->Lookup(i)->AsRecordVal()->Lookup(0);
auto data_val = dynamic_cast<DataVal*>(val);
auto data_val = static_cast<DataVal*>(val);
msg.emplace_back(data_val->data);
}
@ -173,7 +175,7 @@ bool comm::Manager::Event(std::string topic, const RecordVal* args,
return true;
}
bool comm::Manager::AutoEvent(string topic, const Val* event, const Val* flags)
bool comm::Manager::AutoEvent(string topic, Val* event, Val* flags)
{
if ( event->Type()->Tag() != TYPE_FUNC )
{
@ -202,7 +204,7 @@ bool comm::Manager::AutoEvent(string topic, const Val* event, const Val* flags)
return true;
}
bool comm::Manager::AutoEventStop(const string& topic, const Val* event)
bool comm::Manager::AutoEventStop(const string& topic, Val* event)
{
if ( event->Type()->Tag() != TYPE_FUNC )
{
@ -232,12 +234,12 @@ bool comm::Manager::AutoEventStop(const string& topic, const Val* event)
return true;
}
RecordVal* comm::Manager::MakeEventArgs(const val_list* args)
RecordVal* comm::Manager::MakeEventArgs(val_list* args)
{
auto rval = new RecordVal(BifType::Record::Comm::EventArgs);
auto arg_vec = new VectorVal(vector_of_data_type);
rval->Assign(1, arg_vec);
const Func* func;
Func* func;
for ( auto i = 0u; i < args->length(); ++i )
{
@ -347,7 +349,7 @@ bool comm::Manager::UnsubscribeToLogs(const string& topic_prefix)
return log_subscriptions.erase(topic_prefix);
}
int comm::Manager::GetFlags(const Val* flags)
int comm::Manager::GetFlags(Val* flags)
{
auto r = flags->AsRecordVal();
int rval = 0;

View file

@ -31,18 +31,18 @@ public:
bool Disconnect(const std::string& addr, uint16_t port);
bool Print(std::string topic, std::string msg, const Val* flags);
bool Print(std::string topic, std::string msg, Val* flags);
bool Event(std::string topic, broker::message msg, int flags);
bool Event(std::string topic, const RecordVal* args, const Val* flags);
bool Event(std::string topic, RecordVal* args, Val* flags);
bool Log(const EnumVal* stream_id, const RecordVal* columns, int flags);
bool Log(EnumVal* stream_id, RecordVal* columns, int flags);
bool AutoEvent(std::string topic, const Val* event, const Val* flags);
bool AutoEvent(std::string topic, Val* event, Val* flags);
bool AutoEventStop(const std::string& topic, const Val* event);
bool AutoEventStop(const std::string& topic, Val* event);
RecordVal* MakeEventArgs(const val_list* args);
RecordVal* MakeEventArgs(val_list* args);
bool SubscribeToPrints(std::string topic_prefix);
@ -56,7 +56,7 @@ public:
bool UnsubscribeToLogs(const std::string& topic_prefix);
static int GetFlags(const Val* flags);
static int GetFlags(Val* flags);
private:
@ -82,7 +82,6 @@ private:
static int send_flags_self_idx;
static int send_flags_peers_idx;
static int send_flags_unsolicited_idx;
};
} // namespace comm

View file

@ -7,17 +7,507 @@
module Comm;
enum DataType %{
BOOL,
INT,
COUNT,
DOUBLE,
STRING,
ADDR,
SUBNET,
PORT,
TIME,
INTERVAL,
ENUM,
SET,
TABLE,
VECTOR,
RECORD,
%}
type Comm::SendFlags: record;
type Comm::Data: record;
type Comm::EventArgs: record;
type Comm::TableItem: record;
function Comm::data%(d: any%): Comm::Data
%{
return comm::make_data_val(d);
%}
function Comm::data_type%(d: Comm::Data%): Comm::DataType
%{
return comm::get_data_type(d->AsRecordVal(), frame);
%}
function Comm::refine_to_bool%(d: Comm::Data%): bool
%{
return comm::refine<bool>(d->AsRecordVal(), TYPE_BOOL, frame);
%}
function Comm::refine_to_int%(d: Comm::Data%): int
%{
return comm::refine<int64_t>(d->AsRecordVal(), TYPE_INT, frame);
%}
function Comm::refine_to_count%(d: Comm::Data%): count
%{
return comm::refine<uint64_t>(d->AsRecordVal(), TYPE_COUNT, frame);
%}
function Comm::refine_to_double%(d: Comm::Data%): double
%{
return comm::refine<double>(d->AsRecordVal(), TYPE_DOUBLE, frame);
%}
function Comm::refine_to_string%(d: Comm::Data%): string
%{
return new StringVal(comm::require_data_type<std::string>(d->AsRecordVal(),
TYPE_STRING,
frame));
%}
function Comm::refine_to_addr%(d: Comm::Data%): addr
%{
auto& a = comm::require_data_type<broker::address>(d->AsRecordVal(),
TYPE_ADDR, frame);
auto bits = reinterpret_cast<const in6_addr*>(&a.bytes());
return new AddrVal(IPAddr(*bits));
%}
function Comm::refine_to_subnet%(d: Comm::Data%): subnet
%{
auto& a = comm::require_data_type<broker::subnet>(d->AsRecordVal(),
TYPE_SUBNET, frame);
auto bits = reinterpret_cast<const in6_addr*>(&a.network().bytes());
return new SubNetVal(IPPrefix(IPAddr(*bits), a.length()));
%}
function Comm::refine_to_port%(d: Comm::Data%): port
%{
auto& a = comm::require_data_type<broker::port>(d->AsRecordVal(),
TYPE_SUBNET, frame);
return new PortVal(a.number(), comm::to_bro_port_proto(a.type()));
%}
function Comm::refine_to_time%(d: Comm::Data%): time
%{
auto v = comm::require_data_type<broker::time_point>(d->AsRecordVal(),
TYPE_TIME, frame).value;
return new Val(v, TYPE_TIME);
%}
function Comm::refine_to_interval%(d: Comm::Data%): interval
%{
auto v = comm::require_data_type<broker::time_duration>(d->AsRecordVal(),
TYPE_TIME, frame).value;
return new Val(v, TYPE_INTERVAL);
%}
function Comm::refine_to_enum_name%(d: Comm::Data%): string
%{
auto& v = comm::require_data_type<broker::enum_value>(d->AsRecordVal(),
TYPE_ENUM, frame).name;
return new StringVal(v);
%}
function Comm::set_create%(%): Comm::Data
%{
return comm::make_data_val(broker::set());
%}
function Comm::set_clear%(s: Comm::Data%): bool
%{
auto& v = comm::require_data_type<broker::set>(s->AsRecordVal(), TYPE_TABLE,
frame);
v.clear();
return new Val(true, TYPE_BOOL);
%}
function Comm::set_size%(s: Comm::Data%): count
%{
auto& v = comm::require_data_type<broker::set>(s->AsRecordVal(), TYPE_TABLE,
frame);
return new Val(static_cast<uint64_t>(v.size()), TYPE_COUNT);
%}
function Comm::set_contains%(s: Comm::Data, key: Comm::Data%): bool
%{
auto& v = comm::require_data_type<broker::set>(s->AsRecordVal(), TYPE_TABLE,
frame);
auto& k = comm::opaque_field_to_data(key->AsRecordVal(), frame);
return new Val(v.find(k) != v.end(), TYPE_BOOL);
%}
function Comm::set_insert%(s: Comm::Data, key: Comm::Data%): bool
%{
auto& v = comm::require_data_type<broker::set>(s->AsRecordVal(), TYPE_TABLE,
frame);
auto& k = comm::opaque_field_to_data(key->AsRecordVal(), frame);
return new Val(v.insert(k).second, TYPE_BOOL);
%}
function Comm::set_remove%(s: Comm::Data, key: Comm::Data%): bool
%{
auto& v = comm::require_data_type<broker::set>(s->AsRecordVal(), TYPE_TABLE,
frame);
auto& k = comm::opaque_field_to_data(key->AsRecordVal(), frame);
return new Val(v.erase(k) > 0, TYPE_BOOL);
%}
function Comm::set_iterator%(s: Comm::Data%): opaque of Comm::SetIterator
%{
return new comm::SetIterator(s->AsRecordVal(), TYPE_TABLE, frame);
%}
function Comm::set_iterator_last%(it: opaque of Comm::SetIterator%): bool
%{
auto set_it = static_cast<comm::SetIterator*>(it);
return new Val(set_it->it == set_it->dat.end(), TYPE_BOOL);
%}
function Comm::set_iterator_next%(it: opaque of Comm::SetIterator%): bool
%{
auto set_it = static_cast<comm::SetIterator*>(it);
if ( set_it->it == set_it->dat.end() )
return new Val(false, TYPE_BOOL);
++set_it->it;
return new Val(set_it->it != set_it->dat.end(), TYPE_BOOL);
%}
function Comm::set_iterator_value%(it: opaque of Comm::SetIterator%): Comm::Data
%{
auto set_it = static_cast<comm::SetIterator*>(it);
auto rval = new RecordVal(BifType::Record::Comm::Data);
if ( set_it->it == set_it->dat.end() )
{
reporter->PushLocation(frame->GetCall()->GetLocationInfo());
reporter->Warning("attempt to retrieve value of invalid set iterator");
reporter->PopLocation();
return rval;
}
rval->Assign(0, new comm::DataVal(*set_it->it));
return rval;
%}
function Comm::table_create%(%): Comm::Data
%{
return comm::make_data_val(broker::table());
%}
function Comm::table_clear%(t: Comm::Data%): bool
%{
auto& v = comm::require_data_type<broker::table>(t->AsRecordVal(),
TYPE_TABLE, frame);
v.clear();
return new Val(true, TYPE_BOOL);
%}
function Comm::table_size%(t: Comm::Data%): count
%{
auto& v = comm::require_data_type<broker::table>(t->AsRecordVal(),
TYPE_TABLE, frame);
return new Val(static_cast<uint64_t>(v.size()), TYPE_COUNT);
%}
function Comm::table_contains%(t: Comm::Data, key: Comm::Data%): bool
%{
auto& v = comm::require_data_type<broker::table>(t->AsRecordVal(),
TYPE_TABLE, frame);
auto& k = comm::opaque_field_to_data(key->AsRecordVal(), frame);
return new Val(v.find(k) != v.end(), TYPE_BOOL);
%}
function Comm::table_insert%(t: Comm::Data, key: Comm::Data, val: Comm::Data%): Comm::Data
%{
auto& table = comm::require_data_type<broker::table>(t->AsRecordVal(),
TYPE_TABLE, frame);
auto& k = comm::opaque_field_to_data(key->AsRecordVal(), frame);
auto& v = comm::opaque_field_to_data(val->AsRecordVal(), frame);
try
{
auto& prev = table.at(k);
auto rval = comm::make_data_val(move(prev));
prev = v;
return rval;
}
catch (const std::out_of_range&)
{
table[k] = v;
return new RecordVal(BifType::Record::Comm::Data);
}
%}
function Comm::table_remove%(t: Comm::Data, key: Comm::Data%): Comm::Data
%{
auto& table = comm::require_data_type<broker::table>(t->AsRecordVal(),
TYPE_TABLE, frame);
auto& k = comm::opaque_field_to_data(key->AsRecordVal(), frame);
auto it = table.find(k);
if ( it == table.end() )
return new RecordVal(BifType::Record::Comm::Data);
else
{
auto rval = comm::make_data_val(move(it->second));
table.erase(it);
return rval;
}
%}
function Comm::table_lookup%(t: Comm::Data, key: Comm::Data%): Comm::Data
%{
auto& table = comm::require_data_type<broker::table>(t->AsRecordVal(),
TYPE_TABLE, frame);
auto& k = comm::opaque_field_to_data(key->AsRecordVal(), frame);
auto it = table.find(k);
if ( it == table.end() )
return new RecordVal(BifType::Record::Comm::Data);
else
return comm::make_data_val(it->second);
%}
function Comm::table_iterator%(t: Comm::Data%): opaque of Comm::TableIterator
%{
return new comm::TableIterator(t->AsRecordVal(), TYPE_TABLE, frame);
%}
function Comm::table_iterator_last%(it: opaque of Comm::TableIterator%): bool
%{
auto ti = static_cast<comm::TableIterator*>(it);
return new Val(ti->it == ti->dat.end(), TYPE_BOOL);
%}
function Comm::table_iterator_next%(it: opaque of Comm::TableIterator%): bool
%{
auto ti = static_cast<comm::TableIterator*>(it);
if ( ti->it == ti->dat.end() )
return new Val(false, TYPE_BOOL);
++ti->it;
return new Val(ti->it != ti->dat.end(), TYPE_BOOL);
%}
function Comm::table_iterator_value%(it: opaque of Comm::TableIterator%): Comm::TableItem
%{
auto ti = static_cast<comm::TableIterator*>(it);
auto rval = new RecordVal(BifType::Record::Comm::TableItem);
auto key_val = new RecordVal(BifType::Record::Comm::Data);
auto val_val = new RecordVal(BifType::Record::Comm::Data);
rval->Assign(0, key_val);
rval->Assign(1, val_val);
if ( ti->it == ti->dat.end() )
{
reporter->PushLocation(frame->GetCall()->GetLocationInfo());
reporter->Warning("attempt to retrieve value of invalid table iterator");
reporter->PopLocation();
return rval;
}
key_val->Assign(0, new comm::DataVal(ti->it->first));
val_val->Assign(0, new comm::DataVal(ti->it->second));
return rval;
%}
function Comm::vector_create%(%): Comm::Data
%{
return comm::make_data_val(broker::vector());
%}
function Comm::vector_clear%(v: Comm::Data%): bool
%{
auto& vec = comm::require_data_type<broker::vector>(v->AsRecordVal(),
TYPE_VECTOR, frame);
vec.clear();
return new Val(true, TYPE_BOOL);
%}
function Comm::vector_size%(v: Comm::Data%): count
%{
auto& vec = comm::require_data_type<broker::vector>(v->AsRecordVal(),
TYPE_VECTOR, frame);
return new Val(static_cast<uint64_t>(vec.size()), TYPE_COUNT);
%}
function Comm::vector_insert%(v: Comm::Data, d: Comm::Data, idx: count%): bool
%{
auto& vec = comm::require_data_type<broker::vector>(v->AsRecordVal(),
TYPE_VECTOR, frame);
auto& item = comm::opaque_field_to_data(d->AsRecordVal(), frame);
idx = min(idx, static_cast<uint64_t>(vec.size()));
vec.insert(vec.begin() + idx, item);
return new Val(true, TYPE_BOOL);
%}
function Comm::vector_replace%(v: Comm::Data, d: Comm::Data, idx: count%): Comm::Data
%{
auto& vec = comm::require_data_type<broker::vector>(v->AsRecordVal(),
TYPE_VECTOR, frame);
auto& item = comm::opaque_field_to_data(d->AsRecordVal(), frame);
if ( idx >= vec.size() )
return new RecordVal(BifType::Record::Comm::Data);
auto rval = comm::make_data_val(move(vec[idx]));
vec[idx] = item;
return rval;
%}
function Comm::vector_remove%(v: Comm::Data, idx: count%): Comm::Data
%{
auto& vec = comm::require_data_type<broker::vector>(v->AsRecordVal(),
TYPE_VECTOR, frame);
if ( idx >= vec.size() )
return new RecordVal(BifType::Record::Comm::Data);
auto rval = comm::make_data_val(move(vec[idx]));
vec.erase(vec.begin() + idx);
return rval;
%}
function Comm::vector_lookup%(v: Comm::Data, idx: count%): Comm::Data
%{
auto& vec = comm::require_data_type<broker::vector>(v->AsRecordVal(),
TYPE_VECTOR, frame);
if ( idx >= vec.size() )
return new RecordVal(BifType::Record::Comm::Data);
return comm::make_data_val(vec[idx]);
%}
function Comm::vector_iterator%(v: Comm::Data%): opaque of Comm::VectorIterator
%{
return new comm::VectorIterator(v->AsRecordVal(), TYPE_VECTOR, frame);
%}
function Comm::vector_iterator_last%(it: opaque of Comm::VectorIterator%): bool
%{
auto vi = static_cast<comm::VectorIterator*>(it);
return new Val(vi->it == vi->dat.end(), TYPE_BOOL);
%}
function Comm::vector_iterator_next%(it: opaque of Comm::VectorIterator%): bool
%{
auto vi = static_cast<comm::VectorIterator*>(it);
if ( vi->it == vi->dat.end() )
return new Val(false, TYPE_BOOL);
++vi->it;
return new Val(vi->it != vi->dat.end(), TYPE_BOOL);
%}
function Comm::vector_iterator_value%(it: opaque of Comm::VectorIterator%): Comm::Data
%{
auto vi = static_cast<comm::VectorIterator*>(it);
auto rval = new RecordVal(BifType::Record::Comm::Data);
if ( vi->it == vi->dat.end() )
{
reporter->PushLocation(frame->GetCall()->GetLocationInfo());
reporter->Warning("attempt to retrieve value of invalid table iterator");
reporter->PopLocation();
return rval;
}
rval->Assign(0, new comm::DataVal(*vi->it));
return rval;
%}
function Comm::record_create%(sz: count%): Comm::Data
%{
return comm::make_data_val(broker::record(std::vector<broker::record::field>(sz)));
%}
function Comm::record_size%(r: Comm::Data%): count
%{
auto& v = comm::require_data_type<broker::record>(r->AsRecordVal(),
TYPE_RECORD, frame);
return new Val(static_cast<uint64_t>(v.fields.size()), TYPE_COUNT);
%}
function Comm::record_assign%(r: Comm::Data, d: Comm::Data, idx: count%): bool
%{
auto& v = comm::require_data_type<broker::record>(r->AsRecordVal(),
TYPE_RECORD, frame);
auto& item = comm::opaque_field_to_data(d->AsRecordVal(), frame);
if ( idx >= v.fields.size() )
return new Val(false, TYPE_BOOL);
v.fields[idx] = item;
return new Val(true, TYPE_BOOL);
%}
function Comm::record_lookup%(r: Comm::Data, idx: count%): Comm::Data
%{
auto& v = comm::require_data_type<broker::record>(r->AsRecordVal(),
TYPE_RECORD, frame);
if ( idx >= v.size() )
return new RecordVal(BifType::Record::Comm::Data);
if ( ! v.fields[idx] )
return new RecordVal(BifType::Record::Comm::Data);
return comm::make_data_val(*v.fields[idx]);
%}
function Comm::record_iterator%(r: Comm::Data%): opaque of Comm::RecordIterator
%{
return new comm::RecordIterator(r->AsRecordVal(), TYPE_RECORD, frame);
%}
function Comm::record_iterator_last%(it: opaque of Comm::RecordIterator%): bool
%{
auto ri = static_cast<comm::RecordIterator*>(it);
return new Val(ri->it == ri->dat.fields.end(), TYPE_BOOL);
%}
function Comm::record_iterator_next%(it: opaque of Comm::RecordIterator%): bool
%{
auto ri = static_cast<comm::RecordIterator*>(it);
if ( ri->it == ri->dat.fields.end() )
return new Val(false, TYPE_BOOL);
++ri->it;
return new Val(ri->it != ri->dat.fields.end(), TYPE_BOOL);
%}
function Comm::record_iterator_value%(it: opaque of Comm::RecordIterator%): Comm::Data
%{
auto ri = static_cast<comm::RecordIterator*>(it);
auto rval = new RecordVal(BifType::Record::Comm::Data);
if ( ri->it == ri->dat.fields.end() )
{
reporter->PushLocation(frame->GetCall()->GetLocationInfo());
reporter->Warning("attempt to retrieve value of invalid record iterator");
reporter->PopLocation();
return rval;
}
if ( ! *ri->it )
return rval; // field isn't set
rval->Assign(0, new comm::DataVal(**ri->it));
return rval;
%}
event Comm::remote_connection_established%(peer_address: string,
peer_port: port,
peer_name: string%);

View file

@ -0,0 +1,99 @@
Comm::BOOL
Comm::INT
Comm::COUNT
Comm::DOUBLE
Comm::STRING
Comm::ADDR
Comm::SUBNET
Comm::PORT
Comm::TIME
Comm::INTERVAL
Comm::ENUM
Comm::SET
Comm::TABLE
Comm::VECTOR
Comm::RECORD
***************************
T
F
1
0
-1
1
0
1.1
-11.1
hello
1.2.3.4
192.168.0.0/16
22/tcp
42.0
180.0
Comm::BOOL
***************************
{
two,
one,
three
}
0
T
1
T
F
T
2
T
1
F
{
bye
}
0
***************************
{
[two] = 2,
[one] = 1,
[three] = 3
}
0
[d=<uninitialized>]
1
T
42
F
[d=<uninitialized>]
2
[d=broker::data{7}]
2
37
[d=broker::data{42}]
1
***************************
[zero, one, two]
0
T
T
T
T
[hi, salutations, hello, greetings]
4
[d=broker::data{hello}]
[d=broker::data{bah}]
[d=broker::data{hi}]
[hi, salutations, bah, greetings]
[d=broker::data{bah}]
[hi, salutations, greetings]
3
***************************
[a=<uninitialized>, b=bee, c=1]
[a=test, b=bee, c=1]
[a=test, b=testagain, c=1]
3
T
T
T
[d=broker::data{hi}]
[d=broker::data{hello}]
[d=broker::data{37}]
3

219
testing/btest/comm/data.bro Normal file
View file

@ -0,0 +1,219 @@
# @TEST-EXEC: bro -b %INPUT >out
# @TEST-EXEC: btest-diff out
type bro_set: set[string];
type bro_table: table[string] of count;
type bro_vector: vector of string;
type bro_record : record {
a: string &optional;
b: string &default = "bee";
c: count;
};
function comm_record_to_bro_record_recurse(it: opaque of Comm::RecordIterator,
rval: bro_record,
idx: count): bro_record
{
if ( Comm::record_iterator_last(it) )
return rval;
local field_value = Comm::record_iterator_value(it);
if ( field_value?$d )
switch ( idx ) {
case 0:
rval$a = Comm::refine_to_string(field_value);
break;
case 1:
rval$b = Comm::refine_to_string(field_value);
break;
case 2:
rval$c = Comm::refine_to_count(field_value);
break;
};
++idx;
Comm::record_iterator_next(it);
return comm_record_to_bro_record_recurse(it, rval, idx);
}
function comm_record_to_bro_record(d: Comm::Data): bro_record
{
return comm_record_to_bro_record_recurse(Comm::record_iterator(d),
bro_record($c = 0), 0);
}
function
comm_set_to_bro_set_recurse(it: opaque of Comm::SetIterator,
rval: bro_set): bro_set
{
if ( Comm::set_iterator_last(it) )
return rval;
add rval[Comm::refine_to_string(Comm::set_iterator_value(it))];
Comm::set_iterator_next(it);
return comm_set_to_bro_set_recurse(it, rval);
}
function comm_set_to_bro_set(d: Comm::Data): bro_set
{
return comm_set_to_bro_set_recurse(Comm::set_iterator(d), bro_set());
}
function
comm_table_to_bro_table_recurse(it: opaque of Comm::TableIterator,
rval: bro_table): bro_table
{
if ( Comm::table_iterator_last(it) )
return rval;
local item = Comm::table_iterator_value(it);
rval[Comm::refine_to_string(item$key)] = Comm::refine_to_count(item$val);
Comm::table_iterator_next(it);
return comm_table_to_bro_table_recurse(it, rval);
}
function comm_table_to_bro_table(d: Comm::Data): bro_table
{
return comm_table_to_bro_table_recurse(Comm::table_iterator(d),
bro_table());
}
function comm_vector_to_bro_vector_recurse(it: opaque of Comm::VectorIterator,
rval: bro_vector): bro_vector
{
if ( Comm::vector_iterator_last(it) )
return rval;
rval[|rval|] = Comm::refine_to_string(Comm::vector_iterator_value(it));
Comm::vector_iterator_next(it);
return comm_vector_to_bro_vector_recurse(it, rval);
}
function comm_vector_to_bro_vector(d: Comm::Data): bro_vector
{
return comm_vector_to_bro_vector_recurse(Comm::vector_iterator(d),
bro_vector());
}
event bro_init()
{
print Comm::data_type(Comm::data(T));
print Comm::data_type(Comm::data(+1));
print Comm::data_type(Comm::data(1));
print Comm::data_type(Comm::data(1.1));
print Comm::data_type(Comm::data("1 (how creative)"));
print Comm::data_type(Comm::data(1.1.1.1));
print Comm::data_type(Comm::data(1.1.1.1/1));
print Comm::data_type(Comm::data(1/udp));
print Comm::data_type(Comm::data(double_to_time(1)));
print Comm::data_type(Comm::data(1sec));
print Comm::data_type(Comm::data(Comm::BOOL));
local s: bro_set = bro_set("one", "two", "three");
local t: bro_table = bro_table(["one"] = 1, ["two"] = 2, ["three"] = 3);
local v: bro_vector = bro_vector("zero", "one", "two");
local r: bro_record = bro_record($c = 1);
print Comm::data_type(Comm::data(s));
print Comm::data_type(Comm::data(t));
print Comm::data_type(Comm::data(v));
print Comm::data_type(Comm::data(r));
print "***************************";
print Comm::refine_to_bool(Comm::data(T));
print Comm::refine_to_bool(Comm::data(F));
print Comm::refine_to_int(Comm::data(+1));
print Comm::refine_to_int(Comm::data(+0));
print Comm::refine_to_int(Comm::data(-1));
print Comm::refine_to_count(Comm::data(1));
print Comm::refine_to_count(Comm::data(0));
print Comm::refine_to_double(Comm::data(1.1));
print Comm::refine_to_double(Comm::data(-11.1));
print Comm::refine_to_string(Comm::data("hello"));
print Comm::refine_to_addr(Comm::data(1.2.3.4));
print Comm::refine_to_subnet(Comm::data(192.168.1.1/16));
print Comm::refine_to_port(Comm::data(22/tcp));
print Comm::refine_to_time(Comm::data(double_to_time(42)));
print Comm::refine_to_interval(Comm::data(3min));
print Comm::refine_to_enum_name(Comm::data(Comm::BOOL));
print "***************************";
local cs = Comm::data(s);
print comm_set_to_bro_set(cs);
cs = Comm::set_create();
print Comm::set_size(cs);
print Comm::set_insert(cs, Comm::data("hi"));
print Comm::set_size(cs);
print Comm::set_contains(cs, Comm::data("hi"));
print Comm::set_contains(cs, Comm::data("bye"));
print Comm::set_insert(cs, Comm::data("bye"));
print Comm::set_size(cs);
print Comm::set_remove(cs, Comm::data("hi"));
print Comm::set_size(cs);
print Comm::set_remove(cs, Comm::data("hi"));
print comm_set_to_bro_set(cs);
Comm::set_clear(cs);
print Comm::set_size(cs);
print "***************************";
local ct = Comm::data(t);
print comm_table_to_bro_table(ct);
ct = Comm::table_create();
print Comm::table_size(ct);
print Comm::table_insert(ct, Comm::data("hi"), Comm::data(42));
print Comm::table_size(ct);
print Comm::table_contains(ct, Comm::data("hi"));
print Comm::refine_to_count(Comm::table_lookup(ct, Comm::data("hi")));
print Comm::table_contains(ct, Comm::data("bye"));
print Comm::table_insert(ct, Comm::data("bye"), Comm::data(7));
print Comm::table_size(ct);
print Comm::table_insert(ct, Comm::data("bye"), Comm::data(37));
print Comm::table_size(ct);
print Comm::refine_to_count(Comm::table_lookup(ct, Comm::data("bye")));
print Comm::table_remove(ct, Comm::data("hi"));
print Comm::table_size(ct);
print "***************************";
local cv = Comm::data(v);
print comm_vector_to_bro_vector(cv);
cv = Comm::vector_create();
print Comm::vector_size(cv);
print Comm::vector_insert(cv, Comm::data("hi"), 0);
print Comm::vector_insert(cv, Comm::data("hello"), 1);
print Comm::vector_insert(cv, Comm::data("greetings"), 2);
print Comm::vector_insert(cv, Comm::data("salutations"), 1);
print comm_vector_to_bro_vector(cv);
print Comm::vector_size(cv);
print Comm::vector_replace(cv, Comm::data("bah"), 2);
print Comm::vector_lookup(cv, 2);
print Comm::vector_lookup(cv, 0);
print comm_vector_to_bro_vector(cv);
print Comm::vector_remove(cv, 2);
print comm_vector_to_bro_vector(cv);
print Comm::vector_size(cv);
print "***************************";
local cr = Comm::data(r);
print comm_record_to_bro_record(cr);
r$a = "test";
cr = Comm::data(r);
print comm_record_to_bro_record(cr);
r$b = "testagain";
cr = Comm::data(r);
print comm_record_to_bro_record(cr);
cr = Comm::record_create(3);
print Comm::record_size(cr);
print Comm::record_assign(cr, Comm::data("hi"), 0);
print Comm::record_assign(cr, Comm::data("hello"), 1);
print Comm::record_assign(cr, Comm::data(37), 2);
print Comm::record_lookup(cr, 0);
print Comm::record_lookup(cr, 1);
print Comm::record_lookup(cr, 2);
print Comm::record_size(cr);
}