switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Packets / PacketType.hh
1 // $Id$
2 //
3 // Copyright (C) 2007
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 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief PacketType public header */
30
31 #ifndef HH_SENF_Packets_PacketType_
32 #define HH_SENF_Packets_PacketType_ 1
33
34 // Custom includes
35 #include <iostream>
36 #include "PacketTypes.hh"
37 #include "PacketData.hh"
38 #include "PacketParser.hh"
39 #include "Packet.hh"
40
41 //#include "PacketType.mpp"
42 //-/////////////////////////////////////////////////////////////////////////////////////////////////
43
44 namespace senf {
45
46     /** \brief Helper base-class implementing the PacketType interface
47
48         This helper class maybe used when building a new PacketType. It provides a complete default
49         implementations of this interface. To define a new PacketType, derive from this class and
50         implement the members you want to change.
51
52         \code
53         struct SomePacketType : public senf::PacketTypeBase
54         {
55             typedef senf::ConcretePacket<SomePacketType> packet;
56             typedef SomePacketParser parser;
57
58             static size_type initSize()
59             {
60                 // This value can in most cases be taken from the parser
61                 return senf::init_size<parser>::value;
62             }
63
64             static size_type initHeadSize()
65             {
66                 // optional member. This is only needed, if the packet has header and trailer.
67                 return constant_initial_size_of_header
68             }
69
70             static void init(packet p)
71             {
72                 // Initialize a new packet by e.g. setting some fields. Should call
73                 // the packet parsers init() member
74                 p->init();
75                 p->some_field() = 1;
76             }
77
78             static optional_range nextPacketRange(packet p)
79             {
80                 if (have_next_packet)
81                     // return iterator range delimiting the packet, e.g.:
82                     return range(p.data()+begin_offset, p.data()+end_offset);
83                 else
84                     return no_range();
85             }
86
87             static factory_t nextPacketType(packet p)
88             {
89                 if (have_next_packet && know_next_packet_type)
90                     // \a NextPacket is the \c ConcretePacket instantiation of the next packet
91                     return NextPacket::factory();
92                 else
93                     return no_factory();
94             }
95
96             static void finalize(packet p)
97             {
98                 // optionally complete the packet by generating auto-generated information
99                 // (like checksums)
100             }
101
102             static void dump(packet p, std::ostream & os)
103             {
104                 // Write out a readable representation of the packet for debug purposes
105             }
106         }
107         \endcode
108
109         You may leave out any one of the members (you should however always define the \c
110         packet typedef member)
111
112         \ingroup packet_module
113       */
114     struct PacketTypeBase
115     {
116         typedef Packet packet;
117
118         typedef senf::detail::packet::iterator iterator;
119         typedef senf::detail::packet::const_iterator const_iterator;
120         typedef senf::detail::packet::size_type size_type;
121         typedef senf::detail::packet::difference_type difference_type;
122         typedef senf::detail::packet::byte byte;
123
124         typedef PacketInterpreterBase::range range;
125         typedef PacketInterpreterBase::optional_range optional_range;
126         typedef PacketInterpreterBase::factory_t factory_t;
127
128         static optional_range no_range();
129         static factory_t no_factory();
130         template <class PacketType> static factory_t factory();
131
132         typedef VoidPacketParser parser;
133                                         ///< Parser to parser packet fields
134                                         /**< This typedef has to be set to the parser of the packet
135
136                                              The default is a VoidPacketParser which does not parse
137                                              any field. */
138
139         static size_type initSize();
140                                         ///< Get size of new (empty) packet
141                                         /**< The default implementation returns 0.
142                                              \returns size that needs to be allocated to a newly
143                                              constructed packet */
144
145         static size_type initHeadSize();
146                                         ///< Get size of new (empty) packet header
147                                         /**< This function gives the index within a newly created,
148                                              empty packet where a sub-packet is to be placed.
149
150                                              The default implementation returns initSize().
151
152                                              \implementation Ok, it does not really return
153                                                  initSize(), it returns size_type(-1) which is
154                                                  interpreted to mean initSize(). It can't return
155                                                  initSize since initSize() is not (and can't be
156                                                  since it is static) virtual. */
157
158         static void init(packet p);
159                                         ///< Initialize new packet
160                                         /**< This member is called to initialize a just created new
161                                              packet. The new packet will have a size of at least
162                                              initSize() but the size may well be larger. It is also
163                                              possible for the packet to already have further
164                                              sub-packets.
165
166                                              The default implementation does nothing. */
167
168
169
170         static optional_range nextPacketRange(packet p);
171                                         ///< Get next packet placement
172                                         /**< nextPacketRange returns the iterator range where the
173                                              next packet (header) is placed within the current
174                                              packet.
175
176                                              The default implementation always returns
177                                              <tt>no_range()</tt>.
178
179                                              \returns nextPacketRange must return
180                                              \li <tt>\ref interpreter::range(b,e)</tt> (where \a b
181                                                  and \a e are the iterators delimiting the next
182                                                  packet range) if the packet allows a next
183                                                  header. The returned range is allowed to be empty.
184                                              \li <tt>\ref interpreter::no_range()</tt> (a
185                                                  default constructed \c no_range instance) if
186                                                  no next header is allowed */
187
188         static factory_t nextPacketType(packet p);
189                                         ///< Get type of next packet
190                                         /**< nextPacketType retrieves the type of the next packet
191                                              returning a factory to create that packet.
192
193                                              The default implementation always returns
194                                              <tt>no_factory()</tt>.
195
196                                              \returns factory to create next packet
197                                              \li <tt>interpreter::factory<OtherPacketType>()</tt> if
198                                                  the type of the packet can be determined
199                                              \li <tt>interpreter::no_factory()</tt> if the type of
200                                                  the packet cannot be determined or no next packet
201                                                  is supported */
202
203         static void finalize(packet p);
204                                         ///< Finalize packet
205                                         /**< finalize() will be called to complete a packet after it
206                                              has been modified. This function must calculate any
207                                              checksums, set size fields from the interpreter chain
208                                              etc.
209
210                                              The default implementation does nothing. */
211
212         static void dump(packet p, std::ostream & os);
213                                         ///< Dump packet data in readable form
214                                         /**< The dump() function writes out a complete
215                                              representation of the packet. This is used for most for
216                                              debugging purposes.
217
218                                              The default implementation does nothing. */
219     };
220
221
222     /** \brief Mixin to provide standard implementations for nextPacketRange and nextPacketType
223
224         This mixin class simplifies the definition of simple packets:
225
226         \li The packets consist of three sections: The header, the payload and an optional trailer.
227         \li If the packet has a trailer, both the header and the trailer must have a fixed size.
228
229         This mixin provides the nextPacketRange() member as well as initSize() and init(). If you
230         additionally provide the optional \a Registry argument, PacketTypeMixin provides a simple
231         implementation of nextPacketType().
232
233         When using the PacketTypeMixin, the implementation of a packet is simplified to:
234         \code
235         // Here 'SomeRegistryTag' is optional
236         struct SimplePacketType
237             : public senf::PacketTypeBase,
238               public senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag>
239         {
240             typedef senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag> mixin;
241             typedef senf::ConcretePacket<SimplePacketType> packet;
242             typedef SomePacketParser parser;
243
244             using mixin::nextPacketRange;
245             using mixin::nextPacketType;  // Only if the optional 'Registry' argument is provided
246             using mixin::initSize;
247             using mixin::init;
248
249             static key_t nextPacketKey(packet p)
250             {
251                 // Return the key in the registry under which the next packet
252                 // header is to be found. This member must be given if a Registry argument is
253                 // passed to the PacketTypeMixin template.
254                 return p->typeField();
255             }
256
257             static void finalize(packet p)
258             {
259                 // Set the type field by querying the type of the next packet. This is an
260                 // optional assignment: If the key is not found, the value returned by 'key'
261                 // is an empty optional and the assignment will be skipped.
262                 p->typeField << key(p.next(senf::nothrow));
263
264                 // optionally complete the packet by generating auto-generated information
265                 // (like checksums)
266             }
267
268             static void dump(packet p, std::ostream & os)
269             {
270                 // Write out a readable representation of the packet for debug purposes
271             }
272
273             static interpreter::size_type initHeadSize()
274             {
275                 // This member is optional. It returns the \e fixed header size if the packet has a
276                 // trailer.
277                 return header_size;
278             }
279
280         };
281         \endcode
282
283         Most of the members are optional, which reduces the minimal implementation of a packet to:
284
285         \code
286         struct SimplePacketType
287             : public senf::PacketTypeBase,
288               public senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag>
289         {
290             typedef senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag> mixin;
291             typedef senf::ConcretePacket<SimplePacketType> packet;
292             typedef SomePacketParser parser;
293
294             using mixin::nextPacketRange;
295             using mixin::nextPacketType;
296             using mixin::initSize;
297             using mixin::init;
298
299             // 'typeField()' is one of the fields defined in the parser which holds
300             // the next-header information
301
302             static key_t nextPacketKey(packet p) { return p->typeField(); }
303             static void finalize(packet p)       { p->typeField() << key(p.next(senf::nothrow)); }
304
305             static void dump(packet p) {
306                 // should always be implemented although optional
307             }
308         };
309         \endcode
310
311         \ingroup packet_module
312      */
313     template <class Self, class Registry=void>
314     class PacketTypeMixin
315     {
316     public:
317         typedef typename Registry::key_t key_t;
318         typedef boost::optional<key_t> optional_key_t;
319
320         static optional_key_t key (Packet const & p); ///< Find key of packet from registry
321                                         /**< key() will query the registry to find the key of the
322                                              given packet. Whereas \c nextPacketKey() as implemented
323                                              by the mixin user will provide the registry key of the
324                                              next packet from information stored in the current
325                                              packets header, the key() member will look up the type
326                                              of packet \a p in the registry and return it's
327                                              key.
328
329                                              If either \a p is an in - valid() packet or the packet
330                                              type is not found in the registry, the returned
331                                              optional value will be empty. */
332
333         static PacketTypeBase::factory_t lookup (key_t key); ///< Lookup the key in the registry
334                                         /**< lookup() will query the registry and find the factory
335                                              for the given key. If the key cannot be found,
336                                              no_factory() will be returned. */
337
338         ///\name PacketType interface implementation
339         //\{
340
341         static PacketInterpreterBase::optional_range nextPacketRange (ConcretePacket<Self> const & p);
342         static PacketInterpreterBase::factory_t      nextPacketType  (ConcretePacket<Self> const & p);
343         static PacketInterpreterBase::size_type      initSize        ();
344         static void                                  init            (ConcretePacket<Self> const & p);
345
346         //\}
347     };
348
349 #   ifndef DOXYGEN
350
351     template <class Self>
352     class PacketTypeMixin<Self,void>
353     {
354     public:
355         static PacketInterpreterBase::optional_range nextPacketRange (ConcretePacket<Self> const & p);
356         static PacketInterpreterBase::size_type      initSize        ();
357         static void                                  init            (ConcretePacket<Self> const & p);
358     };
359
360 #   endif
361
362 }
363
364 //-/////////////////////////////////////////////////////////////////////////////////////////////////
365 #endif
366 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketType_i_)
367 #define HH_SENF_Packets_PacketType_i_
368 #include "PacketType.cci"
369 #include "PacketType.ct"
370 #include "PacketType.cti"
371 #endif
372
373 \f
374 // Local Variables:
375 // mode: c++
376 // fill-column: 100
377 // c-file-style: "senf"
378 // indent-tabs-mode: nil
379 // ispell-local-dictionary: "american"
380 // compile-command: "scons -u test"
381 // comment-column: 40
382 // End:
383