2c6fd01b9524d468d2f5b9bb25c939fb3d70b5df
[senf.git] / senf / 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_SENF_Packets_PacketType_
27 #define HH_SENF_Packets_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:
220
221         \li The packets consist of three sections: The header, the payload and an optional trailer.
222         \li If the packet has a trailer, both the header and the trailer must have a fixed size.
223
224         This mixin provides the nextPacketRange() member as well as initSize() and init(). If you
225         additionally provide the optional \a Registry argument, PacketTypeMixin provides a simple
226         implementation of nextPacketType().
227
228         When using the PacketTypeMixin, the implementation of a packet is simplified to:
229         \code
230         // Here 'SomeRegistryTag' is optional
231         struct SimplePacketType
232             : public senf::PacketTypeBase,
233               public senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag>
234         {
235             typedef senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag> mixin;
236             typedef senf::ConcretePacket<SimplePacketType> packet;
237             typedef SomePacketParser parser;
238
239             using mixin::nextPacketRange;
240             using mixin::nextPacketType;  // Only if the optional 'Registry' argument is provided
241             using mixin::initSize;
242             using mixin::init;
243
244             static key_t nextPacketKey(packet p)
245             {
246                 // Return the key in the registry under which the next packet
247                 // header is to be found. This member must be given if a Registry argument is
248                 // passed to the PacketTypeMixin template.
249                 return p->typeField();
250             }
251
252             static void finalize(packet p)
253             {
254                 // Set the type field by querying the type of the next packet. This is an
255                 // optional assignment: If the key is not found, the value returned by 'key'
256                 // is an empty optional and the assignment will be skipped.
257                 p->typeField << key(p.next(senf::nothrow));
258
259                 // optionally complete the packet by generating auto-generated information
260                 // (like checksums)
261             }
262
263             static void dump(packet p, std::ostream & os)
264             {
265                 // Write out a readable representation of the packet for debug purposes
266             }
267
268             static interpreter::size_type initHeadSize()
269             {
270                 // This member is optional. It returns the \e fixed header size if the packet has a
271                 // trailer.
272                 return header_size;
273             }
274
275         };
276         \endcode
277
278         Most of the members are optional, which reduces the minimal implementation of a packet to:
279
280         \code
281         struct SimplePacketType
282             : public senf::PacketTypeBase,
283               public senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag>
284         {
285             typedef senf::PacketTypeMixin<SimplePacketType, SomeRegistryTag> mixin;
286             typedef senf::ConcretePacket<SimplePacketType> packet;
287             typedef SomePacketParser parser;
288
289             using mixin::nextPacketRange;
290             using mixin::nextPacketType;
291             using mixin::initSize;
292             using mixin::init;
293
294             // 'typeField()' is one of the fields defined in the parser which holds
295             // the next-header information
296
297             static key_t nextPacketKey(packet p) { return p->typeField(); }
298             static void finalize(packet p)       { p->typeField() << key(p.next(senf::nothrow)); }
299
300             static void dump(packet p) {
301                 // should always be implemented although optional
302             }
303         };
304         \endcode
305
306         \ingroup packet_module
307      */
308     template <class Self, class Registry=void>
309     class PacketTypeMixin
310     {
311     public:
312         typedef typename Registry::key_t key_t;
313         typedef boost::optional<key_t> optional_key_t;
314
315         static optional_key_t key (Packet const & p); ///< Find key of packet from registry
316                                         /**< key() will query the registry to find the key of the
317                                              given packet. Whereas \c nextPacketKey() as implemented
318                                              by the mixin user will provide the registry key of the
319                                              next packet from information stored in the current
320                                              packets header, the key() member will look up the type
321                                              of packet \a p in the registry and return it's
322                                              key.
323
324                                              If either \a p is an in - valid() packet or the packet
325                                              type is not found in the registry, the returned
326                                              optional value will be empty. */
327
328         static PacketTypeBase::factory_t lookup (key_t key); ///< Lookup the key in the registry
329                                         /**< lookup() will query the registry and find the factory
330                                              for the given key. If the key cannot be found,
331                                              no_factory() will be returned. */
332
333         ///\name PacketType interface implementation
334         ///@{
335
336         static PacketInterpreterBase::optional_range nextPacketRange (ConcretePacket<Self> const & p);
337         static PacketInterpreterBase::factory_t      nextPacketType  (ConcretePacket<Self> const & p);
338         static PacketInterpreterBase::size_type      initSize        ();
339         static void                                  init            (ConcretePacket<Self> const & p);
340
341         ///@}
342     };
343
344 #   ifndef DOXYGEN
345
346     template <class Self>
347     class PacketTypeMixin<Self,void>
348     {
349     public:
350         static PacketInterpreterBase::optional_range nextPacketRange (ConcretePacket<Self> const & p);
351         static PacketInterpreterBase::size_type      initSize        ();
352         static void                                  init            (ConcretePacket<Self> const & p);
353     };
354
355 #   endif
356
357 }
358
359 ///////////////////////////////hh.e////////////////////////////////////////
360 #endif
361 #if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_PacketType_i_)
362 #define HH_SENF_Packets_PacketType_i_
363 #include "PacketType.cci"
364 #include "PacketType.ct"
365 #include "PacketType.cti"
366 #endif
367
368 \f
369 // Local Variables:
370 // mode: c++
371 // fill-column: 100
372 // c-file-style: "senf"
373 // indent-tabs-mode: nil
374 // ispell-local-dictionary: "american"
375 // compile-command: "scons -u test"
376 // comment-column: 40
377 // End:
378