// $Id$
//
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-// Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// Copyright (C) 2007
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Main packet interface
-
- \todo Implement assign() method akin to reinterpret(). However,
- instead of using the data already present, assign() will replace
- the date of the current packet with the given Packet.
-
- \todo Implement wrapping-constructor. Somehow we want to have a
- constructor, which allows creating a chain of packet interpreters
- with as little overhead as possible.
-
- \todo Document the additional concrete Packet facade requirements
- explicitly and not only within the Parser requirements (check(),
- bytes() and min_bytes() members ...)
-
- \todo Implement special container replacing vector which manages
- some headroom to allow efficient insertion of elements at the
- beginning. This really is just another type of dequeue
- implementation.
- */
+ \brief Packet public header */
#ifndef HH_Packet_
#define HH_Packet_ 1
// Custom includes
-#include <boost/utility.hpp> // for boost::noncopyable
-#include <boost/cstdint.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/intrusive_ptr.hpp>
-#include <list>
-#include <vector>
-#include <iostream>
+#include <boost/operators.hpp>
-#include "Packet.mpp"
-// ////////////////////////////hh.p////////////////////////////////////////
+#include "../Utils/Exception.hh"
+#include "../Utils/safe_bool.hh"
+#include "PacketInterpreter.hh"
+
+//#include "Packet.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
- namespace impl { template <class OtherPacket> class PkReg_EntryImpl; }
- namespace impl { class PacketImpl; }
-
- /** \brief Basic interface to all packet facades
-
- \section packet_overview Overview
-
- This class is the base class of all Packets. It implements the
- generic Packet interface and provides the packet management
- framework. senf::Packet manages the necessary memory
- resources and controls the chain of packet interpreters.
-
- The Packet user always interfaces with the pkf via a Packet
- derived class. This is the only external entity ever held by a
- library user. The interface is implemented using a reference
- counted smart pointer, so resource management is quasi
- automatic.
-
- \image html structure.png Overview
-
- Internally, every Packet references a PacketImpl instance which
- manages the raw packet data and the interpreter list. This raw
- data is interpreted by the concrete Packet derived class
- according to the definition of that derived classes packet
- type (i.e. EthernetPacket or UDPPacket).
-
- Packet provides several interfaces:
-
- - Creation of Packet instances: create()
-
- - Access to the chain of interpreters: next(), prev(), head(),
- last(), find_next(), find_prev(), get_next(), get_prev(),
- is(), as() and reinterpret()
-
- - Access to the raw packet data: begin(), end(), size(),
- insert() and erase()
-
- - An interface to the derived class: v_nextInterpreter(),
- v_finalize(), registerInterpreter()
-
-
- \section packet_der Implementing new Packet facades
-
- To implement a new Packet facade, publically derive from
- Packet. You need to implement the following minimal interface:
-
- - You need to provide a new #ptr typedef
-
- - You have to implement v_nextInterpreter() and v_finalize()
-
- - The constructor should be private
-
- - You must make Packet a \c friend of the new Packet facade
-
- - You must implement a static check() method which validates
- a byte region as your new Packet
-
- \code
- class ExamplePacket
- : public senf::Packet
- {
- public:
- typedef ptr_t<ExamplePacket>::ptr ptr;
-
- static bool check(Packet::iterator begin, Packet::iterator end)
- {
- // Validate, that the region [begin,end) can be
- // interpreted as an ExamplePacket without risking
- // memory access violations.
- }
-
- private:
- template <class Arg>
- ExamplePacket(Arg arg [, other args ... ])
- : senf::Packet(arg)
- {}
-
- virtual void v_nextInterpreter() const
- {
- // NextPacketType and header_length of course
- // depend on the packet type
- registerInterpreter<NextPacketType>(begin()+header_length, end());
- }
-
- virtual void v_finalize()
- {
- // calculate checksum etc
- }
-
- friend class senf::Packet;
- };
- \endcode
-
- Please do not implement the methods inline to not clutter up
- the header file. This is done here in the example to simplify
- it. If a class is to be registered in some
- senf:PacketRegistry, it must not take any additional
- constructor parameters.
-
- After having implemented the bare framework, the most common
- way to implement access to the packets specific data is to use
- the parser framework by additionally inheriting a
- corresponding parser. This also automatically implements the
- check() method, which is provided by the Parser.
-
- In the following example we only show the differences from the
- previous example:
-
- \code
- class ExamplePacket
- : public senf::Packet,
- public Parse_Example<senf::Packet::iterator,
- ExamplePacket>
- {
-
- // check does not need to be implemented here, it is
- // inherited from the parser
-
- private:
- template <class InputIterator>
- ExamplePacket(InputIterator begin, InputIterator end)
- : senf::Packet(begin,end)
- {}
- };
- \endcode
-
- See the senf::ParserBase Documentation for how to
- implement Parse_Example.
-
- The implementation of v_nextInterpreter most of the time
- relies on some packet registry. This is simplified using the
- senf::PacketRegistryMixin class as follows. Again, we
- only show the differences from the preceding Example:
-
- \code
- struct ExampleRegistry {
- type boost::uint16_t key_t;
- };
-
- class ExamplePacket
- : public senf::Packet,
- public Parse_Example<senf::Packet::iterator,
- ExamplePacket>,
- public senf::PacketRegistryMixin<ExampleRegistry,
- ExamplePacket>
- {
- using senf::Packet::registerInterpreter;
- using senf::PacketRegsitryMixin<ExampleRegistry,ExamplePacket>::registerInterpreter;
- private:
- virtual void v_nextInterpreter() const
- {
- // nextType() is defined in Parse_Example and
- // returns the key in the ExampleRegistry of the
- // next Packet.
- registerInterpreter(nextType(),begin()+header_length, end());
- }
- };
- \endcode
-
- For further details on the packet registry, see
- senf::PacketRegistry.
-
- \section packet_impl Implementation details
-
- The Packet interface is implemented to minimize overhead as
- far as possible without getting to complex. One area for
- improvement is the container class used to hold the raw
- data. This currently is an \a std::vector. This could be
- improved by either allocating some headroom/tailroom in the
- vector and using this when inserting data at the beginning or
- end. Alternatively, a new container class (like the
- senf::deque_list) could be used to support zero-copy
- semantics.
-
- At the moment, we leave the implementation at
- std::vector. This container is very simple and especially it
- can directly be sent out using the operating system since a \a
- vector stores data at contiguous memory locations. An \a
- std::deque could be used with \a writev(), however since we
- have no access to the implementation details of the \a deque,
- we cannot construct the \a writev() data structures.
-
- The interpreter list managed by Packet is lazy, meaning packet
- interpreter facades are added only when requested by next(),
- last() or find_next(). v_nextInterpreter() is called if
- necessary by these methods to complete the interpreter chain.
-
- To implement the automatic memory management, every Packet
- facade is reference counted. Additionally, the number of
- (indirect) references to PacketImpl is counted. This allows to
- manage the PacketImpl instance automatically. To make this
- work, it is necessary to ensure throughout the Packet code,
- that the reference count of a Packet is not accidentally
- decremented to zero. Also, the internal pointers from the
- interpreter list to the Packet facades must not be
- counted. They are therefore implemented differently (
- boost::shared_ptr vs. boost::intrusive_ptr). The choice of
- boost::intrusive_ptr for the externally visible smart pointer
- for all Packet facades is taken to reduce the overhead (an
- intrusive_ptr is only the size of an ordinary pointer, a
- smart_ptr has the size of two pointers).
-
- \nosubgrouping
+ /** \defgroup packet_module Packet Handling
+
+ The basic groundwork of the Packet library is the packet handling:
+
+ \li The packet classes provide access to a chain of packet headers (more generically called
+ interpreters).
+ \li They automatically manage the required memory resources and the shared packet data.
+
+ \section packet_module_chain The Interpreter Chain
+
+ The central data structure for a packet is the interpreter chain
+
+ \image html structure.png The Interpreter Chain
+
+ This image depicts a packet with several headers. Each interpreter is responsible for a
+ specific sub-range of the complete packet. This range always \e includes the packets payload
+ (This is, why we call the data structure interpreter and not header: The interpreter is
+ responsible for interpreting a range of the packet according to a specific protocol), the
+ packet interpreters are nested inside each other.
+
+ For each interpreter, this structure automatically divides the packet into three areas (each
+ of which are optional): The header, the payload and the trailer. Every packet will have
+ either a header or a payload section while most don't have a trailer.
+
+ As user of the library you always interact with the chain through one (or more) of the
+ interpreters. The interpreter provides methods to traverse to the following or preceding
+ header (interpreter) and provides two levels of access to the packet data: Generic low-level
+ access in the form of an STL compatible sequence and access to the parsed fields which are
+ provided by the parser associated with the concrete packet type.
+
+ \section packet_module_management Resource Management
+
+ The interface to the packet library is provided using a handle class (\ref Packet for
+ generic, protocol agnostic access and \ref ConcretePacket derived from \ref Packet to access
+ a specific protocol). This handle automatically manages the resources associated with the
+ packet (the interpreter chain and the data storage holding the packet data). The resources
+ are automatically released when the last packet handle referencing a specific packet is
+ destroyed.
+
+ \implementation The packet chain is provided on two levels: The internal representation \ref
+ PacketInterpreterBase and \ref PacketInterpreter which are referenced by the Handle
+ classes \ref Packet and \ref ConcretePacket. \n
+ The internal representation classes are pertinent in the sense, that they exist
+ regardless of the existence of a handle referencing them (as long as the packet
+ exists). Still the interpreter chain is lazy and packet interpreters beside the first
+ are only created dynamically when accessed (this is implemented in the handle not in the
+ internal representation). \n
+ The packet interpreters make use of a pool allocator. This provides extremely efficient
+ creation and destruction of packet interpreter's and removes the dynamic memory
+ management overhead from the packet interpreter management. The packet implementation
+ class (\ref PacketImpl which holds the packet data itself) however is still dynamically
+ managed (however there is only a single instance for each packet).
+ */
+
+ template <class PackeType> class ConcretePacket;
+
+ ///\addtogroup packet_module
+ ///@{
+
+ /** \brief Main Packet class
+
+ Packet is the main externally visible class of the packet library. Packet is a handle into
+ the internal packet representation. From Packet you may access the data of that specific
+ sub-packet/header/interpreter and navigate to the neighboring
+ sub-packets/headers/interpreters.
+
+ Packet is protocol agnostic. This class only provides non-protocol dependent members. To
+ access the protocol specific features of a packet (like header fields) the ConcretePacket
+ class extending Packet is provided.
+
+ \section packet_semantics Semantics
+
+ All operations accessing the data of \c this packet in some way will ignore any preceding
+ packets/headers/interpreters in the chain. It does not matter, whether a given packet is
+ taken from the middle or the beginning of the chain, all operations (except those explicitly
+ accessing the chain of course) should work the same.
+
+ This especially includes members like clone() or append(): clone() will clone \e only from
+ \c this packet until the end of the chain, append() will append the given packet \e ignoring
+ any possibly preceding packets/headers/interpreters.
+
+ In the same way, the data() member provides an STL-sequence compatible view of the packet
+ data. This only includes the data which is part of \c this packet including header, trailer
+ \e and payload but \e not the headers or trailers of packets \e before \c this packet in the
+ packet/header/interpreter chain (nonetheless, this data overlaps with the data of other
+ packets).
+
+ Several members are member templates taking an \a OtherPacket template parameter. This
+ parameter must be the ConcretePacket instantiation associated with some concrete packet type
+ (protocol). For each implemented protocol, typedefs should be provided for these
+ instantiations (Example: \ref EthernetPacket is a typedef for
+ \ref ConcretePacket < \ref EthernetPacketType >).
+
+ \see
+ \ref ConcretePacket for the type specific interface\n
+ \ref PacketData for the sequence interface\n
+ \ref packetparser for a specification of the parser interface
*/
- class Packet : boost::noncopyable
+ class Packet
+ : public safe_bool<Packet>,
+ public boost::equality_comparable<Packet>
{
public:
- ///\name Types
- ///@{
- typedef boost::uint8_t byte; //!< single byte datatype
- ///@}
-
- private:
- ///\name Implementation
- ///@{
- // These types are implementation details. They are however
- // needed to provide the correct typedefs for the user
- // interface. Hiding these classes would incur a huge
- // additional indirection overhead.
-
- typedef std::vector<byte> raw_container;
- typedef boost::shared_ptr<Packet> interpreter_list_ptr;
- typedef std::list<senf::Packet::interpreter_list_ptr> interpreter_list;
- typedef unsigned refcount_t;
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef void type; ///< Type of the packet.
+ typedef senf::detail::packet::size_type size_type;
+ ///< Unsigned type to represent packet size
+ typedef PacketInterpreterBase::factory_t factory_t; ///< Packet factory type (see below)
- ///@}
-
- public:
+ enum NoInit_t { noinit }; ///< Special argument flag
+ /**< Used in some ConcretePacket constructors */
///////////////////////////////////////////////////////////////////////////
- ///\name Types
+ ///\name Structors and default members
///@{
- /** \brief smart pointer template for all Packet classes
-
- This struct is just a template typedef. It defines the
- smart pointer used for all Packet classes.
- */
- template <class T> struct ptr_t { typedef boost::intrusive_ptr<T> ptr; };
-
- /** \brief smart pointer to the Packet facades
-
- Every derived class \e must redeclare this member for it's
- derived type:
- \code
- typedef ptr_t<DerivedClass>::ptr ptr
- \endcode
- */
- typedef ptr_t<Packet>::ptr ptr;
- typedef raw_container::iterator iterator; //!< raw data iterator
- typedef raw_container::size_type size_type;
- typedef raw_container::difference_type difference_type;
+ // default copy constructor
+ // default copy assignment
+ // default destructor
+
+ Packet(); ///< Create uninitialized packet handle
+ /**< An uninitialized handle is in - valid(). It does not
+ allow any operation except assignment and checking for
+ validity. */
+ Packet clone() const; ///< Create copy packet
+ /**< clone() will create a complete copy of \c this
+ packet. The returned packet will have the same data and
+ packet chain. It does however not share any data with
+ the original packet. */
+
+ // conversion constructors
+
+ template <class PacketType>
+ Packet(ConcretePacket<PacketType> packet); ///< Copy-construct Packet from ConcretePacket
+ /**< This constructor allows to convert an arbitrary
+ ConcretePacket into a general Packet, loosing the
+ protocol specific interface. */
///@}
+ ///////////////////////////////////////////////////////////////////////////
- // ////////////////////////////////////////////////////////////////////////
-
- ///\name Creating packets
+ ///\name Interpreter chain access
///@{
- /** \brief create new Packet
-
- This method is used to create a new Packet. All Packet
- instances are created via this method, they are \e never
- created directly from the Packet derived class.
-
- \param OtherPacket Type of Packet to create, a Packet
- derived class
- \param b begin iterator of byte range to create the Packet
- from
- \param e corresponding end iterator
- \return smart pointer to new packet
- \throws TruncatedPacketException The data cannot be parsed
- securely (the data might be truncated or just
- plain invalid)
- */
- template <class OtherPacket, class InputIterator>
- static typename ptr_t<OtherPacket>::ptr create(InputIterator b, InputIterator e);
-
- template <class OtherPacket>
- static typename ptr_t<OtherPacket>::ptr create();
-
- template <class OuterPacket>
- static typename ptr_t<OuterPacket>::ptr create(Packet::ptr payload);
+ Packet next() const;
+ ///< Get next packet in chain
+ /**< \returns in - valid() packet, if no next packet
+ exists */
+ Packet next(NoThrow_t) const;
+ ///< Get next packet in chain
+ /**< \returns in - valid() packet, if no next packet
+ exists */
+ template <class OtherPacket> OtherPacket next() const;
+ ///< Get next packet in chain and cast to \a OtherPacket
+ /**< \throws std::bad_cast if the next() packet is not of
+ type \a OtherPacket
+ \returns in - valid() packet, if no next packet
+ exists */
+ template <class OtherPacket> OtherPacket next(NoThrow_t) const;
+ ///< Get next packet in chain and cast to \a OtherPacket
+ /**< \throws std::bad_cast if the next() packet is not of
+ type \a OtherPacket
+ \returns in - valid() packet, if no next packet
+ exists */
+ template <class OtherPacket> OtherPacket find() const;
+ ///< Search chain forward for packet of type \a OtherPacket
+ /**< The search will start with the current packet.
+ \returns in - valid() packet, if no packet of type \a
+ OtherPacket can be found. */
+ template <class OtherPacket> OtherPacket find(NoThrow_t) const;
+ ///< Search chain forward for packet of type \a OtherPacket
+ /**< The search will start with the current packet.
+ \returns in - valid() packet, if no packet of type \a
+ OtherPacket can be found. */
+
+ Packet prev() const;
+ ///< Get previous packet in chain
+ /**< \returns in - valid() packet, if no previous packet
+ exists */
+ Packet prev(NoThrow_t) const;
+ ///< Get previous packet in chain
+ /**< \returns in - valid() packet, if no previous packet
+ exists */
+ template <class OtherPacket> OtherPacket prev() const;
+ ///< Get previous packet in chain and cast to \a OtherPacket
+ /**< \throws std::bad_cast, if the previous packet is not of
+ type \a OtherPacket
+ \returns in - valid() packet, if no previous packet
+ exists */
+ template <class OtherPacket> OtherPacket prev(NoThrow_t) const;
+ ///< Get previous packet in chain and cast to \a OtherPacket
+ /**< \throws std::bad_cast, if the previous packet is not of
+ type \a OtherPacket
+ \returns in - valid() packet, if no previous packet
+ exists */
+ template <class OtherPacket> OtherPacket rfind() const;
+ ///< Search chain backwards for packet of type \a OtherPacket
+ /**< The search will start with the current packet.
+ \returns in - valid() packet, if no packet of type \a
+ OtherPacket can be found. */
+ template <class OtherPacket> OtherPacket rfind(NoThrow_t) const;
+ ///< Search chain backwards for packet of type \a OtherPacket
+ /**< The search will start with the current packet.
+ \returns in - valid() packet, if no packet of type \a
+ OtherPacket can be found. */
+
+
+ Packet first() const;
+ ///< Return first packet in chain
+ template <class OtherPacket> OtherPacket first() const;
+ ///< Return first packet in chain and cast
+ /**< \throws std::bad_cast if the first() packet is not of
+ type \a OtherPacket */
+
+ Packet last() const;
+ ///< Return last packet in chain
+ template <class OtherPacket> OtherPacket last() const;
+ ///< Return last packet in chain and cast
+ /**< \throws std::bad_cast if the last() packet is not of
+ type \a OtherPacket */
+
+
+ template <class OtherPacket> OtherPacket parseNextAs() const;
+ ///< Interpret payload of \c this as \a OtherPacket
+ /**< parseNextAs() will throw away the packet chain after
+ the current packet if necessary. It will then parse the
+ payload section of \c this packet as given by \a
+ OtherPacket. The new packet is added to the chain after
+ \c this.
+ \returns new packet instance sharing the same data and
+ placed after \c this packet in the chain. */
+ Packet parseNextAs(factory_t factory) const;
+ ///< Interpret payload of \c this as \a factory type packet
+ /**< parseNextAs() will throw away the packet chain after
+ the current packet if necessary. It will then parse the
+ payload section of \c this packet as given by \a
+ factory. The new packet is added to the chain after
+ \c this.
+ \returns new packet instance sharing the same data and
+ placed after \c this packet in the chain. */
+
+ template <class OtherPacket> bool is() const;
+ ///< Check, whether \c this packet is of the given type
+ template <class OtherPacket> OtherPacket as() const;
+ ///< Cast current packet to the given type
+ /**< This operations returns a handle to the same packet
+ header/interpreter however cast to the given
+ ConcretePacket type.
+ \throws std::bad_cast if the current packet is not of
+ type \a OtherPacket */
+
+ Packet append(Packet packet) const; ///< Append the given packet to \c this packet
+ /**< This operation will replace the payload section of \c
+ this packet with \a packet. This operation will replace
+ the packet chain after \c this packet with a clone of
+ \a packet and will replace the raw data of the payload
+ of \c this with the raw data of \a packet. \c this
+ packet will not share any date with \a packet.
+ \returns Packet handle to the cloned \a packet, placed
+ after \c this in the packet/header/interpreter
+ chain. */
///@}
- ///\name Interpreter chain
+ ///\name Data access
///@{
- /** \brief get next packet from the interpreter chain
- \return smart pointer to next packet or 0 if last packet */
- ptr next() const;
- /** \brief get previous packet from the interpreter chain
- \return smart pointer to previous packet or 0 if last packet */
- ptr prev() const;
- /** \brief first packet of the interpreter chain
- \return smart pointer to first packet */
- ptr head() const;
- /** \brief get last packet of the interpreter chain
- \return smart pointer to last packet */
- ptr last() const;
-
- /** \brief first packet of given type after the current packet
- \return smart pointer to first following packet of type \a
- OtherPacket or 0, if no such packet exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_next() const;
- /** \brief first packet of given type before the current packet
- \return smart pointer to first preceding packet of type \a
- OtherPacket or 0, if no such packet exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr find_prev() const;
-
- /** \brief first packet of given type after the current packet
- \return smart pointer to first following packet of type \a
- OtherPacket. \e Assert's, that a packet of this type exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_next() const;
- /** \brief first packet of given type before the current packet
- \return smart pointer to first preceding packet of type \a
- OtherPacket. \e Assert's, that a packet of this type exists */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr get_prev() const;
-
- /** \brief check, whether the packet is of the given type
- \return true, if packet is of type \a OtherPacket, false
- otherwise */
- template <class OtherPacket> bool is() const;
- /** \brief cast packet pointer to the given type
- \return a properly cast smart pointer if packet is of type
- \a OtherPacket. Otherwise return 0 */
- template <class OtherPacket> typename ptr_t<OtherPacket>::ptr as();
-
- /** \brief replace current packet interpreter
-
- This method will \e replace the current packet facade in
- the interpreter list with a new interpreter given by \a
- OtherPacket.
-
- \attention This invalidates the packet instance \e
- this. You must ensure, not to use the Packet instance any
- further after this call
-
- \return smart pointer to a \e new packet facade
- \throws TruncatedPacketException there is not enough data
- to safely interpret the packet as the given type. The
- original packet is \e not invalidated
- */
- template <class OtherPacket>
- typename ptr_t<OtherPacket>::ptr reinterpret();
-
+ PacketData & data() const; ///< Access the packets raw data container
+ size_type size() const; ///< Return size of packet in bytes
+ /**< This size does \e not include the size of any preceding
+ headers/packets/interpreters. It does however include
+ \c this packets payload. */
+
///@}
- ///\name Raw packet data
+ ///\name Other methods
///@{
- /** \brief begin iterator of raw packet data
-
- This iterator allows access to the raw data interpreted by
- the packet facade. This \e includes any header possibly
- interpreted by the derived packet instance. To access the
- payload of the packet, use next()->begin().
-
- \return random access iterator to the begin of the raw
- data */
- iterator begin() const;
- /** \brief past-the-end iterator of raw packet data
-
- This iterator allows access to the raw data interpreted by
- the packet facade. This \e includes any header possibly
- interpreted by the derived packet instance. To access the
- payload of the packet, use next()->end().
-
- \return random access past-the-end iterator of the raw
- data */
- iterator end() const;
- /** \brief raw data size of packet
- \return size of the raw data interpreted by this
- packet in bytes. This is \e not necessarily the size of
- the complete packet, use head()->size() for this. */
- size_t size() const;
-
- // Modifying the raw packet data
-
- typedef enum { AUTO, BEFORE, INSIDE, OUTSIDE, AFTER } Whence;
-
- /** \brief insert single byte \a v before pos
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void insert(iterator pos, byte v, Whence whence = AUTO);
- /** \brief insert \a n copies of byte \a v before pos
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void insert(iterator pos, size_type n, byte v, Whence whence = AUTO);
- /** \brief insert a copy of the given range before pos
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- template <class InputIterator>
- void insert(iterator pos, InputIterator f, InputIterator l, Whence whence = AUTO);
-
- /** \brief erase single byte
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void erase(iterator pos);
- /** \brief erase range
-
- \attention The change will \e not be validated by the
- derived packet instance. This method is mostly to be used
- by the derived class implementation and their helper
- classes. */
- void erase(iterator first, iterator last);
-
+ bool operator==(Packet other) const; ///< Check for packet identity
+ /**< Two packet handles compare equal if they really are the
+ same packet header in the same packet chain. */
+ bool boolean_test() const; ///< Check, whether the packet is valid()
+ /**< \see valid() */
+ bool valid() const; ///< Check, whether the packet is valid()
+ /**< An in - valid() packet does not allow any operation
+ except checking for validity and assignment. in -
+ valid() packets serve the same role as 0-pointers.
+
+ This is an alias for boolean_test() which is called
+ when using a packet in a boolean context. */
+
+ void finalize() const; ///< Update calculated fields
+ /**< This call will update all calculated fields of the
+ packet after it has been created or changed. This
+ includes checksums, payload size fields or other
+ fields, which can be set from other information in the
+ packet. Each concrete packet type should document,
+ which fields are set by finalize().
+
+ finalize() will automatically process all
+ packets/headers/interpreters from the end of the chain
+ backwards up to \c this. */
+
+ void dump(std::ostream & os) const; ///< Write out a printable packet representation
+ /**< This method is provided mostly to help debugging packet
+ problems. Each concrete packet should implement a dump
+ method writing out all fields of the packet in a
+ readable representation. dump() will call this member
+ for each packet/header/interpreter in the chain from \c
+ this packet up to the end of the chain. */
+
+ TypeIdValue typeId() const; ///< Get id of \c this packet
+ /**< This value is used e.g. in the packet registry to
+ associate packet types with other information.
+ \returns A type holding the same information as a
+ type_info object, albeit assignable */
+ factory_t factory() const; ///< Return factory instance of \c this packet
+ /**< The returned factory instance can be used to create new
+ packets of the given type without knowing the concrete
+ type of the packet. The value may be stored away for
+ later use if needed. */
+
///@}
- void dump(std::ostream & os) const;
-
protected:
- ///\name Derived class interface
- ///@{
-
- /** \brief create new interpreter facade for an existing packet
+ explicit Packet(PacketInterpreterBase::ptr packet);
- This constructor is called, when a new interpreter is to
- be added to the interpreter chain. The constructor is
- called indirectly from registerInterpreter() or
- reinterpret() via the derived classes template
- constructor.
- */
- template <class Operation>
- Packet(Operation const & arg);
- virtual ~Packet();
+ PacketInterpreterBase::ptr ptr() const;
private:
- /** \brief create next packet interpreter
-
- This method is called by next(), last() or find_next() to
- create any missing interpreters in the interpreter
- chain. This method must be overridden in the derived class
- to register the next packet interpreter in the interpreter
- chain with the packet framework.
-
- To register the new interpreter, use
- registerInterpreter() to create the new Packet
- instance. The new instance is automatically added to the
- interpreter chain after the current interpreter.
-
- See also senf::PacketRegistryMixin on how to
- use a Registry to find the next interpreters implementing
- class.
- */
- virtual void v_nextInterpreter() const = 0;
-
- /** \brief finalize packet for sending
+ Packet checkNext() const;
+ Packet checkLast() const;
+
+ PacketInterpreterBase::ptr packet_;
+
+ template <class PacketType>
+ friend class ConcretePacket;
+ friend class PacketParserBase;
+ };
- This method is called by the packet framework to let the
- interpreter facade do some final calculations/packet
- cleanup before the packet is sent out or digested in some
- other way. This is the place to calculate checksums and
- such.
+ /** \brief Protocol specific packet handle
+
+ The ConcretePacket template class extends Packet to provide protocol/packet type specific
+ aspects. These are packet constructors and access to the parsed packet fields.
+
+ The \c PacketType template argument to ConcretePacket is a protocol specific and internal
+ policy class which defines the protocol specific behavior. To access a specific type of
+ packet, the library provides corresponding typedefs of ConcretePacket < \a SomePacketType >
+ (e.g. \ref EthernetPacket as typedef for \ref ConcretePacket < \ref EthernetPacketType >).
+
+ The new members provided by ConcretePacket over packet are mostly comprised of the packet
+ constructors. These come in three major flavors:
+
+ \li The create() family of constructors will create completely new packets.
+ \li The createAfter() family of constructors will create new packets (with new data for the
+ packet) \e after a given existing packet.
+ \li The createBefore() family of constructors will create new packets (again with new data)
+ \e before a given existing packet.
+
+ Whereas create() will create a completely new packet with it's own chain and data storage,
+ createAfter() and createBefore() extend a packet with additional
+ headers/interpreters. createAfter() will set the payload of the given packet to the new
+ packet whereas createBefore() will create a new packet with the existing packet as it's
+ payload.
+
+ createAfter() differs from Packet::parseNextAs() in that the former creates a new packet \e
+ replacing any possibly existing data whereas the latter will interpret the already \e
+ existing data as given by the type argument.
+
+ \see \ref PacketTypeBase for a specification of the interface to be provided by the \a
+ PacketType policy class.
+ */
+ template <class PacketType>
+ class ConcretePacket
+ : public Packet
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef PacketType type;
+ typedef typename PacketType::parser Parser;
- This method is automatically called for all interpreters on
- the interpreter chain.
- */
- virtual void v_finalize() = 0;
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
- virtual void v_dump(std::ostream & os) const = 0;
-
- protected:
- /** \brief add interpreter to interpreter chain
-
- This method is used by v_nextInterpreter() in the derived
- classes to add a new interpreter to the interpreter
- chain. This method will call \c OtherPacket's constructor
- with the correct arguments and insert the new interpreter
- into the interpreter list. This method is used, if no
- further arguments are to be passed to the \c OtherPacket
- constructor. If additional arguments are necessary, just
- add them after \c end. The compiler will then choose the
- correct overload to use.
- */
- template <class OtherPacket>
- typename ptr_t<OtherPacket>::ptr registerInterpreter(
- raw_container::iterator begin, raw_container::iterator end) const;
- template <class OtherPacket, class A0>
- typename ptr_t<OtherPacket>::ptr registerInterpreter(
- raw_container::iterator begin, raw_container::iterator end,
- A0 const & a0) const;
-
-# define BOOST_PP_ITERATION_PARAMS_1 (4, (2, 9, "Packets/Packet.mpp", 3))
-# include BOOST_PP_ITERATE()
+ // default copy constructor
+ // default copy assignment
+ // default destructor
+ // no conversion constructors
+
+ ConcretePacket(); ///< Create uninitialized packet handle
+ /**< An uninitialized handle is not valid(). It does not
+ allow any operation except assignment and checking for
+ validity. */
+
+ static factory_t factory(); ///< Return factory for packets of specific type
+ /**< This \e static member is like Packet::factory() for a
+ specific packet of type \a PacketType */
+
+ // Create completely new packet
+
+ static ConcretePacket create(); ///< Create default initialized packet
+ /**< The packet will be initialized to it's default empty
+ state. */
+ static ConcretePacket create(NoInit_t); ///< Create uninitialized empty packet
+ /**< This will create a completely empty and uninitialized
+ packet with <tt>size() == 0</tt>.
+ \param[in] noinit This parameter must always have the
+ value \c senf::noinit. */
+ static ConcretePacket create(size_type size); ///< Create default initialized packet
+ /**< This member will create a default initialized packet
+ with the given size. If the size parameter is smaller
+ than the minimum allowed packet size an exception will
+ be thrown.
+ \param[in] size Size of the packet to create in bytes.
+ \throws TruncatedPacketException if \a size is smaller
+ than the smallest permissible size for this type of
+ packet. */
+ static ConcretePacket create(size_type size, NoInit_t); ///< Create uninitialized packet
+ /**< Creates an uninitialized (all-zero) packet of the exact
+ given size.
+ \param[in] size Size of the packet to create in bytes
+ \param[in] noinit This parameter must always have the
+ value \c senf::noinit. */
+ template <class ForwardReadableRange>
+ static ConcretePacket create(ForwardReadableRange const & range);
+ ///< Create packet from given data
+ /**< The packet will be created from a copy of the given
+ data. The data from the range will be copied directly
+ into the packet representation. The data will \e not be
+ validated in any way.
+ \param[in] range <a
+ href="http://www.boost.org/libs/range/index.html">Boost.Range</a>
+ of data to construct packet from. */
+
+ // Create packet as new packet after a given packet
+
+ static ConcretePacket createAfter(Packet packet);
+ ///< Create default initialized packet after \a packet
+ /**< The packet will be initialized to it's default empty
+ state. It will be appended as next header/interpreter
+ after \a packet in that packets interpreter chain.
+ \param[in] packet Packet to append new packet to. */
+ static ConcretePacket createAfter(Packet packet, NoInit_t);
+ ///< Create uninitialized empty packet after\a packet
+ /**< This will create a completely empty and uninitialized
+ packet with <tt>size() == 0</tt>. It will be appended
+ as next header/interpreter after \a packet in that
+ packets interpreter chain.
+ \param[in] packet Packet to append new packet to.
+ \param[in] noinit This parameter must always have the
+ value \c senf::noinit. */
+ static ConcretePacket createAfter(Packet packet, size_type size);
+ ///< Create default initialized packet after \a packet
+ /**< This member will create a default initialized packet
+ with the given size. If the size parameter is smaller
+ than the minimum allowed packet size an exception will
+ be thrown. It will be appended as next
+ header/interpreter after \a packet in that packets
+ interpreter chain.
+ \param[in] packet Packet to append new packet to.
+ \param[in] size Size of the packet to create in bytes.
+ \throws TruncatedPacketException if \a size is smaller
+ than the smallest permissible size for this type of
+ packet. */
+ static ConcretePacket createAfter(Packet packet, size_type size, NoInit_t);
+ ///< Create uninitialized packet after \a packet
+ /**< Creates an uninitialized (all-zero) packet of the exact
+ given size. It will be appended as next
+ header/interpreter after \a packet in that packets
+ interpreter chain.
+ \param[in] packet Packet to append new packet to.
+ \param[in] size Size of the packet to create in bytes
+ \param[in] noinit This parameter must always have the
+ value \c senf::noinit. */
+ template <class ForwardReadableRange>
+ static ConcretePacket createAfter(Packet packet,
+ ForwardReadableRange const & range);
+ ///< Create packet from given data after \a packet
+ /**< The packet will be created from a copy of the given
+ data. The data from the range will be copied directly
+ into the packet representation. The data will \e not be
+ validated in any way. It will be appended as next
+ header/interpreter after \a packet in that packets
+ interpreter chain.
+ \param[in] packet Packet to append new packet to.
+ \param[in] range <a
+ href="http://www.boost.org/libs/range/index.html">Boost.Range</a>
+ of data to construct packet from. */
+
+ // Create packet as new packet (header) before a given packet
+
+ static ConcretePacket createBefore(Packet packet);
+ ///< Create default initialized packet before \a packet
+ /**< The packet will be initialized to it's default empty
+ state. It will be prepended as previous
+ header/interpreter before \a packet in that packets
+ interpreter chain.
+ \param[in] packet Packet to prepend new packet to. */
+ static ConcretePacket createBefore(Packet packet, NoInit_t);
+ ///< Create uninitialized empty packet before \a packet
+ /**< Creates a completely empty and uninitialized packet. It
+ will be prepended as previous header/interpreter before
+ \a packet in that packets interpreter chain.
+ \param[in] packet Packet to prepend new packet to. */
+
+ // Create a clone of the current packet
+
+ ConcretePacket clone() const;
///@}
+ ///////////////////////////////////////////////////////////////////////////
- private:
-
- ///\name Implementation
- ///@{
-
- void add_ref() const;
- bool release();
- bool unlink();
+ // Field access
- struct PacketOp_register;
- friend class PacketOp_register;
- void i_registerInterpreter(Packet * p) const;
+ Parser * operator->() const; ///< Access packet fields
+ /**< This operator allows to access the parsed fields of the
+ packet using the notation <tt>packet->field()</tt>. The
+ fields of the packet are specified by the PacketType's
+ \c parser member.
- struct PacketOp_replace;
- friend class PacketOp_replace;
- void i_replaceInterpreter(Packet * p);
+ The members are not strictly restricted to simple field
+ access. The parser class may have any member which is
+ needed for full packet access (e.g. checksum validation
+ / recreation ...)
+ \see \ref packetparser for the parser interface. */
- struct PacketOp_set;
- friend class PacketOp_set;
- void i_setInterpreter(impl::PacketImpl * i);
+ protected:
private:
- friend class impl::PacketImpl;
- template <class OtherPacket> friend class impl::PkReg_EntryImpl;
+ typedef PacketInterpreter<PacketType> interpreter;
- impl::PacketImpl* impl_;
- size_type begin_;
- size_type end_;
- interpreter_list::iterator self_;
- mutable bool parsed_;
- mutable refcount_t refcount_;
+ ConcretePacket(typename interpreter::ptr packet_);
+
+ typename interpreter::ptr ptr() const;
- ///@}
+ friend class Packet;
+ friend class PacketInterpreter<PacketType>;
};
- /** \brief dump packet to stream
- \related Packet */
- // std::ostream & operator<<(std::ostream & os, Packet const & packet);
-
- /** \brief smart pointer handling
- \relates Packet */
- void intrusive_ptr_add_ref(Packet const *);
- /** \brief smart pointer handling
- \relates Packet */
- void intrusive_ptr_release(Packet *);
-
- struct TruncatedPacketException : public std::exception
- { virtual char const * what() const throw() { return "truncated packet"; } };
+ ///@}
}
-// ////////////////////////////hh.e////////////////////////////////////////
+///////////////////////////////hh.e////////////////////////////////////////
+#endif
+#if !defined(HH_Packets__decls_) && !defined(HH_Packet_i_)
+#define HH_Packet_i_
#include "Packet.cci"
#include "Packet.ct"
#include "Packet.cti"
-
-#include "Packet.mpp"
#endif
\f
// compile-command: "scons -u test"
// comment-column: 40
// End:
+