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