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