Utils: Implement IpChecksum helper class
[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 
218         and/or trailers. For this type of Packet, this mixin provides the nextPacketRange() 
219         member. If you additionally provide the optional \a Registry argument, PacketTypeMixin 
220         provides a simple implementation of nextPacketType. When using the PacketTypeMixin, the 
221         implementation of a 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 p->typeField();
270             }
271
272             static void finalize(packet p)
273             {
274                 // Set the type field by querying the type of the next packet. This is an 
275                 // optional assignment: If the key is not found, the value returned by 'key'
276                 // is an empty optional and the assignment will be skipped.
277                 p->typeField << key(p.next());
278
279                 // optionally complete the packet by generating auto-generated information
280                 // (like checksums)
281             }
282
283             static void dump(packet p, std::ostream & os)
284             {
285                 // Write out a readable representation of the packet for debug purposes
286             }
287         };
288         \endcode
289
290         Most of the members are optional, which reduces the implementation of a fixed-sized header
291         packet with no trailer and a simple next-packet header to
292
293         \code
294         struct SimplePacketType 
295             : public senf::PacketTypeBase
296               public senf:PacketTypeMixin<SimplePacketType, SomeRegistryTag>
297         {
298             typedef senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag> mixin;
299             typedef senf::ConcretePacket<SimplePacketType> packet;
300             typedef SomePacketParser parser;
301         
302             using mixin::nextPacketRange;
303             using mixin::nextPacketType;            
304             using mixin::initSize;
305             using mixin::init;         
306
307             static registry_key_t nextPacketKey(packet p)
308             { return p->typeField(); }
309         };
310         \endcode
311
312         If needed, you may additionally add a \c finalize() member. You also should add a \c dump()
313         member to help debugging but both members are optional.
314
315         \ingroup packet_module
316      */
317     template <class Self, class Registry=void>
318     class PacketTypeMixin
319     {
320     public:
321         typedef typename Registry::key_t registry_key_t;
322         typedef boost::optional<registry_key_t> optional_registry_key_t;
323
324         static optional_registry_key_t key (Packet p); ///< Find key of packet from registry
325                                         /**< key() will query the registry to find the key of the
326                                              given packet. Whereas \c nextPacketKey() as implemented
327                                              by the mixin user will provide the registry key of the
328                                              next packet from information stored in the current
329                                              packets header, the key() member will look up the type
330                                              of packet \a p in the registry and return it's
331                                              key. 
332                                              
333                                              If either \a p is an in - valid() packet or the packet
334                                              type is not found in the registry, the returned
335                                              optional value will be empty. */
336
337         ///@{
338         ///\name PacketType interface implementation
339
340         static PacketInterpreterBase::optional_range nextPacketRange (Packet p);
341         static PacketInterpreterBase::factory_t      nextPacketType  (Packet p);
342         static PacketInterpreterBase::size_type      initSize        ();
343         static void                                  init            (Packet p);
344         
345         ///@}
346     };
347
348 #   ifndef DOXYGEN
349
350     template <class Self>
351     class PacketTypeMixin<Self,void>
352     {
353     public:
354         static PacketInterpreterBase::optional_range nextPacketRange (Packet p);
355         static PacketInterpreterBase::size_type      initSize        ();
356         static void                                  init            (Packet p);
357     };
358
359 #   endif
360
361 }
362
363 ///////////////////////////////hh.e////////////////////////////////////////
364 #endif
365 #if !defined(SENF_PACKETS_DECL_ONLY) && !defined(HH_PacketType_i_)
366 #define HH_PacketType_i_
367 #include "PacketType.cci"
368 //#include "PacketType.ct"
369 #include "PacketType.cti"
370 #endif
371
372 \f
373 // Local Variables:
374 // mode: c++
375 // fill-column: 100
376 // c-file-style: "senf"
377 // indent-tabs-mode: nil
378 // ispell-local-dictionary: "american"
379 // compile-command: "scons -u test"
380 // comment-column: 40
381 // End:
382