-// Copyright (C) 2007
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// $Id$
+//
+// 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
// Custom includes
#include <boost/operators.hpp>
-
+#include <boost/utility.hpp>
+#include <boost/type_traits/is_integral.hpp>
#include "../Utils/Exception.hh"
-#include "../Utils/SafeBool.hh"
+#include "../Utils/Tags.hh"
+#include "../Utils/safe_bool.hh"
#include "PacketInterpreter.hh"
//#include "Packet.mpp"
/** \defgroup packet_module Packet Handling
- The basic groundwork of the Packet library is the 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).
///\addtogroup packet_module
///@{
- /** \brief Main Packet class
+ /** \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
+ %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
+ %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.
+ class extending %Packet is provided.
\section packet_semantics Semantics
\ref ConcretePacket < \ref EthernetPacketType >).
\see
- \ref ConcretePacket for the type specific interface\n
+ \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
- : public SafeBool<Packet>,
+ : public safe_bool<Packet>,
public boost::equality_comparable<Packet>
{
public:
// Types
typedef void type; ///< Type of the packet.
- typedef senf::detail::packet::size_type size_type; ///< Unsigned type to represent packet size
+ 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)
- /// Special argument flag
- /** Used in some ConcretePacket constructors */
- enum NoInit_t { noinit };
-
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
// default destructor
Packet(); ///< Create uninitialized packet handle
- /**< An uninitialized handle is not valid(). It does not
+ /**< 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 the packet. The
- returned packet will have the same data and packet
- chain. It does however not share any data with the
- original 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
Packet next() const;
///< Get next packet in chain
+ /**< \throws InvalidPacketChainException 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 of given type in chain
- /**< \throws InvalidPacketChainException if no such packet
- is found */
+ ///< Get next packet in chain and cast to \a OtherPacket
+ /**< \throws std::bad_cast if the next() packet is not of
+ type \a OtherPacket
+ \throws InvalidPacketChainException if no next packet
+ exists */
template <class OtherPacket> OtherPacket next(NoThrow_t) const;
- ///< Get next packet of given type in chain
- /**< \param[in] nothrow This argument always has the value
- \c senf::nothrow
- \returns in-valid() packet, if no such packet is found */
- template <class OtherPacket> OtherPacket findNext() const;
- ///< Find next packet of given type in chain
- /**< findNext() is like next(), it will however return \c
- *this if it is of the given type.
- \throws InvalidPacketChainException if no such packet
- is found */
- template <class OtherPacket> OtherPacket findNext(NoThrow_t) const;
- ///< Find next packet of given type in chain
- /**< findNext() is like next(), it will however return \c
- *this if it is of the given type.
- \param[in] nothrow This argument always has the value
- \c senf::nothrow
- \returns in-valid() packet, if no such packet is found */
+ ///< 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.
+ \throws InvalidPacketChainException 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
+ /**< \throws InvalidPacketChainException 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 of given type in chain
- /**< \throws InvalidPacketChainException if no such packet
- is found */
- template <class OtherPacket> OtherPacket prev(NoThrow_t) const;
- ///< Get previous packet of given type in chain
- /**< \param[in] nothrow This argument always has the value
- \c senf::nothrow
- \returns in-valid() packet, if no such packet is found */
- template <class OtherPacket> OtherPacket findPrev() const;
- ///< Find previous packet of given type in chain
- /**< findPrev() is like prev(), it will however return \c
- *this if it is of the type
- \throws InvalidPacketChainException if no such packet
- is found */
- template <class OtherPacket> OtherPacket findPrev(NoThrow_t) const;
- ///< Find previous packet of given type in chain
- /**< findPrev() is like prev(), it will however return \c
- *this if it is of the type
- \param[in] nothrow This argument always has the value
- \c senf::nothrow
- \returns in-valid() packet, if no such packet is found */
+ ///< Get previous packet in chain and cast to \a OtherPacket
+ /**< \throws std::bad_cast, if the previous packet is not of
+ type \a OtherPacket
+ \throws InvalidPacketChainException 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.
+ \throws InvalidPacketChainException 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 of given type in chain
- /**< \throws InvalidPacketChainException if no such packet
- is found */
- template <class OtherPacket> OtherPacket first(NoThrow_t) const;
- ///< Return first packet of given type in chain
- /**< \param[in] nothrow This argument always has the value
- \c senf::nothrow
- \returns in-valid() packet, if no such packet is found */
+ ///< 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 of given type in chain
- /**< \throws InvalidPacketChainException if no such packet
- is found */
- template <class OtherPacket> OtherPacket last(NoThrow_t) const;
- ///< Return last packet of given type in chain
- /**< \param[in] nothrow This argument always has the value
- \c senf::nothrow
- \returns in-valid() packet, if no such packet is found */
+ ///< 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;
- ///< Parse payload as given by \a OtherPacket and add packet
+ ///< 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
\returns new packet instance sharing the same data and
placed after \c this packet in the chain. */
Packet parseNextAs(factory_t factory) const;
- ///< Parse payload as given by \a factory and add packet
+ ///< 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
- OtherPacket. The new packet is added to the chain after
+ 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. <b>This conversion is
- unchecked</b>. If the packet really is of a different
- type, this will wreak havoc with the packet
- data-structures. You can validate whether the
- conversion is valid using is(). */
+ 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 if \a packet.
+ 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 Annotations
+ ///@{
+
+ template <class Annotation>
+ Annotation & annotation(); ///< Get packet annotation
+ /**< This member will retrieve an arbitrary packet
+ annotation. Every annotation is identified by a unique
+ \a Annotation type. This type should \e always be a \c
+ struct.
+
+ \code
+ struct MyAnnotation {
+ int value;
+ };
+
+ senf::Packet p (...);
+
+ p.annotation<MyAnnotation>().value = 1;
+ \endcode
+
+ Annotations are shared by all headers / interpreters
+ within a single packet chain.
+
+ If an annotation is \e not a POD type (more
+ specifically, if it's constructor or destructor is not
+ trivial including base classes and members), the \a
+ Annotation type \e must inherit from
+ senf::ComplexAnnotation. Failing to follow this rule
+ will result in undefined behavior and will probably
+ lead to a program crash.
+
+ \code
+ struct MyStringAnnotation : senf::ComplexAnnotation {
+ std::string value;
+ };
+ \endcode
+ (This type is not POD since \c std::string is not POD)
+
+ \see \ref packet_usage_annotation
+
+ \implementation The annotation system is implemented
+ quite efficiently since annotations are stored
+ within a packet embedded vector of fixed size (the
+ size is determined automatically at runtime by the
+ number of different annotations
+ used). Additionally, non-complex small annotations
+ require no additional memory management (\c new /
+ \c delete).
+
+ \idea Pool the annotation vectors: In the destructor
+ swap the vector into a vector graveyard (swapping
+ two vectors is an O(1) no allocation operation). In
+ the constructor, if there is a vector in the
+ graveyard, swap it in from there. Of course, it
+ would be better to do away with the vector and just
+ allocate the space together with the packet but
+ that looks quite complicated to do ... especially
+ considering that the packetimpl itself uses a pool.
+ */
+
+ ///@}
+
///\name Other methods
///@{
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. */
-
-
- 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
+ /**< 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 finalizeThis(); ///< Update calculated fields
+ /**< The finalize() fammily of members will update
+ calculated packet fields: checksums, size fields and so
+ on. This includes any field, which can be set from
+ other information in the packet. Each concrete packet
+ type should document, which fields are set by
+ finalize().
+
+ finalizeThis() will \e only process the current
+ header. Even if only changing fields in this protocol,
+ depending on the protocol it may not be enough to
+ finalize this header only. See the packet type
+ documentation. */
+
+ template <class Other>
+ void finalizeTo(); ///< Update calculated fields
+ /**< The finalize() fammily of members will update
+ calculated packet fields: checksums, size fields and so
+ on. This includes any field, which can be set from
+ other information in the packet. Each concrete packet
+ type should document, which fields are set by
+ finalize().
+
+ finalizeTo() will automatically process all
+ packets/headers/interpreters from the \e first
+ occurrence of packet type \a Other (beginning at \c
+ this packet searching forward towards deeper nested
+ packets) backwards up to \c this.
+
+ This call is equivalent to
+ \code
+ p.finalizeTo(p.next<Other>())
+ \endcode */
+
+ void finalizeTo(Packet other); ///< Update calculated fields
+ /**< The finalize() fammily of members will update
+ calculated packet fields: checksums, size fields and so
+ on. This includes any field, which can be set from
+ other information in the packet. Each concrete packet
+ type should document, which fields are set by
+ finalize().
+
+ finalizeTo(other) will automatically process all
+ packets/headers/interpreters beginning at \a other
+ backwards towards outer packets up to \c this. */
+
+ void finalizeAll(); ///< Update calculated fields
+ /**< The finalize() fammily of members will update
+ calculated packet fields: checksums, size fields and so
+ on. This includes any field, which can be set from
+ other information in the packet. Each concrete packet
+ type should document, which fields are set by
+ finalize().
+
+ finalizeAll() will automatically process all
packets/headers/interpreters from the end of the chain
- backwards up to \c this. */
+ (the most inner packet) backwards up to \c this.
+
+ This call is equivalent to
+ \code
+ p.finalizeTo(p.last())
+ \endcode
+
+ Beware, that finalizeAll() will \e not finalize any
+ headers before \c this, it will \e only process inner
+ headers. */
void dump(std::ostream & os) const; ///< Write out a printable packet representation
/**< This method is provided mostly to help debugging packet
template <class PacketType>
friend class ConcretePacket;
+ friend class PacketParserBase;
};
/** \brief Protocol specific packet handle
// Types
typedef PacketType type;
+ typedef typename PacketType::parser Parser;
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
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
+ static ConcretePacket create(senf::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
+ \param[in] senf::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
\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
+ static ConcretePacket create(size_type size, senf::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
+ \param[in] senf::noinit This parameter must always have the
value \c senf::noinit. */
+#ifndef DOXYGEN
+ template <class ForwardReadableRange>
+ static ConcretePacket create(
+ ForwardReadableRange const & range,
+ typename boost::disable_if< boost::is_integral<ForwardReadableRange> >::type * = 0);
+#else
template <class ForwardReadableRange>
static ConcretePacket create(ForwardReadableRange const & range);
///< Create packet from given data
\param[in] range <a
href="http://www.boost.org/libs/range/index.html">Boost.Range</a>
of data to construct packet from. */
+#endif
// Create packet as new packet after a given packet
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);
+ static ConcretePacket createAfter(Packet packet, senf::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
+ \param[in] senf::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
\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);
+ static ConcretePacket createAfter(Packet packet, size_type size, senf::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
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
+ \param[in] senf::noinit This parameter must always have the
value \c senf::noinit. */
+#ifndef DOXYGEN
+ template <class ForwardReadableRange>
+ static ConcretePacket createAfter(
+ Packet packet,
+ ForwardReadableRange const & range,
+ typename boost::disable_if< boost::is_integral<ForwardReadableRange> >::type * = 0);
+#else
template <class ForwardReadableRange>
static ConcretePacket createAfter(Packet packet,
ForwardReadableRange const & range);
\param[in] range <a
href="http://www.boost.org/libs/range/index.html">Boost.Range</a>
of data to construct packet from. */
+#endif
// Create packet as new packet (header) before a given packet
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);
+ static ConcretePacket createBefore(Packet packet, senf::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
// Field access
- typename type::parser * operator->() const; ///< Access packet fields
+ 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
/ recreation ...)
\see \ref packetparser for the parser interface. */
+ Parser parser() const; ///< Access packet field parser directly
+ /**< Access the parser of the packet. This is the same
+ object returned by the operator->() operator. The
+ operator however does not allow to access this object
+ itself, only it's members.
+ \see \ref packetparser for the parser interface */
+
protected:
private:
///////////////////////////////hh.e////////////////////////////////////////
#endif
-#if !defined(SENF_PACKETS_DECL_ONLY) && !defined(HH_Packet_i_)
+#if !defined(HH_Packets__decls_) && !defined(HH_Packet_i_)
#define HH_Packet_i_
#include "Packet.cci"
#include "Packet.ct"