4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 // Stefan Bund <stefan.bund@fokus.fraunhofer.de>
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.
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.
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.
23 // TODO: Implement assign() method akin to reinterpret(). However,
24 // instead of using the data already present, assign() will replace
25 // the date of the current packet with the given Packet.
27 // TODO: Implement wrapping-constructor. Somehow we want to have a
28 // constructor, which allows creating a chain of packet interpreters
29 // with as little overhead as possible.
31 // TODO: Document the additional concrete Packet facade requirements
32 // explicitly and not only within the Parser requirements (check(),
33 // bytes() and min_bytes() members ...)
35 // TODO: Implement special container replacing vector which manages
36 // some headroom to allow efficient insertion of elements at the
37 // beginning. This really is just another type of deque
41 /** \mainpage The SENF Packet Library
43 \section arch Overall Architecture
45 The general Architecture of the Packet Framework (pkf for short)
46 is seperated into two components: The basic packet handling and
49 The basic packet handling implements a packet interpreter
50 chain. Every packet is represented as a chain of interpreters
51 where each interpreter is a facade looking into the same
52 packet. Each interpreter will interpret a specific header of a
53 packet. For example, an ethernet frame might have an interpreter
54 chain consisting of EthernetPacket, IPPacket, UDPPacket and
55 DataPacket. Each of these interpreters will interpret a section of
56 the raw data bytes. The interpreter ranges overlap since every
57 packet also includes it's payload.
59 The parser framework is used to interpret the raw bytes of a
60 specific packet and parse the values present in that packet. For
61 example, Parse_Ethernet will parse the ethernet source MAC,
62 destination MAC and ethertype given any random access iterator to
63 the first byte of the ethernet frame. Parsers are extremely light
64 classes. They are temporary classes passed around by value. In
65 most cases, they are just comprised of a single pointer adorned
66 with type information.
68 \section handling Packet Handling
70 The packet handling is implemented within
71 satcom::pkf::Packet. This class is the baseclass to all packet
72 interpreter facades. To implement a new packet type, publically
73 derive from satcom::pkf::Packet and implement the virtual
74 interface (see the class documentation for details).
76 \section framework Parser Framework
78 The parser framework provides an abstract framwork to parse packet
79 oriented data. A Parser is a template class taking an arbitrary
80 iterator as input and allowing random access to data elements of
81 the interpreted type, like source and destination MAC of an
82 ethernet frame. The parser framework is to be used hierarchically
83 and recursively, the parser methods should return further parsers
84 which can return further parsers and so on.
86 The parser framework contains some basic parsers to be used to
87 build up more complex parsers:
89 - ParseInt.hh: Lots of parsers for integer numbers like
90 satcom::pkf::Parse_UInt8, for integer bitfields like
91 satcom::pkf::Parse_UIntField and satcom::pkf::Parse_Flag to
94 - ParseArray.hh: The satcom::pkf::Parse_Array parser to parse
95 arbitrary fixed-size arrays of fixed-size elements (that is
98 - ParseVec.hh: The satcom::pkf::Parse_Vector parser to parse
99 dynamically sized arrays of fixed-size elements (that is
102 See satcom::pkf::ParserBase for further information.
104 \section stuff Other Utilities
106 The pkf also comprises some additional utilities to support the
107 development of packet classes.
109 The satcom::pkf::PacketRegistry implements a registry of packets
110 keyed by an arbitrary type. The registry is used to find a packet
111 type given some kind of id (like the ethertype value from the
112 ethernet header). Together with it's support classes (especially
113 satcom::pkf::PacketRegistryMixin) this class greatly simplifies
114 implementing the needed table lookups.
118 \brief Main packet interface
125 #include <boost/utility.hpp> // for boost::noncopyable
126 #include <boost/cstdint.hpp>
127 #include <boost/shared_ptr.hpp>
128 #include <boost/intrusive_ptr.hpp>
133 #include "Packet.mpp"
134 // ////////////////////////////hh.p////////////////////////////////////////
139 namespace impl { template <class OtherPacket> class PkReg_EntryImpl; }
140 namespace impl { class PacketImpl; }
142 /** \brief Basic interface to all packet facades
144 \section packet_overview Overview
146 This class is the base class of all Packets. It implements the
147 generic Packet interface and provides the packet management
148 framework. satcom::pkf::Packet manages the necessary memory
149 resources and controlls the chain of packet interpreters.
151 The Packet user always interfaces with the pkf via a Packet
152 derived class. This is the only external entity ever held by a
153 library user. The interface is implemented using a reference
154 counted smart pointer, so resource management is quasi
157 \image html "../../structure.png" Overview
159 Internally, every Packet references a PacketImpl instance which
160 manages the raw packet data and the interpreter list. This raw
161 data is interpreted by the concrete Packet derived class
162 according to the definition of that derived class's packet
163 type (i.e. EthernetPacket or UDPPacket).
165 Packet provides several interfaces:
167 - Creation of Packet instances: create()
169 - Access to the chain of interpreters: next(), prev(), head(),
170 last(), find_next(), find_prev(), get_next(), get_prev(),
171 is(), as() and reinterpret()
173 - Access to the raw packet data: begin(), end(), size(),
176 - An interface to the derived class: v_nextInterpreter(),
177 v_finalize(), registerInterpreter()
180 \section packet_der Implementing new Packet facades
182 To implement a new Packet facade, publically derive from
183 Packet. You need to implement the following minimal interface:
185 - You need to provide a new #ptr typedef
187 - You have to implement v_nextInterpreter() and v_finalize()
189 - The constructor should be private
191 - You must make Packet a \c friend of the new Packet facade
193 - You must implement a static check() method which validates
194 a byte region as your new Packet
198 : public satcom::pkf::Packet
201 typedef ptr_t<ExamplePacket>::ptr ptr;
203 static bool check(Packet::iterator begin, Packet::iterator end)
205 // Validate, that the region [begin,end) can be
206 // interpreted as an ExamplePacket without risking
207 // memory access violations.
212 ExamplePacket(Arg arg [, other args ... ])
213 : satcom::pkf::Packet(arg)
216 virtual void v_nextInterpreter() const
218 // NextPacketType and header_length of course
219 // depend on the packet type
220 registerInterpreter<NextPacketType>(begin()+header_length, end());
223 virtual void v_finalize()
225 // calculate checksum etc
228 friend class satcom::pkf::Packet;
232 Please do not implement the methods inline to not clutter up
233 the header file. This is done here in the example to simplify
234 it. If a class is to be registered in some
235 satcom:pkf::PacketRegistry, it must not take any additional
236 constructor parameters.
238 After having implemented the bare framework, the most comman
239 way to implement access to the packets specific data is to use
240 the parser framework by additionally inheriting a
241 corresponding parser. This also automatically implements the
242 check() method, which is provided by the Parser.
244 In the following example we only show the differences from the
249 : public satcom::pkf::Packet,
250 public Parse_Example<satcom::pkf::Packet::iterator,
254 // check does not need to be implemented here, it is
255 // inherited from the parser
258 template <class InputIterator>
259 ExamplePacket(InputIterator begin, InputIterator end)
260 : satcom::pkf::Packet(begin,end)
265 See the satcom::pkf::ParserBase Documentation for how to
266 implement Parse_Example.
268 The implementation of v_nextInterpreter most of the time
269 relies on some packet registry. This is simplified using the
270 satcom::pkf::PacketRegistryMixin class as follows. Again, we
271 only show the differences from the preceding Example:
274 struct ExampleRegistry {
275 type boost::uint16_t key_t;
279 : public satcom::pkf::Packet,
280 public Parse_Example<satcom::pkf::Packet::iterator,
282 public satcom::pkf::PacketRegistryMixin<ExampleRegistry,
285 using satcom::pkf::Packet::registerInterpreter;
286 using satcom::pkf::PacketRegsitryMixin<ExampleRegistry,ExamplePacket>::registerInterpreter;
288 virtual void v_nextInterpreter() const
290 // nextType() is defined in Parse_Example and
291 // returns the key in the ExampleRegistry of the
293 registerInterpreter(nextType(),begin()+header_length, end());
298 For further details on the packet registry, see
299 satcom::pkf::PacketRegistry.
301 \section packet_impl Implementation details
303 The Packet interface is implemented to minimize overhead as
304 far as possible without getting to complex. One area for
305 improvement ist the container class used to hold the raw
306 data. This currently is an \a std::vector. This could be
307 imporved by either allocating some headroom/tailroom in the
308 vector and using this when inserting data at the beginning or
309 end. Alternatively, a new container class (like the
310 satcom::lib::deque_list) could be used to support zero-copy
313 At the moment, we leave the implementation at
314 std::vector. This container is very simple and especially it
315 can directly be sent out using the operating system since a \a
316 vector stores data at contiguous memory locations. An \a
317 std::deque could be used with \a writev(), however since we
318 have no access to the implementation details of the \a deque,
319 we cannot construct the \a writev() data structures.
321 The interpreter list managed by Packet is lazy, meaning packet
322 interpreter facades are added only when requestd by next(),
323 last() or find_next(). v_nextInterpreter() is called if
324 necessary by these methods to complete the interpreter chain.
326 To implement the automatic memory management, every Packet
327 facade is reference counted. Additionally, the number of
328 (indirect) references to PacketImpl is counted. This allows to
329 manage the PacketImpl instance automatically. To make this
330 work, it is necessary to ensure throughout the Packet code,
331 that the reference count of a Packet is not accidentally
332 decremented to zero. Also, the internal pointers from the
333 interpreter list to the Packet facades must not be
334 counted. They are therefore implemented differently (
335 boost::shared_ptr vs. boost::intrusive_ptr). The choice of
336 boost::intrusive_ptr for the externaly visible smart pointer
337 for all Packet facades is taken to reduce the overhead (an
338 intrusive_ptr is only the size of an ordinary pointer, a
339 smart_ptr has the size of two pointers).
343 class Packet : boost::noncopyable
348 typedef boost::uint8_t byte; //!< single byte datatype
352 ///\name Implementation
354 // These types are implementation details. They are however
355 // needed to provide the correct typedefs for the user
356 // interface. Hiding these classes would incur a huge
357 // additional indirection overhead.
359 typedef std::vector<byte> raw_container;
360 typedef boost::shared_ptr<Packet> interpreter_list_ptr;
361 typedef std::list<satcom::pkf::Packet::interpreter_list_ptr> interpreter_list;
362 typedef unsigned refcount_t;
368 ///////////////////////////////////////////////////////////////////////////
372 /** \brief smart pointer template for all Packet classes
374 This struct is just a template typedef. It defines the
375 smart pointer used for all Packet classes.
377 template <class T> struct ptr_t { typedef boost::intrusive_ptr<T> ptr; };
379 /** \brief smart pointer to the Packet facades
381 Every derived class \e must redeclare this member for it's
384 typedef ptr_t<DerivedClass>::ptr ptr
387 typedef ptr_t<Packet>::ptr ptr;
388 typedef raw_container::iterator iterator; //!< raw data iterator
389 typedef raw_container::size_type size_type;
390 typedef raw_container::difference_type difference_type;
394 // ////////////////////////////////////////////////////////////////////////
396 ///\name Creating packets
399 /** \brief create new Packet
401 This method is used to create a new Packet. All Packet
402 instances are created via this method, they are \e never
403 created directly from the Packet derived class.
405 \param OtherPacket Type of Packet to create, a Packet
407 \param b begin iterator of byte range to create the Packet
409 \param e corresponding end iterator
410 \return smart pointer to new packet
411 \throws TruncatedPacketException The data cannot be parsed
412 securely (the data might be trunctated or just
415 template <class OtherPacket, class InputIterator>
416 static typename ptr_t<OtherPacket>::ptr create(InputIterator b, InputIterator e);
418 template <class OtherPacket>
419 static typename ptr_t<OtherPacket>::ptr create();
421 template <class OuterPacket>
422 static typename ptr_t<OuterPacket>::ptr create(Packet::ptr payload);
426 ///\name Interpreter chain
429 /** \brief get next packet from the interpreter chain
430 \return smart pointer to next packet or 0 if last packet */
432 /** \brief get previous packet from the interpreter chain
433 \return smart pointer to previous packet or 0 if last packet */
435 /** \brief first packet of the interpreter chain
436 \return smart pointer to first packet */
438 /** \brief get last packet of the interpreter chain
439 \return smart pointer to last packet */
442 /** \brief first packet of given type after the current packet
443 \return smart pointer to first following packet of type \a
444 OtherPacket or 0, if no such packet exists */
445 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_next() const;
446 /** \brief first packet of given type before the current packet
447 \return smart pointer to first preceding packet of type \a
448 OtherPacket or 0, if no such packet exists */
449 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_prev() const;
451 /** \brief first packet of given type after the current packet
452 \return smart pointer to first following packet of type \a
453 OtherPacket. \e Assert's, that a packet of this type exists */
454 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_next() const;
455 /** \brief first packet of given type before the current packet
456 \return smart pointer to first preceding packet of type \a
457 OtherPacket. \e Assert's, that a packet of this type exists */
458 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_prev() const;
460 /** \brief check, wether the packet is of the given type
461 \return true, if packt is of type \a OtherPacket, false
463 template <class OtherPacket> bool is() const;
464 /** \brief cast packet pointer to the given type
465 \return a properly cast smart pointer if packet is of type
466 \a OtherPacket. Otherwise return 0 */
467 template <class OtherPacket> typename ptr_t<OtherPacket>::ptr as();
469 /** \brief replace current packet interpreter
471 This method will \e replace the current packet facade in
472 the interpreter list with a new interpreter given by \a
475 \attention This invalidates the packet instance \e
476 this</b>. You must ensure, not to use the Packet instance
477 any further after this call
479 \return smart pointer to a \e new packet facade
480 \throws TruncatedPacketException there is not enough data
481 to savely interpret the packet as the given type. The
482 original packet is \e not invalidated
484 template <class OtherPacket>
485 typename ptr_t<OtherPacket>::ptr reinterpret();
489 ///\name Raw packet data
492 /** \brief begin interator of raw packet data
494 This iterator allows access to the raw data interpreted by
495 the packet facade. This \e includes any header possibly
496 interpreted by the derived packet instance. To access the
497 payload of the packet, use next()->begin().
499 \return random access iterator to the begin of the raw
501 iterator begin() const;
502 /** \brief past-the-end iterator of raw packet data
504 This iterator allows access to the raw data interpreted by
505 the packet facade. This \e includes any header possibly
506 interpreted by the derived packet instance. To access the
507 payload of the packet, use next()->end().
509 \return random access past-the-end iterator of the raw
511 iterator end() const;
512 /** \brief raw data size of packet
513 \return size of the raw data interpreted by this
514 packet in bytes. This is \e not necessarily the size of
515 the complete packet, use head()->size() for this. */
518 // Modifying the raw packet data
520 // FIXME: Make all data mutators protected
522 typedef enum { AUTO, BEFORE, INSIDE, OUTSIDE, AFTER } Whence;
524 /** \brief insert single byte \a v before pos
526 \attention The change will \e not be validated by the
527 derived packet instance. This method is mostly to be used
528 by the derived class implementation and their helper
530 void insert(iterator pos, byte v, Whence whence = AUTO);
531 /** \brief insert \a n copies of byte \a v before pos
533 \attention The change will \e not be validated by the
534 derived packet instance. This method is mostly to be used
535 by the derived class implementation and their helper
537 void insert(iterator pos, size_type n, byte v, Whence whence = AUTO);
538 /** \brief insert a copy of the given range before pos
540 \attention The change will \e not be validated by the
541 derived packet instance. This method is mostly to be used
542 by the derived class implementation and their helper
544 template <class InputIterator>
545 void insert(iterator pos, InputIterator f, InputIterator l, Whence whence = AUTO);
547 /** \brief erase single byte
549 \attention The change will \e not be validated by the
550 derived packet instance. This method is mostly to be used
551 by the derived class implementation and their helper
553 void erase(iterator pos);
554 /** \brief erase range
556 \attention The change will \e not be validated by the
557 derived packet instance. This method is mostly to be used
558 by the derived class implementation and their helper
560 void erase(iterator first, iterator last);
564 void dump(std::ostream & os) const;
567 ///\name Derived class interface
570 /** \brief create new interpreter facade for an existing packet
572 This constructor is called, when a new interpreter is to
573 be added to the interpreter chain. The constructor is
574 called indirectly from registerInterpreter() or
575 reinterpret() via the derived classes template
578 template <class Operation>
579 Packet(Operation const & arg);
583 /** \brief create next packet interpreter
585 This method is called by next(), last() or find_next() to
586 create any missing interpreters in the interpreter
587 chain. This method must be overridden in the derived class
588 to register the next packet interpreter in the interpreter
589 chain with the packet framework.
591 To register the new interpreter, use
592 registerInterpreter() to create the new Packet
593 instance. The new instance is automatically added to the
594 interpreter chain after the current interpreter.
596 See also satcom::pkf::PacketRegistryMixin on how to
597 use a Registry to find the next interpreters implementing
600 virtual void v_nextInterpreter() const = 0;
602 /** \brief finalize packet for sending
604 This method is called by the packet framework to let the
605 interpreter facade do some final calculations/packet
606 cleanup before the packet is sent out or digested in some
607 other way. This is the place to calcaulate checksums and
610 This method is autmatically called for all interpreters on
611 the interpreter chain.
613 virtual void v_finalize() = 0;
615 virtual void v_dump(std::ostream & os) const = 0;
618 /** \brief add interpreter to interpreter chain
620 This method is used by v_nextInterpreter() in the derived
621 classes to add a new interpreter to the interpreter
622 chain. This method will call \c OtherPacket's constructor
623 with the correct arguments and insert the new interpreter
624 into the interpreter list. This method is used, if no
625 further arguments are to be passed to the \c OtherPacket
626 constructor. If additional arguments are necessary, just
627 add them after \c end. The compiler will then choose the
628 correct overload to use.
630 template <class OtherPacket>
631 typename ptr_t<OtherPacket>::ptr registerInterpreter(
632 raw_container::iterator begin, raw_container::iterator end) const;
633 template <class OtherPacket, class A0>
634 typename ptr_t<OtherPacket>::ptr registerInterpreter(
635 raw_container::iterator begin, raw_container::iterator end,
636 A0 const & a0) const;
638 # define BOOST_PP_ITERATION_PARAMS_1 (4, (2, 9, "Packets/Packet.mpp", 3))
639 # include BOOST_PP_ITERATE()
645 ///\name Implementation
648 void add_ref() const;
652 struct PacketOp_register;
653 friend class PacketOp_register;
654 void i_registerInterpreter(Packet * p) const;
656 struct PacketOp_replace;
657 friend class PacketOp_replace;
658 void i_replaceInterpreter(Packet * p);
661 friend class PacketOp_set;
662 void i_setInterpreter(impl::PacketImpl * i);
665 friend class impl::PacketImpl;
666 template <class OtherPacket> friend class impl::PkReg_EntryImpl;
668 impl::PacketImpl* impl_;
671 interpreter_list::iterator self_;
672 mutable bool parsed_;
673 mutable refcount_t refcount_;
678 /** \brief dump packet to stream
680 // std::ostream & operator<<(std::ostream & os, Packet const & packet);
682 /** \brief smart pointer handling
684 void intrusive_ptr_add_ref(Packet const *);
685 /** \brief smart pointer handling
687 void intrusive_ptr_release(Packet *);
689 struct TruncatedPacketException : public std::exception
690 { virtual char const * what() const throw() { return "truncated packet"; } };
694 // ////////////////////////////hh.e////////////////////////////////////////
695 #include "Packet.cci"
697 #include "Packet.cti"
699 #include "Packet.mpp"
705 // c-file-style: "satcom"