diff --git a/scripts/base/init-bare.zeek b/scripts/base/init-bare.zeek index 02d5ab599d..c1e214e4c8 100644 --- a/scripts/base/init-bare.zeek +++ b/scripts/base/init-bare.zeek @@ -579,6 +579,23 @@ const io_poll_interval_live = 10 &redef; ## while testing, but should be used sparingly. const running_under_test: bool = F &redef; +module EventMetadata; + +export { + ## Enum type for metadata identifiers. + type ID: enum { + NETWORK_TIMESTAMP = 1, + }; + + ## A event metadata entry. + type Entry: record { + id: EventMetadata::ID; ##< The registered :zeek:see:`EventMetadata::ID` value. + val: any; ##< The value. Its type aligns to what was passed to :zeek:see:`EventMetadata::register_type`. + }; +} + +type ::event_metadata_vec: vector of Entry; + module FTP; export { diff --git a/src/Event.cc b/src/Event.cc index d113e475cf..4f117bfa2b 100644 --- a/src/Event.cc +++ b/src/Event.cc @@ -8,6 +8,7 @@ #include "zeek/iosource/Manager.h" #include "zeek/plugin/Manager.h" +#include "const.bif.netvar_h" #include "event.bif.netvar_h" zeek::EventMgr zeek::event_mgr; @@ -182,6 +183,58 @@ void EventMgr::Process() { // and had the opportunity to spawn new events. } -void EventMgr::InitPostScript() { iosource_mgr->Register(this, true, false); } +void EventMgr::InitPostScript() { + // Check if expected types and identifiers are available. + auto et = zeek::id::find_type("EventMetadata::ID"); + if ( ! et ) + zeek::reporter->FatalError("Failed to find EventMetadata::ID"); + + auto net_ts_val = et->GetEnumVal(et->Lookup("EventMetadata::NETWORK_TIMESTAMP")); + if ( ! net_ts_val ) + zeek::reporter->FatalError("Failed to lookup EventMetadata::NETWORK_TIMESTAMP"); + + iosource_mgr->Register(this, true, false); +} + +bool EventMgr::RegisterMetadata(EnumValPtr id, zeek::TypePtr type) { + static const auto& metadata_id_type = zeek::id::find_type("EventMetadata::ID"); + + if ( metadata_id_type != id->GetType() ) + return false; + + auto id_int = id->Get(); + if ( id_int < 0 ) { + zeek::reporter->InternalError("Negative enum value %s: %" PRId64, obj_desc_short(id.get()).c_str(), id_int); + return false; // unreached + } + + zeek_uint_t id_uint = static_cast(id_int); + + auto it = event_metadata_types.find(id_uint); + + // If type contains anything with any, like table[count] of any, we should reject it. + // + // cb = AnyTypeChecker() + // type->Traverse(cb) + if ( it != event_metadata_types.end() ) + return same_type(it->second.type, type); + + event_metadata_types.insert({id_uint, detail::MetadataDescriptor{id_uint, std::move(id), std::move(type)}}); + + return true; +} + +const detail::MetadataDescriptor* EventMgr::LookupMetadata(zeek_uint_t id) const { + const auto it = event_metadata_types.find(id); + if ( it == event_metadata_types.end() ) + return nullptr; + + if ( it->second.id != id ) { + zeek::reporter->InternalError("inconsistent metadata descriptor: %" PRIu64 " vs %" PRId64, it->second.id, id); + return nullptr; // unreached + } + + return &(it->second); +} } // namespace zeek diff --git a/src/Event.h b/src/Event.h index e3d17aae47..3c7e31a54b 100644 --- a/src/Event.h +++ b/src/Event.h @@ -18,6 +18,29 @@ extern double network_time; class EventMgr; +class EnumVal; +using EnumValPtr = IntrusivePtr; + +class Type; +using TypePtr = IntrusivePtr; + +namespace detail { + +/** + * Descriptor for event metadata. + * + * Event metadata has an identifying *id* and a static *type*. The descriptor + * structure holds both and the script-layer enum value in addition. + */ +struct MetadataDescriptor { + zeek_uint_t id; + EnumValPtr enum_val; + TypePtr type; +}; + + +} // namespace detail + class Event final : public Obj { public: Event(const EventHandlerPtr& handler, zeek::Args args, util::detail::SourceID src = util::detail::SOURCE_LOCAL, @@ -119,6 +142,12 @@ public: // Access the currently dispatched event. const Event* CurrentEvent() { return current; } + // Register a EventMetadata::ID with a Zeek type. + bool RegisterMetadata(EnumValPtr id, zeek::TypePtr type); + + // Lookup the descriptor for the given metadata identifier, or nullptr if unknown. + const detail::MetadataDescriptor* LookupMetadata(zeek_uint_t id) const; + void Process() override; const char* Tag() override { return "EventManager"; } void InitPostScript(); @@ -132,6 +161,8 @@ private: Event* current = nullptr; Event* head = nullptr; Event* tail = nullptr; + + std::map event_metadata_types; }; extern EventMgr event_mgr; diff --git a/src/zeek.bif b/src/zeek.bif index 8702a0a7fa..831261b70e 100644 --- a/src/zeek.bif +++ b/src/zeek.bif @@ -401,6 +401,31 @@ function current_event_time%(%): time return zeek::make_intrusive(zeek::event_mgr.CurrentEventTime()); %} +## Register the expected Zeek type for event metadata. +## +## id: The event metadata identifier. +## +## t: A type expression. +## +## Returns: true if the registration was successful, false if *id* is +## registered with a different type already, or type is *any* +## or a composite type containing *any*. +function EventMetadata::register_type%(id: EventMetadata::ID, t: any%): bool + %{ + const auto& tty = t->GetType(); + + if ( tty->Tag() != zeek::TYPE_TYPE ) + { + zeek::emit_builtin_error("register_event_metadata() expects type"); + return zeek::val_mgr->False(); + } + + EnumValPtr idvp = {zeek::NewRef{}, id->AsEnumVal()}; + + bool r = zeek::event_mgr.RegisterMetadata(idvp, tty->AsTypeType()->GetType()); + return zeek::val_mgr->Bool(r); + %} + ## Returns a system environment variable. ## ## var: The name of the variable whose value to request.