A set of interface changes in preparation for merging into BinPAC++

branch.
This commit is contained in:
Robin Sommer 2013-04-09 16:23:20 -07:00
parent 52cd02173d
commit 2002787c6e
27 changed files with 381 additions and 172 deletions

2
cmake

@ -1 +1 @@
Subproject commit 39c1516be5e630bd5d78082e974fae708faa4e8c Subproject commit 8cc03d64d00676cb75a38543800ac0de192557dd

View file

@ -117,7 +117,7 @@ foreach (bift ${BIF_SRCS})
bif_target(${bift}) bif_target(${bift})
endforeach () endforeach ()
add_custom_target(generate_standard_bifs DEPENDS ${ALL_BIF_OUTPUTS}) add_custom_target(generate_bifs DEPENDS ${ALL_BIF_OUTPUTS})
######################################################################## ########################################################################
## BinPAC-dependent targets ## BinPAC-dependent targets
@ -159,20 +159,16 @@ binpac_target(modbus.pac
## Including subdirectories. ## Including subdirectories.
######################################################################## ########################################################################
set(bro_PLUGIN_OBJECT_LIBS CACHE INTERNAL "plugin object libraries" FORCE)
add_subdirectory(analyzer) add_subdirectory(analyzer)
add_subdirectory(protocols)
set(bro_SUBDIRS set(bro_SUBDIRS
$<TARGET_OBJECTS:bro_analyzer> $<TARGET_OBJECTS:bro_analyzer>
${bro_PLUGIN_OBJECT_LIBS}
) )
########################################################################
## Including plug-ins that are compiled in statically.
########################################################################
set(bro_PLUGIN_OBJECT_LIBS CACHE INTERNAL "plugin object libraries" FORCE)
add_subdirectory(protocols)
######################################################################## ########################################################################
## bro target ## bro target
@ -403,8 +399,7 @@ set(bro_SRCS
) )
collect_headers(bro_HEADERS ${bro_SRCS}) collect_headers(bro_HEADERS ${bro_SRCS})
add_executable(bro ${bro_SRCS} ${bro_HEADERS} ${bro_SUBDIRS})
add_executable(bro ${bro_SRCS} ${bro_HEADERS} ${bro_PLUGIN_OBJECT_LIBS} ${bro_SUBDIRS})
target_link_libraries(bro ${brodeps} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(bro ${brodeps} ${CMAKE_THREAD_LIBS_INIT})

View file

@ -413,7 +413,7 @@ analyzer::Analyzer* Connection::FindAnalyzer(analyzer::Tag tag)
return root_analyzer ? root_analyzer->FindChild(tag) : 0; return root_analyzer ? root_analyzer->FindChild(tag) : 0;
} }
analyzer::Analyzer* Connection::FindAnalyzer(const string& name) analyzer::Analyzer* Connection::FindAnalyzer(const char* name)
{ {
return root_analyzer->FindChild(name); return root_analyzer->FindChild(name);
} }

View file

@ -107,7 +107,7 @@ public:
analyzer::Analyzer* FindAnalyzer(analyzer::ID id); analyzer::Analyzer* FindAnalyzer(analyzer::ID id);
analyzer::Analyzer* FindAnalyzer(analyzer::Tag tag); // find first in tree. analyzer::Analyzer* FindAnalyzer(analyzer::Tag tag); // find first in tree.
analyzer::Analyzer* FindAnalyzer(const string& name); // find first in tree. analyzer::Analyzer* FindAnalyzer(const char* name); // find first in tree.
TransportProto ConnTransport() const { return proto; } TransportProto ConnTransport() const { return proto; }

View file

@ -80,8 +80,10 @@ void EventRegistry::PrintDebug()
while ( (v = handlers.NextEntry(k, c)) ) while ( (v = handlers.NextEntry(k, c)) )
{ {
delete k; delete k;
fprintf(stderr, "Registered event %s (%s handler)\n", v->Name(), fprintf(stderr, "Registered event %s (%s handler / %s)\n", v->Name(),
v->LocalHandler()? "local" : "no"); v->LocalHandler()? "local" : "no",
*v ? "active" : "not active"
);
} }
} }

View file

@ -26,6 +26,7 @@ public:
bool IsGlobal() const { return scope != SCOPE_FUNCTION; } bool IsGlobal() const { return scope != SCOPE_FUNCTION; }
bool IsExport() const { return is_export; } bool IsExport() const { return is_export; }
void SetExport() { is_export = true; }
string ModuleName() const; string ModuleName() const;

View file

@ -40,7 +40,7 @@ RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer)
string str(arg_analyzer); string str(arg_analyzer);
string::size_type pos = str.find(':'); string::size_type pos = str.find(':');
string arg = str.substr(0, pos); string arg = str.substr(0, pos);
analyzer = analyzer_mgr->GetAnalyzerTag(arg); analyzer = analyzer_mgr->GetAnalyzerTag(arg.c_str());
if ( ! analyzer ) if ( ! analyzer )
reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str()); reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str());
@ -48,7 +48,7 @@ RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer)
if ( pos != string::npos ) if ( pos != string::npos )
{ {
arg = str.substr(pos + 1); arg = str.substr(pos + 1);
child_analyzer = analyzer_mgr->GetAnalyzerTag(arg); child_analyzer = analyzer_mgr->GetAnalyzerTag(arg.c_str());
if ( ! child_analyzer ) if ( ! child_analyzer )
reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str()); reporter->Warning("unknown analyzer '%s' specified in rule", arg.c_str());
@ -60,11 +60,11 @@ RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer)
void RuleActionAnalyzer::PrintDebug() void RuleActionAnalyzer::PrintDebug()
{ {
if ( ! child_analyzer ) if ( ! child_analyzer )
fprintf(stderr, "|%s|\n", analyzer_mgr->GetAnalyzerName(analyzer).c_str()); fprintf(stderr, "|%s|\n", analyzer_mgr->GetAnalyzerName(analyzer));
else else
fprintf(stderr, "|%s:%s|\n", fprintf(stderr, "|%s:%s|\n",
analyzer_mgr->GetAnalyzerName(analyzer).c_str(), analyzer_mgr->GetAnalyzerName(analyzer),
analyzer_mgr->GetAnalyzerName(child_analyzer).c_str()); analyzer_mgr->GetAnalyzerName(child_analyzer));
} }

View file

@ -267,6 +267,10 @@ public:
: Analyzer(name, conn) : Analyzer(name, conn)
{ tcp = 0; } { tcp = 0; }
TCP_ApplicationAnalyzer(Connection* conn)
: Analyzer(conn)
{ tcp = 0; }
virtual ~TCP_ApplicationAnalyzer() { } virtual ~TCP_ApplicationAnalyzer() { }
// This may be nil if we are not directly associated with a TCP // This may be nil if we are not directly associated with a TCP

View file

@ -72,28 +72,56 @@ void AnalyzerTimer::Init(Analyzer* arg_analyzer, analyzer_timer_func arg_timer,
analyzer::ID Analyzer::id_counter = 0;; analyzer::ID Analyzer::id_counter = 0;;
const string& Analyzer::GetAnalyzerName() const const char* Analyzer::GetAnalyzerName() const
{ {
assert(tag);
return analyzer_mgr->GetAnalyzerName(tag); return analyzer_mgr->GetAnalyzerName(tag);
} }
void Analyzer::SetAnalyzerTag(const Tag& arg_tag)
{
assert(! tag || tag == arg_tag);
tag = arg_tag;
}
bool Analyzer::IsAnalyzer(const char* name) bool Analyzer::IsAnalyzer(const char* name)
{ {
return analyzer_mgr->GetAnalyzerName(tag) == name; assert(tag);
return strcmp(analyzer_mgr->GetAnalyzerName(tag), name) == 0;
} }
// Used in debugging output. // Used in debugging output.
static string fmt_analyzer(Analyzer* a) static string fmt_analyzer(Analyzer* a)
{ {
return a->GetAnalyzerName() + fmt("[%d]", a->GetID()); return string(a->GetAnalyzerName()) + fmt("[%d]", a->GetID());
} }
Analyzer::Analyzer(const char* name, Connection* arg_conn) Analyzer::Analyzer(const char* name, Connection* conn)
{
Tag tag = analyzer_mgr->GetAnalyzerTag(name);
if ( ! tag )
reporter->InternalError("unknown analyzer name %s; mismatch with tag analyzer::Component?", name);
CtorInit(tag, conn);
}
Analyzer::Analyzer(const Tag& tag, Connection* conn)
{
CtorInit(tag, conn);
}
Analyzer::Analyzer(Connection* conn)
{
CtorInit(Tag(), conn);
}
void Analyzer::CtorInit(const Tag& arg_tag, Connection* arg_conn)
{ {
// Don't Ref conn here to avoid circular ref'ing. It can't be deleted // Don't Ref conn here to avoid circular ref'ing. It can't be deleted
// before us. // before us.
conn = arg_conn; conn = arg_conn;
tag = analyzer_mgr->GetAnalyzerTag(name); tag = arg_tag;
id = ++id_counter; id = ++id_counter;
protocol_confirmed = false; protocol_confirmed = false;
skip = false; skip = false;
@ -104,10 +132,6 @@ Analyzer::Analyzer(const char* name, Connection* arg_conn)
resp_supporters = 0; resp_supporters = 0;
signature = 0; signature = 0;
output_handler = 0; output_handler = 0;
if ( ! tag )
reporter->InternalError("unknown analyzer name %s; mismatch with tag analyzer::Component?", name);
} }
Analyzer::~Analyzer() Analyzer::~Analyzer()
@ -417,7 +441,7 @@ void Analyzer::RemoveChildAnalyzer(ID id)
LOOP_OVER_CHILDREN(i) LOOP_OVER_CHILDREN(i)
if ( (*i)->id == id && ! ((*i)->finished || (*i)->removing) ) if ( (*i)->id == id && ! ((*i)->finished || (*i)->removing) )
{ {
DBG_LOG(DBG_ANALYZER, "%s disabling child %s", GetAnalyzerName().c_str(), id, DBG_LOG(DBG_ANALYZER, "%s disabling child %s", GetAnalyzerName(), id,
fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str()); fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str());
// See comment above. // See comment above.
(*i)->removing = true; (*i)->removing = true;
@ -468,7 +492,7 @@ Analyzer* Analyzer::FindChild(Tag arg_tag)
return 0; return 0;
} }
Analyzer* Analyzer::FindChild(const string& name) Analyzer* Analyzer::FindChild(const char* name)
{ {
Tag tag = analyzer_mgr->GetAnalyzerTag(name); Tag tag = analyzer_mgr->GetAnalyzerTag(name);
return tag ? FindChild(tag) : 0; return tag ? FindChild(tag) : 0;
@ -625,9 +649,12 @@ void Analyzer::ProtocolConfirmation()
if ( protocol_confirmed ) if ( protocol_confirmed )
return; return;
EnumVal* tval = tag.AsEnumVal();
Ref(tval);
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(tag.AsEnumVal()); vl->append(tval);
vl->append(new Val(id, TYPE_COUNT)); vl->append(new Val(id, TYPE_COUNT));
// We immediately raise the event so that the analyzer can quickly // We immediately raise the event so that the analyzer can quickly
@ -653,9 +680,12 @@ void Analyzer::ProtocolViolation(const char* reason, const char* data, int len)
else else
r = new StringVal(reason); r = new StringVal(reason);
EnumVal* tval = tag.AsEnumVal();
Ref(tval);
val_list* vl = new val_list; val_list* vl = new val_list;
vl->append(BuildConnVal()); vl->append(BuildConnVal());
vl->append(tag.AsEnumVal()); vl->append(tval);
vl->append(new Val(id, TYPE_COUNT)); vl->append(new Val(id, TYPE_COUNT));
vl->append(r); vl->append(r);

View file

@ -61,13 +61,32 @@ public:
/** /**
* Constructor. * Constructor.
* *
* @param name A name for the protocol the analyzer is parsing. The * @param name The name for the type of analyzer. The name must match
* name must match the one the corresponding Component registers. * the one the corresponding Component registers.
* *
* @param conn The connection the analyzer is associated with. * @param conn The connection the analyzer is associated with.
*/ */
Analyzer(const char* name, Connection* conn); Analyzer(const char* name, Connection* conn);
/**
* Constructor.
*
* @param tag The tag for the type of analyzer. The tag must map to
* the name the corresponding Component registers.
*
* @param conn The connection the analyzer is associated with.
*/
Analyzer(const Tag& tag, Connection* conn);
/**
* Constructor. As this version of the constructor does not receive a
* name or tag, setTag() must be called before the instance can be
* used.
*
* @param conn The connection the analyzer is associated with.
*/
Analyzer(Connection* conn);
/** /**
* Destructor. * Destructor.
*/ */
@ -285,14 +304,22 @@ public:
/** /**
* Returns the tag associated with the analyzer's type. * Returns the tag associated with the analyzer's type.
*/ */
Tag GetAnalyzerTag() const { return tag; } Tag GetAnalyzerTag() const { assert(tag); return tag; }
/**
* Sets the tag associated with the analyzer's type. Note that this
* can be called only right after construction, if the constructor
* did not receive a name or tag. The method cannot be used to change
* an existing tag.
*/
void SetAnalyzerTag(const Tag& tag);
/** /**
* Returns a textual description of the analyzer's type. This is * Returns a textual description of the analyzer's type. This is
* what's passed to the constructor and usally corresponds to the * what's passed to the constructor and usally corresponds to the
* protocol name, e.g., "HTTP". * protocol name, e.g., "HTTP".
*/ */
const string& GetAnalyzerName() const; const char* GetAnalyzerName() const;
/** /**
* Returns true if this analyzer's type matches the name passes in. * Returns true if this analyzer's type matches the name passes in.
@ -377,7 +404,7 @@ public:
* @return The first analyzer of the given type found, or null if * @return The first analyzer of the given type found, or null if
* none. * none.
*/ */
Analyzer* FindChild(const string& name); Analyzer* FindChild(const char* name);
/** /**
* Returns a list of all direct child analyzers. * Returns a list of all direct child analyzers.
@ -574,6 +601,9 @@ private:
// already Done(). // already Done().
void DeleteChild(analyzer_list::iterator i); void DeleteChild(analyzer_list::iterator i);
// Helper for the ctors.
void CtorInit(const Tag& tag, Connection* conn);
Tag tag; Tag tag;
ID id; ID id;

View file

@ -7,10 +7,10 @@ using namespace analyzer;
Tag::type_t Component::type_counter = 0; Tag::type_t Component::type_counter = 0;
Component::Component(std::string arg_name, factory_callback arg_factory, Tag::subtype_t arg_subtype, bool arg_enabled, bool arg_partial) Component::Component(const char* arg_name, factory_callback arg_factory, Tag::subtype_t arg_subtype, bool arg_enabled, bool arg_partial)
: plugin::Component(plugin::component::ANALYZER) : plugin::Component(plugin::component::ANALYZER)
{ {
name = arg_name; name = copy_string(arg_name);
factory = arg_factory; factory = arg_factory;
enabled = arg_enabled; enabled = arg_enabled;
partial = arg_partial; partial = arg_partial;
@ -18,6 +18,26 @@ Component::Component(std::string arg_name, factory_callback arg_factory, Tag::su
tag = analyzer::Tag(++type_counter, arg_subtype); tag = analyzer::Tag(++type_counter, arg_subtype);
} }
Component::Component(const Component& other)
: plugin::Component(Type())
{
name = copy_string(other.name);
factory = other.factory;
enabled = other.enabled;
partial = other.partial;
tag = other.tag;
}
Component::~Component()
{
delete [] name;
}
analyzer::Tag Component::Tag() const
{
return tag;
}
void Component::Describe(ODesc* d) void Component::Describe(ODesc* d)
{ {
plugin::Component::Describe(d); plugin::Component::Describe(d);
@ -27,3 +47,16 @@ void Component::Describe(ODesc* d)
d->Add(")"); d->Add(")");
} }
Component& Component::operator=(const Component& other)
{
if ( &other != this )
{
name = copy_string(other.name);
factory = other.factory;
enabled = other.enabled;
partial = other.partial;
tag = other.tag;
}
return *this;
}

View file

@ -2,8 +2,6 @@
#ifndef ANALYZER_PLUGIN_COMPONENT_H #ifndef ANALYZER_PLUGIN_COMPONENT_H
#define ANALYZER_PLUGIN_COMPONENT_H #define ANALYZER_PLUGIN_COMPONENT_H
#include <string>
#include "Tag.h" #include "Tag.h"
#include "plugin/Component.h" #include "plugin/Component.h"
@ -21,8 +19,6 @@ class Analyzer;
* *
* A plugin can provide a specific protocol analyzer by registering this * A plugin can provide a specific protocol analyzer by registering this
* analyzer component, describing the analyzer. * analyzer component, describing the analyzer.
*
* This class is safe to copy by value.
*/ */
class Component : public plugin::Component { class Component : public plugin::Component {
public: public:
@ -58,13 +54,23 @@ public:
* connections has generally not seen much testing yet as virtually * connections has generally not seen much testing yet as virtually
* no existing analyzer supports it. * no existing analyzer supports it.
*/ */
Component(std::string name, factory_callback factory, Tag::subtype_t subtype = 0, bool enabled = true, bool partial = false); Component(const char* name, factory_callback factory, Tag::subtype_t subtype = 0, bool enabled = true, bool partial = false);
/**
* Copy constructor.
*/
Component(const Component& other);
/**
* Destructor.
*/
~Component();
/** /**
* Returns the name of the analyzer. This name is unique across all * Returns the name of the analyzer. This name is unique across all
* analyzers and used to identify it. * analyzers and used to identify it.
*/ */
const std::string& Name() const { return name; } const char* Name() const { return name; }
/** /**
* Returns the analyzer's factory function. * Returns the analyzer's factory function.
@ -74,7 +80,7 @@ public:
/** /**
* Returns whether the analyzer supports partial connections. Partial * Returns whether the analyzer supports partial connections. Partial
* connections are those where Bro starts processing payload * connections are those where Bro starts processing payload
* mid-stream, after missing the beginning. * mid-stream, after missing the beginning.
*/ */
bool Partial() const { return partial; } bool Partial() const { return partial; }
@ -89,7 +95,7 @@ public:
* generated for each new Components, and hence unique across all of * generated for each new Components, and hence unique across all of
* them. * them.
*/ */
analyzer::Tag Tag() const { return tag; } analyzer::Tag Tag() const;
/** /**
* Enables or disables this analyzer. * Enables or disables this analyzer.
@ -105,15 +111,17 @@ public:
*/ */
virtual void Describe(ODesc* d); virtual void Describe(ODesc* d);
Component& operator=(const Component& other);
private: private:
std::string name; // The analyzer's name. const char* name; // The analyzer's name.
factory_callback factory; // The analyzer's factory callback. factory_callback factory; // The analyzer's factory callback.
bool partial; // True if the analyzer supports partial connections. bool partial; // True if the analyzer supports partial connections.
analyzer::Tag tag; // The automatically assigned analyzer tag. analyzer::Tag tag; // The automatically assigned analyzer tag.
bool enabled; // True if the analyzer is enabled. bool enabled; // True if the analyzer is enabled.
// Global counter used to generate unique tags. // Global counter used to generate unique tags.
static analyzer::Tag::type_t type_counter; static analyzer::Tag::type_t type_counter;
}; };
} }

View file

@ -108,7 +108,7 @@ void Manager::DumpDebug()
#ifdef DEBUG #ifdef DEBUG
DBG_LOG(DBG_ANALYZER, "Available analyzers after bro_init():"); DBG_LOG(DBG_ANALYZER, "Available analyzers after bro_init():");
for ( analyzer_map_by_name::const_iterator i = analyzers_by_name.begin(); i != analyzers_by_name.end(); i++ ) for ( analyzer_map_by_name::const_iterator i = analyzers_by_name.begin(); i != analyzers_by_name.end(); i++ )
DBG_LOG(DBG_ANALYZER, " %s (%s)", i->second->Name().c_str(), IsEnabled(i->second->Tag()) ? "enabled" : "disabled"); DBG_LOG(DBG_ANALYZER, " %s (%s)", i->second->Name(), IsEnabled(i->second->Tag()) ? "enabled" : "disabled");
DBG_LOG(DBG_ANALYZER, ""); DBG_LOG(DBG_ANALYZER, "");
DBG_LOG(DBG_ANALYZER, "Analyzers by port:"); DBG_LOG(DBG_ANALYZER, "Analyzers by port:");
@ -118,7 +118,7 @@ void Manager::DumpDebug()
string s; string s;
for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ )
s += GetAnalyzerName(*j) + " "; s += string(GetAnalyzerName(*j)) + " ";
DBG_LOG(DBG_ANALYZER, " %d/tcp: %s", i->first, s.c_str()); DBG_LOG(DBG_ANALYZER, " %d/tcp: %s", i->first, s.c_str());
} }
@ -128,7 +128,7 @@ void Manager::DumpDebug()
string s; string s;
for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ )
s += GetAnalyzerName(*j) + " "; s += string(GetAnalyzerName(*j)) + " ";
DBG_LOG(DBG_ANALYZER, " %d/udp: %s", i->first, s.c_str()); DBG_LOG(DBG_ANALYZER, " %d/udp: %s", i->first, s.c_str());
} }
@ -151,10 +151,10 @@ void Manager::Done()
void Manager::RegisterAnalyzerComponent(Component* component) void Manager::RegisterAnalyzerComponent(Component* component)
{ {
if ( Lookup(component->Name()) ) if ( Lookup(component->Name()) )
reporter->FatalError("Analyzer %s defined more than once", component->Name().c_str()); reporter->FatalError("Analyzer %s defined more than once", component->Name());
DBG_LOG(DBG_ANALYZER, "Registering analyzer %s (tag %s)", DBG_LOG(DBG_ANALYZER, "Registering analyzer %s (tag %s)",
component->Name().c_str(), component->Tag().AsString().c_str()); component->Name(), component->Tag().AsString().c_str());
analyzers_by_name.insert(std::make_pair(component->Name(), component)); analyzers_by_name.insert(std::make_pair(component->Name(), component));
analyzers_by_tag.insert(std::make_pair(component->Tag(), component)); analyzers_by_tag.insert(std::make_pair(component->Tag(), component));
@ -173,7 +173,7 @@ bool Manager::EnableAnalyzer(Tag tag)
if ( ! p ) if ( ! p )
return false; return false;
DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name());
p->SetEnabled(true); p->SetEnabled(true);
return true; return true;
@ -186,7 +186,7 @@ bool Manager::EnableAnalyzer(EnumVal* val)
if ( ! p ) if ( ! p )
return false; return false;
DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Enabling analyzer %s", p->Name());
p->SetEnabled(true); p->SetEnabled(true);
return true; return true;
@ -199,7 +199,7 @@ bool Manager::DisableAnalyzer(Tag tag)
if ( ! p ) if ( ! p )
return false; return false;
DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name());
p->SetEnabled(false); p->SetEnabled(false);
return true; return true;
@ -212,7 +212,7 @@ bool Manager::DisableAnalyzer(EnumVal* val)
if ( ! p ) if ( ! p )
return false; return false;
DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name().c_str()); DBG_LOG(DBG_ANALYZER, "Disabling analyzer %s", p->Name());
p->SetEnabled(false); p->SetEnabled(false);
return true; return true;
@ -256,7 +256,7 @@ bool Manager::RegisterAnalyzerForPort(EnumVal* val, PortVal* port)
if ( ! p ) if ( ! p )
return false; return false;
return RegisterAnalyzerForPort(p->Tag(), port->PortType(), port->Port()); return RegisterAnalyzerForPort(p->Tag(), port->PortType(), port->Port());
} }
@ -275,8 +275,8 @@ bool Manager::RegisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port
tag_set* l = LookupPort(proto, port, true); tag_set* l = LookupPort(proto, port, true);
#ifdef DEBUG #ifdef DEBUG
std::string name = GetAnalyzerName(tag); const char* name = GetAnalyzerName(tag);
DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name.c_str(), port, proto); DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name, port, proto);
#endif #endif
l->insert(tag); l->insert(tag);
@ -288,8 +288,8 @@ bool Manager::UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 po
tag_set* l = LookupPort(proto, port, true); tag_set* l = LookupPort(proto, port, true);
#ifdef DEBUG #ifdef DEBUG
std::string name = GetAnalyzerName(tag); const char* name = GetAnalyzerName(tag);
DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name.c_str(), port, proto); DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name, port, proto);
#endif #endif
l->erase(tag); l->erase(tag);
@ -312,6 +312,8 @@ Analyzer* Manager::InstantiateAnalyzer(Tag tag, Connection* conn)
if ( ! a ) if ( ! a )
reporter->InternalError("analyzer instantiation failed"); reporter->InternalError("analyzer instantiation failed");
a->SetAnalyzerTag(tag);
return a; return a;
} }
@ -321,9 +323,9 @@ Analyzer* Manager::InstantiateAnalyzer(const char* name, Connection* conn)
return tag ? InstantiateAnalyzer(tag, conn) : 0; return tag ? InstantiateAnalyzer(tag, conn) : 0;
} }
const string& Manager::GetAnalyzerName(Tag tag) const char* Manager::GetAnalyzerName(Tag tag)
{ {
static string error = "<error>"; static const char* error = "<error>";
if ( ! tag ) if ( ! tag )
return error; return error;
@ -336,17 +338,11 @@ const string& Manager::GetAnalyzerName(Tag tag)
return c->Name(); return c->Name();
} }
const string& Manager::GetAnalyzerName(Val* val) const char* Manager::GetAnalyzerName(Val* val)
{ {
return GetAnalyzerName(Tag(val->AsEnumVal())); return GetAnalyzerName(Tag(val->AsEnumVal()));
} }
Tag Manager::GetAnalyzerTag(const string& name)
{
Component* c = Lookup(name);
return c ? c->Tag() : Tag();
}
Tag Manager::GetAnalyzerTag(const char* name) Tag Manager::GetAnalyzerTag(const char* name)
{ {
Component* c = Lookup(name); Component* c = Lookup(name);
@ -358,12 +354,6 @@ EnumType* Manager::GetTagEnumType()
return tag_enum_type; return tag_enum_type;
} }
Component* Manager::Lookup(const string& name)
{
analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name));
return i != analyzers_by_name.end() ? i->second : 0;
}
Component* Manager::Lookup(const char* name) Component* Manager::Lookup(const char* name)
{ {
analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name)); analyzer_map_by_name::const_iterator i = analyzers_by_name.find(to_upper(name));
@ -474,7 +464,7 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
root->AddChildAnalyzer(analyzer, false); root->AddChildAnalyzer(analyzer, false);
DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled", DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled",
analyzer_mgr->GetAnalyzerName(*i).c_str()); analyzer_mgr->GetAnalyzerName(*i));
} }
} }
@ -500,7 +490,7 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
root->AddChildAnalyzer(analyzer, false); root->AddChildAnalyzer(analyzer, false);
DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d", DBG_ANALYZER_ARGS(conn, "activated %s analyzer due to port %d",
analyzer_mgr->GetAnalyzerName(*j).c_str(), resp_port); analyzer_mgr->GetAnalyzerName(*j), resp_port);
} }
} }
} }
@ -622,7 +612,7 @@ void Manager::ExpireScheduledAnalyzers()
conns.erase(i); conns.erase(i);
DBG_LOG(DBG_ANALYZER, "Expiring expected analyzer %s for connection %s", DBG_LOG(DBG_ANALYZER, "Expiring expected analyzer %s for connection %s",
analyzer_mgr->GetAnalyzerName(a->analyzer).c_str(), analyzer_mgr->GetAnalyzerName(a->analyzer),
fmt_conn_id(a->conn.orig, 0, a->conn.resp, a->conn.resp_p)); fmt_conn_id(a->conn.orig, 0, a->conn.resp, a->conn.resp_p));
delete a; delete a;
@ -661,7 +651,7 @@ void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp,
void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, void Manager::ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp,
uint16 resp_p, uint16 resp_p,
TransportProto proto, const string& analyzer, TransportProto proto, const char* analyzer,
double timeout) double timeout)
{ {
Tag tag = GetAnalyzerTag(analyzer); Tag tag = GetAnalyzerTag(analyzer);

View file

@ -42,6 +42,10 @@ namespace analyzer {
* sets up their initial analyzer tree, including adding the right \c PIA, * sets up their initial analyzer tree, including adding the right \c PIA,
* respecting well-known ports, and tracking any analyzers specifically * respecting well-known ports, and tracking any analyzers specifically
* scheduled for individidual connections. * scheduled for individidual connections.
*
* Note that we keep the public interface of this class free of std::*
* classes. This allows to external analyzer code to potentially use a
* different C++ standard library.
*/ */
class Manager { class Manager {
public: public:
@ -232,7 +236,7 @@ public:
* *
* @return The name, or an empty string if the tag is invalid. * @return The name, or an empty string if the tag is invalid.
*/ */
const string& GetAnalyzerName(Tag tag); const char* GetAnalyzerName(Tag tag);
/** /**
* Translates an script-level analyzer tag into corresponding * Translates an script-level analyzer tag into corresponding
@ -243,17 +247,7 @@ public:
* *
* @return The name, or an empty string if the tag is invalid. * @return The name, or an empty string if the tag is invalid.
*/ */
const string& GetAnalyzerName(Val* val); const char* GetAnalyzerName(Val* val);
/**
* Translates an analyzer name into the corresponding tag.
*
* @param name The name.
*
* @return The tag. If the name does not correspond to a valid
* analyzer, the returned tag will evaluate to false.
*/
Tag GetAnalyzerTag(const string& name);
/** /**
* Translates an analyzer name into the corresponding tag. * Translates an analyzer name into the corresponding tag.
@ -327,7 +321,7 @@ public:
* schedule this analyzer. Must be non-zero. * schedule this analyzer. Must be non-zero.
*/ */
void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16 resp_p, void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
TransportProto proto, const string& analyzer, TransportProto proto, const char* analyzer,
double timeout); double timeout);
/** /**

View file

@ -31,7 +31,7 @@ Tag::Tag(EnumVal* arg_val)
subtype = (i >> 31) & 0xffffffff; subtype = (i >> 31) & 0xffffffff;
} }
Tag::Tag(const Tag& other) : type(other.type), subtype(other.subtype) Tag::Tag(const Tag& other)
{ {
type = other.type; type = other.type;
subtype = other.subtype; subtype = other.subtype;
@ -48,6 +48,27 @@ Tag::Tag()
val = 0; val = 0;
} }
Tag::~Tag()
{
Unref(val);
val = 0;
}
Tag& Tag::operator=(const Tag& other)
{
if ( this != &other )
{
type = other.type;
subtype = other.subtype;
val = other.val;
if ( val )
Ref(val);
}
return *this;
}
EnumVal* Tag::AsEnumVal() const EnumVal* Tag::AsEnumVal() const
{ {
if ( ! val ) if ( ! val )

View file

@ -53,6 +53,11 @@ public:
*/ */
Tag(); Tag();
/**
* Destructor.
*/
~Tag();
/** /**
* Returns the tag's main type. * Returns the tag's main type.
*/ */
@ -81,6 +86,11 @@ public:
*/ */
operator bool() const { return *this != Tag(); } operator bool() const { return *this != Tag(); }
/**
* Assignment operator.
*/
Tag& operator=(const Tag& other);
/** /**
* Compares two tags for equality. * Compares two tags for equality.
*/ */

View file

@ -235,9 +235,9 @@ void init_alternative_mode()
fprintf(fp_func_init, "\n"); fprintf(fp_func_init, "\n");
fprintf(fp_func_init, "namespace plugin { namespace %s {\n", plugin); fprintf(fp_func_init, "namespace plugin { namespace %s {\n", plugin);
fprintf(fp_func_init, "\n"); fprintf(fp_func_init, "\n");
fprintf(fp_func_init, "std::list<std::pair<std::string, int> > __bif_%s_init()\n", name); fprintf(fp_func_init, "std::list<std::pair<const char*, int> > __bif_%s_init()\n", name);
fprintf(fp_func_init, "\t{\n"); fprintf(fp_func_init, "\t{\n");
fprintf(fp_func_init, "\tstd::list<std::pair<std::string, int> > bifs;\n"); fprintf(fp_func_init, "\tstd::list<std::pair<const char*, int> > bifs;\n");
fprintf(fp_func_init, "\n"); fprintf(fp_func_init, "\n");
} }
} }

View file

@ -814,8 +814,8 @@ int main(int argc, char** argv)
log_mgr = new logging::Manager(); log_mgr = new logging::Manager();
input_mgr = new input::Manager(); input_mgr = new input::Manager();
plugin_mgr = new plugin::Manager(); plugin_mgr = new plugin::Manager();
plugin_mgr->InitPlugins();
plugin_mgr->InitPlugins();
analyzer_mgr->Init(); analyzer_mgr->Init();
if ( events_file ) if ( events_file )

View file

@ -15,25 +15,22 @@
protected: \ protected: \
void Init() \ void Init() \
{ \ { \
plugin::Description _desc; \ SetName(#_name); \
_desc.name = #_name; \ SetVersion(_BRO_PLUGIN_VERSION_DEFAULT); \
_desc.version = _BRO_PLUGIN_VERSION_DEFAULT; \ SetAPIVersion(BRO_PLUGIN_API_VERSION);
_desc.api_version = BRO_PLUGIN_API_VERSION;
#define BRO_PLUGIN_END \ #define BRO_PLUGIN_END \
SetDescription(_desc); \
} \ } \
}; \ }; \
\ \
static Plugin __plugin; \ static Plugin __plugin; \
} } } }
#define BRO_PLUGIN_DESCRIPTION _desc.description #define BRO_PLUGIN_DESCRIPTION(x) SetDescription(x)
#define BRO_PLUGIN_URL _desc.url #define BRO_PLUGIN_VERSION(x) SetVersion(x)
#define BRO_PLUGIN_VERSION _desc.version
#define BRO_PLUGIN_BIF_FILE(file) \ #define BRO_PLUGIN_BIF_FILE(file) \
std::list<std::pair<std::string, int> > __bif_##file##_init(); \ std::list<std::pair<const char*, int> > __bif_##file##_init(); \
AddBifInitFunction(&__bif_##file##_init); AddBifInitFunction(&__bif_##file##_init);
#define BRO_PLUGIN_ANALYZER(tag, factory) \ #define BRO_PLUGIN_ANALYZER(tag, factory) \

View file

@ -9,33 +9,86 @@
using namespace plugin; using namespace plugin;
Description::Description() BifItem::BifItem(const BifItem& other)
{ {
name = "<NAME-NOT-SET>"; id = copy_string(other.id);
type = other.type;
}
// These will be reset by the BRO_PLUGIN_* macros. BifItem& BifItem::operator=(const BifItem& other)
version = -9999; {
api_version = -9999; if ( this != &other )
{
id = copy_string(other.id);
type = other.type;
}
return *this;
}
BifItem::~BifItem()
{
delete [] id;
} }
Plugin::Plugin() Plugin::Plugin()
{ {
name = copy_string("<NAME-NOT-SET>");
description = copy_string("");
// These will be reset by the BRO_PLUGIN_* macros.
version = -9999;
api_version = -9999;
Manager::RegisterPlugin(this); Manager::RegisterPlugin(this);
} }
Description Plugin::GetDescription() const
{
return description;
}
void Plugin::SetDescription(Description& desc)
{
description = desc;
}
Plugin::~Plugin() Plugin::~Plugin()
{ {
Done(); Done();
delete [] name;
delete [] description;
}
const char* Plugin::Name()
{
return name;
}
void Plugin::SetName(const char* arg_name)
{
name = copy_string(arg_name);
}
const char* Plugin::Description()
{
return description;
}
void Plugin::SetDescription(const char* arg_description)
{
description = copy_string(arg_description);
}
int Plugin::Version()
{
return version;
}
void Plugin::SetVersion(int arg_version)
{
version = arg_version;
}
int Plugin::APIVersion()
{
return api_version;
}
void Plugin::SetAPIVersion(int arg_version)
{
api_version = arg_version;
} }
void Plugin::Init() void Plugin::Init()
@ -50,17 +103,26 @@ void Plugin::InitBif()
for ( bif_init_func_result::const_iterator i = items.begin(); i != items.end(); i++ ) for ( bif_init_func_result::const_iterator i = items.begin(); i != items.end(); i++ )
{ {
BifItem bi; BifItem bi((*i).first, (BifItem::Type)(*i).second);
bi.id = (*i).first;
bi.type = (BifItem::Type)(*i).second;
bif_items.push_back(bi); bif_items.push_back(bi);
} }
} }
} }
const Plugin::bif_item_list& Plugin::BifItems() Plugin::bif_item_list Plugin::BifItems()
{ {
return bif_items; bif_item_list l1 = bif_items;
bif_item_list l2 = CustomBifItems();
for ( bif_item_list::const_iterator i = l2.begin(); i != l2.end(); i++ )
l1.push_back(*i);
return l1;
}
Plugin::bif_item_list Plugin::CustomBifItems()
{
return bif_item_list();
} }
void Plugin::Done() void Plugin::Done()
@ -89,24 +151,18 @@ void Plugin::AddBifInitFunction(bif_init_func c)
void Plugin::Describe(ODesc* d) void Plugin::Describe(ODesc* d)
{ {
d->Add("Plugin: "); d->Add("Plugin: ");
d->Add(description.name); d->Add(name);
if ( description.description.size() ) if ( description && *description )
{ {
d->Add(" - "); d->Add(" - ");
d->Add(description.description); d->Add(description);
} }
if ( description.version != BRO_PLUGIN_VERSION_BUILTIN ) if ( version != BRO_PLUGIN_VERSION_BUILTIN )
{ {
d->Add(" (version "); d->Add(" (version ");
d->Add(description.version); d->Add(version);
if ( description.url.size() )
{
d->Add(", from ");
d->Add(description.url);
}
d->Add(")"); d->Add(")");
} }
@ -125,11 +181,13 @@ void Plugin::Describe(ODesc* d)
d->Add("\n"); d->Add("\n");
} }
for ( bif_item_list::const_iterator i = bif_items.begin(); i != bif_items.end(); i++ ) bif_item_list items = BifItems();
for ( bif_item_list::const_iterator i = items.begin(); i != items.end(); i++ )
{ {
const char* type = 0; const char* type = 0;
switch ( (*i).type ) { switch ( (*i).GetType() ) {
case BifItem::FUNCTION: case BifItem::FUNCTION:
type = "Function"; type = "Function";
break; break;
@ -158,7 +216,7 @@ void Plugin::Describe(ODesc* d)
d->Add("["); d->Add("[");
d->Add(type); d->Add(type);
d->Add("] "); d->Add("] ");
d->Add((*i).id); d->Add((*i).GetID());
d->Add("\n"); d->Add("\n");
} }
} }

View file

@ -14,25 +14,30 @@ namespace plugin {
class Manager; class Manager;
class Component; class Component;
struct Description { class BifItem {
std::string name; public:
std::string description;
std::string url;
int version;
int api_version;
Description();
void Describe(ODesc* d);
};
struct BifItem {
// Values must match the integers bifcl generates. // Values must match the integers bifcl generates.
enum Type { FUNCTION = 1, EVENT = 2, CONSTANT = 3, GLOBAL = 4, TYPE = 5 }; enum Type { FUNCTION = 1, EVENT = 2, CONSTANT = 3, GLOBAL = 4, TYPE = 5 };
std::string id; BifItem(const std::string& id, Type type);
BifItem(const BifItem& other);
BifItem& operator=(const BifItem& other);
~BifItem();
const char* GetID() const { return id; }
Type GetType() const { return type; }
private:
const char* id;
Type type; Type type;
}; };
inline BifItem::BifItem(const std::string& arg_id, Type arg_type)
{
id = copy_string(arg_id.c_str());
type = arg_type;
}
class Plugin { class Plugin {
public: public:
typedef std::list<Component *> component_list; typedef std::list<Component *> component_list;
@ -41,15 +46,17 @@ public:
Plugin(); Plugin();
virtual ~Plugin(); virtual ~Plugin();
Description GetDescription() const; const char* Name();
void SetDescription(Description& desc); const char* Description();
int Version();
int APIVersion();
component_list Components(); component_list Components();
void InitBif(); void InitBif();
// Must be called after InitBif() only. // Must be called after InitBif() only.
const bif_item_list& BifItems(); bif_item_list BifItems();
virtual void Init(); virtual void Init();
virtual void Done(); virtual void Done();
@ -57,19 +64,42 @@ public:
void Describe(ODesc* d); void Describe(ODesc* d);
protected: protected:
typedef std::list<std::pair<const char*, int> > bif_init_func_result;
typedef bif_init_func_result (*bif_init_func)();
void SetName(const char* name);
void SetDescription(const char* descr);
void SetVersion(int version);
void SetAPIVersion(int version);
/** /**
* Takes ownership. * Takes ownership.
*/ */
void AddComponent(Component* c); void AddComponent(Component* c);
typedef std::list<std::pair<std::string, int> > bif_init_func_result; /**
typedef bif_init_func_result (*bif_init_func)(); * Can be overriden by derived class to inform the plugin about
* further BiF items they provide on their own (i.e., outside of the
* standard mechanism processing *.bif files automatically.). This
* information is for information purpuses only and will show up in
* the result of BifItem() as well as in the Describe() output.
*/
virtual bif_item_list CustomBifItems() ;
/**
* Internal function adding an entry point for registering
* auto-generated BiFs.
*/
void AddBifInitFunction(bif_init_func c); void AddBifInitFunction(bif_init_func c);
private: private:
typedef std::list<bif_init_func> bif_init_func_list; typedef std::list<bif_init_func> bif_init_func_list;
plugin::Description description; const char* name;
const char* description;
int version;
int api_version;
component_list components; component_list components;
bif_item_list bif_items; bif_item_list bif_items;
bif_init_func_list bif_inits; bif_init_func_list bif_inits;

View file

@ -50,11 +50,9 @@ BuiltinAnalyzers builtin_analyzers;
void BuiltinAnalyzers::Init() void BuiltinAnalyzers::Init()
{ {
plugin::Description desc; SetName("Core-Analyzers");
desc.name = "Core-Analyzers"; SetDescription("Built-in protocol analyzers");
desc.description = "Built-in protocol analyzers"; SetVersion(BRO_PLUGIN_VERSION_BUILTIN);
desc.version = BRO_PLUGIN_VERSION_BUILTIN;
SetDescription(desc);
DEFINE_ANALYZER("PIA_TCP", PIA_TCP::InstantiateAnalyzer); DEFINE_ANALYZER("PIA_TCP", PIA_TCP::InstantiateAnalyzer);
DEFINE_ANALYZER("PIA_UDP", PIA_UDP::InstantiateAnalyzer); DEFINE_ANALYZER("PIA_UDP", PIA_UDP::InstantiateAnalyzer);

View file

@ -16,7 +16,7 @@
#include "plugin/Plugin.h" #include "plugin/Plugin.h"
BRO_PLUGIN_BEGIN(HTTP) BRO_PLUGIN_BEGIN(HTTP)
BRO_PLUGIN_DESCRIPTION = "HTTP Analyzer"; BRO_PLUGIN_DESCRIPTION("HTTP Analyzer");
BRO_PLUGIN_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer); BRO_PLUGIN_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer);
BRO_PLUGIN_BIF_FILE(events); BRO_PLUGIN_BIF_FILE(events);
BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_BIF_FILE(functions);

View file

@ -4,7 +4,7 @@
#include "SSL.h" #include "SSL.h"
BRO_PLUGIN_BEGIN(SSL) BRO_PLUGIN_BEGIN(SSL)
BRO_PLUGIN_DESCRIPTION = "SSL Analyzer"; BRO_PLUGIN_DESCRIPTION("SSL Analyzer");
BRO_PLUGIN_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer); BRO_PLUGIN_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer);
BRO_PLUGIN_BIF_FILE(events); BRO_PLUGIN_BIF_FILE(events);
BRO_PLUGIN_END BRO_PLUGIN_END

View file

@ -4,7 +4,7 @@
#include "Syslog.h" #include "Syslog.h"
BRO_PLUGIN_BEGIN(Syslog) BRO_PLUGIN_BEGIN(Syslog)
BRO_PLUGIN_DESCRIPTION = "Syslog Analyzer (UDP-only currently)"; BRO_PLUGIN_DESCRIPTION("Syslog Analyzer (UDP-only currently)");
BRO_PLUGIN_ANALYZER("SYSLOG", Syslog_Analyzer::InstantiateAnalyzer); BRO_PLUGIN_ANALYZER("SYSLOG", Syslog_Analyzer::InstantiateAnalyzer);
BRO_PLUGIN_BIF_FILE(events); BRO_PLUGIN_BIF_FILE(events);
BRO_PLUGIN_END BRO_PLUGIN_END

View file

@ -1042,6 +1042,7 @@ static void check_dpd_config_changes()
valdesc.PushIndent(); valdesc.PushIndent();
v->Describe(&valdesc); v->Describe(&valdesc);
#if 0
if ( tag < AnalyzerTag::Error || tag > AnalyzerTag::LastAnalyzer ) if ( tag < AnalyzerTag::Error || tag > AnalyzerTag::LastAnalyzer )
{ {
fprintf(stderr, "Warning: skipped bad analyzer tag: %i\n", tag); fprintf(stderr, "Warning: skipped bad analyzer tag: %i\n", tag);
@ -1049,8 +1050,9 @@ static void check_dpd_config_changes()
} }
last_reST_doc->AddPortAnalysis( last_reST_doc->AddPortAnalysis(
Analyzer::GetTagName((AnalyzerTag::Tag)tag), Analyzer::GetTagName((AnalyzerTag)tag),
valdesc.Description()); valdesc.Description());
#endif
} }
dpd_table->RemoveAll(); dpd_table->RemoveAll();

View file

@ -5,8 +5,14 @@
// Expose C99 functionality from inttypes.h, which would otherwise not be // Expose C99 functionality from inttypes.h, which would otherwise not be
// available in C++. // available in C++.
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS
#endif
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
#endif
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>