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