7792653700b9c8fec866602cfd5f6d17e661c7be
[senf.git] / senf / Packets / GenericTLV.hh
1 // $Id$
2 //
3 // Copyright (C) 2009
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Thorsten Horstmann <tho@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief GenericTLV public header */
25
26 #ifndef HH_SENF_Packets_GenericTLV_
27 #define HH_SENF_Packets_GenericTLV_ 1
28
29 // Custom includes
30 #include <boost/ptr_container/ptr_map.hpp>
31 #include <senf/Packets/Packets.hh>
32 #include <senf/Utils/type_traits.hh>
33 #include <senf/Utils/singleton.hh>
34
35 //#include "GenericTLV.hh.mpp"
36 //-/////////////////////////////////////////////////////////////////////////////////////////////////
37
38 namespace senf {
39
40     /** \brief Base class for generic TLV parsers
41
42        This abstract base class can be used to define generic TLV parsers. The following
43        class structure is assumed:
44        \image html GenericTLV.png
45
46         Your TLVParser base class has to define a \c type and a \c length field:
47         \code
48         struct MyTLVParserBase : public senf::PacketParserBase
49         {
50         #   include SENF_PARSER()
51             SENF_PARSER_FIELD    ( type,   senf::UInt8Parser );
52             SENF_PARSER_FIELD_RO ( length, senf::UInt8Parser );
53             SENF_PARSER_FINALIZE ( MyTLVParserBase           );
54         };
55         \endcode
56
57         Your concrete TLV parsers will inherit from this base class and have to define a specific
58         value field and a \c typeId member:
59         \code
60         struct MyConcreteTLVParser : public MyTLVParserBase
61         {
62         #   include SENF_PARSER()
63             SENF_PARSER_INHERIT  ( MyTLVParserBase             );
64             SENF_PARSER_FIELD    ( myValue, senf::UInt32Parser );
65             SENF_PARSER_FINALIZE ( MyConcreteTLVParser         );
66
67             SENF_PARSER_INIT() {
68                 type() = typeId;
69                 length_() = 4;
70             }
71             static const type_t::value_type typeId = 0x42;
72         };
73         \endcode
74
75         With GenericTLVParserBase you can define a generic parser class which provides
76         members to access the value data and and to cast the parser to a concrete tlv
77         parser:
78         \code
79         struct MyGenericTLVParser : public senf::GenericTLVParserBase<MyTLVParserBase>
80         {
81             typedef senf::GenericTLVParserBase<MyTLVParserBase> base;
82             MyGenericTLVParser(data_iterator i, state_type s) : base(i,s) {}
83
84             // members for your generic TLV parser...
85         };
86         \endcode
87
88         If your generic TLV parser just inherits from GenericTLVParserBase and doesn't
89         add any additional functionality you can use a simple \c typedef as well:
90         \code
91         typedef senf::GenericTLVParserBase<MyTLVParserBase> MyGenericTLVParser;
92         \endcode
93
94         This generic tlv parser can now be used for example in a list:
95         \code
96         class MyTestPacketParser : public senf::PacketParserBase
97         {
98         #   include SENF_PARSER()
99             SENF_PARSER_FIELD_RO ( list_length, senf::UInt8Parser );
100             SENF_PARSER_LIST     ( tlv_list, list_length, MyGenericTLVParser );
101             SENF_PARSER_FINALIZE ( MyTestPacketParser );
102         };
103         \endcode
104
105         Now, you can access the TLV parsers in the list in a generic way or you
106         can cast the parsers to some concrete tlv parser:
107         \code
108         MyTestPacket p (...
109         typedef MyTestPacket::Parser::tlv_list_t::container container_t;
110         container_t tlvContainer (p->tlv_list() );
111         optContainer_t::iterator listIter (tlvContainer.begin());
112
113         // listIter points to a MyGenericTLVParser, so you have generic access:
114         listIter->type() = 0x42;
115         listIter->value( someRangeOfValueData);
116
117         // cast to an instance of MyConcreteTLVParser:
118         if (listIter->is<MyConcreteTLVParser>()) {
119             MyConcreteTLVParser concreteTLVParser ( listIter->as<MyConcreteTLVParser>());
120             concreteTLVParser.myValue() = 0xabababab;
121         }
122
123         // add a MyConcreteTLV to the list:
124         MyConcreteTLVParser tlv ( tlvContainer.push_back_space().init<MyConcreteTLVParser>());
125         tlv.myValue() = 0xffff;
126         \endcode
127
128         \see
129             IPv6GenericOptionParser, WLANGenericInfoElementParser, MIHGenericTLVParser \n
130             GenericTLVParserRegistry
131      */
132     template <class Base>
133     class GenericTLVParserBase : public Base
134     {
135     public:
136         GenericTLVParserBase(senf::PacketParserBase::data_iterator i, senf::PacketParserBase::state_type s)
137             : Base(i,s) {}
138
139         senf::PacketParserBase::size_type bytes() const;
140         void init() const;
141
142         template <class Parser>
143         Parser init();
144
145         template <class Parser>
146         Parser as() const;
147
148         template <class Parser>
149         bool is() const;
150
151         senf::PacketInterpreterBase::range value() const;
152
153         void dump(std::ostream & os) const;
154
155 #ifndef DOXYGEN
156         template<class ForwardReadableRange>
157         void value(ForwardReadableRange const & val,
158                 typename boost::disable_if<senf::is_pair<ForwardReadableRange> >::type * = 0);
159
160         template<class First, class Second>
161         void value(std::pair<First, Second> const & val,
162                 typename boost::disable_if<boost::is_convertible<First, typename Base::type_t::value_type> >::type * = 0);
163
164         template <class Type, class ForwardReadableRange>
165         void value(std::pair<Type, ForwardReadableRange> const & val,
166                 typename boost::enable_if<boost::is_convertible<Type, typename Base::type_t::value_type> >::type * = 0);
167 #else
168         template<class ForwardReadableRange>
169         void value(ForwardReadableRange const & val);
170
171         template <class ForwardReadableRange>
172         void value(std::pair<typename Base::type_t::value_type, ForwardReadableRange> const & val);
173 #endif
174
175     private:
176         template<class ForwardReadableRange>
177         void value_(ForwardReadableRange const &range);
178
179         Base & self();
180         Base const & self() const;
181     };
182
183
184     namespace detail {
185         template <class BaseParser>
186         struct GenericTLVParserRegistry_EntryBase {
187             virtual ~GenericTLVParserRegistry_EntryBase() {}
188             virtual void dump(GenericTLVParserBase<BaseParser> const & parser, std::ostream & os) const = 0;
189             virtual PacketParserBase::size_type bytes(GenericTLVParserBase<BaseParser> const & parser) const = 0;
190         };
191
192         template <class BaseParser, class Parser>
193         struct GenericTLVParserRegistry_Entry
194             : GenericTLVParserRegistry_EntryBase<BaseParser>
195         {
196             virtual void dump(GenericTLVParserBase<BaseParser> const & parser, std::ostream & os) const;
197             virtual PacketParserBase::size_type bytes(GenericTLVParserBase<BaseParser> const & parser) const;
198         };
199
200         //Helper Functor for STL-compatible predicate (E.g. find_if, for_each ...)
201         template <class BaseParser, class Parser>
202         class Predicate
203         {
204             public:
205                 bool operator() (BaseParser const &p) const {
206                     return p.template is<Parser>();
207                 }
208         };
209     }
210
211     /** \brief TLV parser registration facility
212
213         The %GenericTLVParserRegistry provides a generic facility to globally register concrete
214         TLV parser by the type value. The concrete TLV parser must therefore provide a \c typeId
215         member. See GenericTLVParserBase for details about the assumed class structure.
216
217         Every registry is identified by the base tlv parser class. Parsers can be registered
218         statically only:
219         \code
220         GenericTLVParserRegistry<MyTLVParserBase>::RegistrationProxy<ConcreteTLVParser>
221             registerConcreteTLVParser;
222         \endcode
223         This global variable declaration will register ConcreteTLVParser. The variable
224         registerConcreteTLVParser is a dummy. It's only function is to force the call of
225         it's constructor during global construction time. This static registration only
226         works when the symbol is included into the final binary.
227
228         To simplify the registration the \ref SENF_PACKET_TLV_REGISTRY_REGISTER macro can be used.
229         The \c ConreteTLVParser must therefore provide a \c Registry typedef pointing to the
230         %GenericTLVParserRegistry; typically you put this typedef to the TLVBaseParser class.
231         \code
232         struct MyTLVParserBase : public senf::PacketParserBase
233         {
234             ...
235             typedef GenericTLVParserRegistry<MyTLVParserBase> Registry;
236         };
237         struct MyConcreteTLVParser : public MyTLVParserBase
238         {
239             ....
240             static const type_t::value_type typeId = 0x42;
241             void dump(std::ostream & os) const;
242         };
243
244         // register MyConcreteTLVParser to the MyTLVParserBase-Registry with the type id 0x42:
245         SENF_PACKET_TLV_REGISTRY_REGISTER( MyConcreteTLVParser );
246         \endcode
247
248         The registry provides a dump() member to dump an instance of a generic TLV parser.
249         If the type value of the given TLV parser is registered the generic tlv will be
250         casted to the registered concrete TLV parser and the dump member from this parser
251         will be called.
252
253         \see
254             GenericTLVParserBase for the general TLV class structure \n
255             IPv6OptionParser::Registry, WLANInfoElementParser::Registry,
256             MIHBaseTLVParser::Registry
257      */
258     template <class BaseParser, class Keytype = typename BaseParser::type_t::value_type>
259     class GenericTLVParserRegistry
260         : public senf::singleton<GenericTLVParserRegistry<BaseParser,Keytype> >
261     {
262         typedef boost::ptr_map<Keytype,
263             detail::GenericTLVParserRegistry_EntryBase<BaseParser> > Map;
264         Map map_;
265
266         GenericTLVParserRegistry() {};
267     public:
268         using senf::singleton<GenericTLVParserRegistry<BaseParser,Keytype> >::instance;
269         friend class senf::singleton<GenericTLVParserRegistry<BaseParser,Keytype> >;
270
271         template <class PacketParser>
272         struct RegistrationProxy {
273             RegistrationProxy();
274         };
275
276         template <typename Parser>
277         void registerParser();
278
279         typedef GenericTLVParserBase<BaseParser> GenericTLVParser;
280
281         bool isRegistered(GenericTLVParserBase<BaseParser> const & parser) const;
282         bool isRegistered(Keytype const & key) const;
283
284         void dump(GenericTLVParser const & parser, std::ostream & os) const;
285         void dump(GenericTLVParser const & parser, Keytype const & key, std::ostream & os) const;
286
287         PacketParserBase::size_type bytes(GenericTLVParser const & parser) const;
288         PacketParserBase::size_type bytes(GenericTLVParser const & parser, Keytype const & key) const;
289     };
290
291     struct TLVParserNotRegisteredException : public senf::Exception
292     {
293         TLVParserNotRegisteredException() : senf::Exception("tlv parser not registered") {}
294     };
295
296
297     /** \brief Statically add an entry to a TLV parser registry
298
299         This macro will declare an anonymous global variable in such a way, that constructing
300         this variable will register the given tlv parser.
301
302         \hideinitializer
303         \see senf::GenericTLVParserRegistry
304      */
305 #   define SENF_PACKET_TLV_REGISTRY_REGISTER( ConreteTLVParser )                \
306         namespace {                                                             \
307             ConreteTLVParser::Registry::RegistrationProxy<ConreteTLVParser>     \
308                     BOOST_PP_CAT(tlvparserRegistration_, __LINE__);             \
309         }
310
311 }
312
313 //-/////////////////////////////////////////////////////////////////////////////////////////////////
314 //#include "GenericTLV.cci"
315 #include "GenericTLV.ct"
316 #include "GenericTLV.cti"
317 #endif
318
319 \f
320 // Local Variables:
321 // mode: c++
322 // fill-column: 100
323 // comment-column: 40
324 // c-file-style: "senf"
325 // indent-tabs-mode: nil
326 // ispell-local-dictionary: "american"
327 // compile-command: "scons -u test"
328 // End: