X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=senf%2FPackets%2FGenericTLV.hh;h=b1298e0ce66dbe5bedde2affc29e649d17950077;hb=4a99bad0289a65567e85cb51bd357a34562b2c04;hp=894d728c026557f20f6120be71afbc72c0ff98f0;hpb=a79c5e98760ea8232c13d8266eb7ca0ac5cdefd3;p=senf.git diff --git a/senf/Packets/GenericTLV.hh b/senf/Packets/GenericTLV.hh index 894d728..b1298e0 100644 --- a/senf/Packets/GenericTLV.hh +++ b/senf/Packets/GenericTLV.hh @@ -27,14 +27,108 @@ #define HH_SENF_Packets_GenericTLV_ 1 // Custom includes +#include #include #include +#include //#include "GenericTLV.hh.mpp" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { + /** \brief Base class for generic TLV parsers + + This abstract base class can be used to define generic TLV parsers. The following + class structure is assumed: + \image html GenericTLV.png + + Your TLVParser base class has to define a \c type and a \c length field: + \code + struct MyTLVParserBase : public senf::PacketParserBase + { + # include SENF_PARSER() + SENF_PARSER_FIELD ( type, senf::UInt8Parser ); + SENF_PARSER_FIELD_RO ( length, senf::UInt8Parser ); + SENF_PARSER_FINALIZE ( MyTLVParserBase ); + }; + \endcode + + Your concrete TLV parsers will inherit from this base class and have to define a specific + value field and a \c typeId member: + \code + struct MyConcreteTLVParser : public MyTLVParserBase + { + # include SENF_PARSER() + SENF_PARSER_INHERIT ( MyTLVParserBase ); + SENF_PARSER_FIELD ( myValue, senf::UInt32Parser ); + SENF_PARSER_FINALIZE ( MyConcreteTLVParser ); + + SENF_PARSER_INIT() { + type() = typeId; + length_() = 4; + } + static const type_t::value_type typeId = 0x42; + }; + \endcode + + With GenericTLVParserBase you can define a generic parser class which provides + members to access the value data and and to cast the parser to a concrete tlv + parser: + \code + struct MyGenericTLVParser : public senf::GenericTLVParserBase + { + typedef senf::GenericTLVParserBase base; + MyGenericTLVParser(data_iterator i, state_type s) : base(i,s) {} + + // members for your generic TLV parser... + }; + \endcode + + If your generic TLV parser just inherits from GenericTLVParserBase and doesn't + add any additional functionality you can use a simple \c typedef as well: + \code + typedef senf::GenericTLVParserBase MyGenericTLVParser; + \endcode + + This generic tlv parser can now be used for example in a list: + \code + class MyTestPacketParser : public senf::PacketParserBase + { + # include SENF_PARSER() + SENF_PARSER_FIELD_RO ( list_length, senf::UInt8Parser ); + SENF_PARSER_LIST ( tlv_list, list_length, MyGenericTLVParser ); + SENF_PARSER_FINALIZE ( MyTestPacketParser ); + }; + \endcode + + Now, you can access the TLV parsers in the list in a generic way or you + can cast the parsers to some concrete tlv parser: + \code + MyTestPacket p (... + typedef MyTestPacket::Parser::tlv_list_t::container container_t; + container_t tlvContainer (p->tlv_list() ); + optContainer_t::iterator listIter (tlvContainer.begin()); + + // listIter points to a MyGenericTLVParser, so you have generic access: + listIter->type() = 0x42; + listIter->value( someRangeOfValueData); + + // cast to an instance of MyConcreteTLVParser: + if (listIter->is()) { + MyConcreteTLVParser concreteTLVParser ( listIter->as()); + concreteTLVParser.myValue() = 0xabababab; + } + + // add a MyConcreteTLV to the list: + MyConcreteTLVParser tlv ( tlvContainer.push_back_space().init()); + tlv.myValue() = 0xffff; + \endcode + + \see + IPv6GenericOptionParser, WLANGenericInfoElementParser, MIHGenericTLVParser \n + GenericTLVParserRegistry + */ template class GenericTLVParserBase : public Base { @@ -49,13 +143,16 @@ namespace senf { Parser init(); template - Parser as(); + Parser as() const; template - bool is(); + bool is() const; senf::PacketInterpreterBase::range value() const; + void dump(std::ostream & os) const; + +#ifndef DOXYGEN template void value(ForwardReadableRange const & val, typename boost::disable_if >::type * = 0); @@ -67,13 +164,138 @@ namespace senf { template void value(std::pair const & val, typename boost::enable_if >::type * = 0); - +#else + template + void value(ForwardReadableRange const & val); + + template + void value(std::pair const & val); +#endif + private: template void value_(ForwardReadableRange const &range); + + Base & self(); + Base const & self() const; }; -} + + + namespace detail { + template + struct GenericTLVParserRegistry_EntryBase { + virtual void dump(GenericTLVParserBase const & parser, std::ostream & os) const = 0; + }; + + template + struct GenericTLVParserRegistry_Entry + : GenericTLVParserRegistry_EntryBase + { + virtual void dump(GenericTLVParserBase const & parser, std::ostream & os) const; + }; + + //Helper Functor for STL-compatible predicate (E.g. find_if, for_each ...) + template + class Predicate + { + public: + const bool operator() (BaseParser const &p) const{ + return p.template is(); + } + }; + } + + /** \brief TLV parser registration facility + The %GenericTLVParserRegistry provides a generic facility to globally register concrete + TLV parser by the type value. The concrete TLV parser must therefore provide a \c typeId + member. See GenericTLVParserBase for details about the assumed class structure. + + Every registry is identified by the base tlv parser class. Parsers can be registered + statically only: + \code + GenericTLVParserRegistry::RegistrationProxy + registerConcreteTLVParser; + \endcode + This global variable declaration will register ConcreteTLVParser. The variable + registerConcreteTLVParser is a dummy. It's only function is to force the call of + it's constructor during global construction time. This static registration only + works when the symbol is included into the final binary. + + To simplify the registration the \ref SENF_PACKET_TLV_REGISTRY_REGISTER macro can be used. + The \c ConreteTLVParser must therefore provide a \c Registry typedef pointing to the + %GenericTLVParserRegistry; typically you put this typedef to the TLVBaseParser class. + \code + struct MyTLVParserBase : public senf::PacketParserBase + { + ... + typedef GenericTLVParserRegistry Registry; + }; + struct MyConcreteTLVParser : public MyTLVParserBase + { + .... + static const type_t::value_type typeId = 0x42; + void dump(std::ostream & os) const; + }; + + // register MyConcreteTLVParser to the MyTLVParserBase-Registry with the type id 0x42: + SENF_PACKET_TLV_REGISTRY_REGISTER( MyConcreteTLVParser ); + \endcode + + The registry provides a dump() member to dump an instance of a generic TLV parser. + If the type value of the given TLV parser is registered the generic tlv will be + casted to the registered concrete TLV parser and the dump member from this parser + will be called. Otherwise the generic TLV parser will be dumped in a generic way + (hexdump of the value). + + \see + GenericTLVParserBase for the general TLV class structure \n + IPv6OptionParser::Registry, WLANInfoElementParser::Registry, + MIHBaseTLVParser::Registry + */ + template + class GenericTLVParserRegistry + : public senf::singleton > + { + typedef boost::ptr_map > Map; + Map map_; + + GenericTLVParserRegistry() {}; + public: + using senf::singleton >::instance; + friend class senf::singleton >; + + template + struct RegistrationProxy { + RegistrationProxy(); + }; + + template + void registerParser(); + + bool isRegistered(GenericTLVParserBase const & parser) const; + bool isRegistered(Keytype const & key) const; + + void dump(GenericTLVParserBase const & parser, std::ostream & os) const; + void dump(GenericTLVParserBase const & parser, Keytype const & key, std::ostream & os) const; + }; + + /** \brief Statically add an entry to a TLV parser registry + + This macro will declare an anonymous global variable in such a way, that constructing + this variable will register the given tlv parser. + + \hideinitializer + \see senf::GenericTLVParserRegistry + */ +# define SENF_PACKET_TLV_REGISTRY_REGISTER( ConreteTLVParser ) \ + namespace { \ + ConreteTLVParser::Registry::RegistrationProxy \ + BOOST_PP_CAT(tlvparserRegistration_, __LINE__); \ + } + +} ///////////////////////////////hh.e//////////////////////////////////////// //#include "GenericTLV.cci"