diff --git a/scripts/base/frameworks/comm/main.bro b/scripts/base/frameworks/comm/main.bro index efe3069a1c..974e5e43af 100644 --- a/scripts/base/frameworks/comm/main.bro +++ b/scripts/base/frameworks/comm/main.bro @@ -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; + }; } diff --git a/src/Reporter.cc b/src/Reporter.cc index 9002633b10..cd1aa09d4c 100644 --- a/src/Reporter.cc +++ b/src/Reporter.cc @@ -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; diff --git a/src/Reporter.h b/src/Reporter.h index e477ad8934..52bcd7d02a 100644 --- a/src/Reporter.h +++ b/src/Reporter.h @@ -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(). diff --git a/src/comm/Data.cc b/src/comm/Data.cc index b279b97529..f32bedd885 100644 --- a/src/comm/Data.cc +++ b/src/comm/Data.cc @@ -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(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(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 comm::val_to_data(const Val* v) +broker::util::optional comm::val_to_data(Val* v) { switch ( v->Type()->Tag() ) { case TYPE_BOOL: @@ -388,7 +394,7 @@ broker::util::optional 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 ? "" : enum_name)}; + return {broker::enum_value(enum_name ? enum_name : "")}; } case TYPE_STRING: { @@ -433,7 +439,9 @@ broker::util::optional 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 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(rval)->emplace(move(key)); else @@ -521,7 +536,7 @@ broker::util::optional 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(d)->data; + } diff --git a/src/comm/Data.h b/src/comm/Data.h index e3197b61da..c720dcda71 100644 --- a/src/comm/Data.h +++ b/src/comm/Data.h @@ -3,14 +3,27 @@ #include #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 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 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 +T& require_data_type(broker::data& d, TypeTag tag, Frame* f) + { + auto ptr = broker::get(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 +inline T& require_data_type(RecordVal* v, TypeTag tag, Frame* f) + { + return require_data_type(opaque_field_to_data(v, f), tag, f); + } + +template +inline Val* refine(RecordVal* v, TypeTag tag, Frame* f) + { + return new Val(require_data_type(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(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(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(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(v, TYPE_VECTOR, f)), + it(dat.fields.begin()) + {} + + broker::record dat; + decltype(broker::record::fields)::iterator it; +}; + } // namespace comm #endif // BRO_COMM_DATA_H diff --git a/src/comm/Manager.cc b/src/comm/Manager.cc index bc0bc3f8a8..e64c74c377 100644 --- a/src/comm/Manager.cc +++ b/src/comm/Manager.cc @@ -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(val); + auto data_val = static_cast(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; diff --git a/src/comm/Manager.h b/src/comm/Manager.h index 5e3ec350b8..44f5eb0f2b 100644 --- a/src/comm/Manager.h +++ b/src/comm/Manager.h @@ -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 diff --git a/src/comm/comm.bif b/src/comm/comm.bif index ebe206d266..b2ce0fb415 100644 --- a/src/comm/comm.bif +++ b/src/comm/comm.bif @@ -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(d->AsRecordVal(), TYPE_BOOL, frame); + %} + +function Comm::refine_to_int%(d: Comm::Data%): int + %{ + return comm::refine(d->AsRecordVal(), TYPE_INT, frame); + %} + +function Comm::refine_to_count%(d: Comm::Data%): count + %{ + return comm::refine(d->AsRecordVal(), TYPE_COUNT, frame); + %} + +function Comm::refine_to_double%(d: Comm::Data%): double + %{ + return comm::refine(d->AsRecordVal(), TYPE_DOUBLE, frame); + %} + +function Comm::refine_to_string%(d: Comm::Data%): string + %{ + return new StringVal(comm::require_data_type(d->AsRecordVal(), + TYPE_STRING, + frame)); + %} + +function Comm::refine_to_addr%(d: Comm::Data%): addr + %{ + auto& a = comm::require_data_type(d->AsRecordVal(), + TYPE_ADDR, frame); + auto bits = reinterpret_cast(&a.bytes()); + return new AddrVal(IPAddr(*bits)); + %} + +function Comm::refine_to_subnet%(d: Comm::Data%): subnet + %{ + auto& a = comm::require_data_type(d->AsRecordVal(), + TYPE_SUBNET, frame); + auto bits = reinterpret_cast(&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(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(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(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(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(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(s->AsRecordVal(), TYPE_TABLE, + frame); + return new Val(static_cast(v.size()), TYPE_COUNT); + %} + +function Comm::set_contains%(s: Comm::Data, key: Comm::Data%): bool + %{ + auto& v = comm::require_data_type(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(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(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(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(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(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(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(t->AsRecordVal(), + TYPE_TABLE, frame); + return new Val(static_cast(v.size()), TYPE_COUNT); + %} + +function Comm::table_contains%(t: Comm::Data, key: Comm::Data%): bool + %{ + auto& v = comm::require_data_type(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(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(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(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(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(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(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(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(v->AsRecordVal(), + TYPE_VECTOR, frame); + return new Val(static_cast(vec.size()), TYPE_COUNT); + %} + +function Comm::vector_insert%(v: Comm::Data, d: Comm::Data, idx: count%): bool + %{ + auto& vec = comm::require_data_type(v->AsRecordVal(), + TYPE_VECTOR, frame); + auto& item = comm::opaque_field_to_data(d->AsRecordVal(), frame); + idx = min(idx, static_cast(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(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(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(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(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(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(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(sz))); + %} + +function Comm::record_size%(r: Comm::Data%): count + %{ + auto& v = comm::require_data_type(r->AsRecordVal(), + TYPE_RECORD, frame); + return new Val(static_cast(v.fields.size()), TYPE_COUNT); + %} + +function Comm::record_assign%(r: Comm::Data, d: Comm::Data, idx: count%): bool + %{ + auto& v = comm::require_data_type(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(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(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(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(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%); diff --git a/testing/btest/Baseline/comm.data/out b/testing/btest/Baseline/comm.data/out new file mode 100644 index 0000000000..eea78d39a2 --- /dev/null +++ b/testing/btest/Baseline/comm.data/out @@ -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=] +1 +T +42 +F +[d=] +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=, 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 diff --git a/testing/btest/comm/data.bro b/testing/btest/comm/data.bro new file mode 100644 index 0000000000..3fb9dcd86e --- /dev/null +++ b/testing/btest/comm/data.bro @@ -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); +}