X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Packets%2FPacket.hh;h=ac77eedd960592819d9eaf2ab6af386c53809a19;hb=a4ebeef29f8eb69dc2dad10668d762540002b924;hp=44dcf2f7a82fc8791250ccae7808b9e5b4da0823;hpb=f00a102138bcbabdaab1caab1db6a8876463dedc;p=senf.git diff --git a/Packets/Packet.hh b/Packets/Packet.hh index 44dcf2f..ac77eed 100644 --- a/Packets/Packet.hh +++ b/Packets/Packet.hh @@ -1,6 +1,8 @@ -// 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 // // This program is free software; you can redistribute it and/or modify @@ -26,8 +28,10 @@ // Custom includes #include - +#include +#include #include "../Utils/Exception.hh" +#include "../Utils/Tags.hh" #include "../Utils/safe_bool.hh" #include "PacketInterpreter.hh" @@ -38,7 +42,7 @@ namespace senf { /** \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). @@ -95,16 +99,16 @@ namespace senf { ///\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 @@ -130,7 +134,7 @@ namespace senf { \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 */ @@ -143,13 +147,10 @@ namespace senf { // 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 ///@{ @@ -159,14 +160,14 @@ namespace senf { // 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 @@ -184,93 +185,84 @@ namespace senf { Packet next() const; ///< Get next packet in chain - /**< \returns in - valid() packet, if no next packet + /**< \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 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 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 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 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 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 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 + /**< \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 OtherPacket prev() const; - ///< Get previous packet of given type in chain - /**< \throws InvalidPacketChainException if no such packet - is found */ - template 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 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 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 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 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 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 OtherPacket first() const; - ///< Return first packet of given type in chain - /**< \throws InvalidPacketChainException if no such packet - is found */ - template 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 OtherPacket last() const; - ///< Return last packet of given type in chain - /**< \throws InvalidPacketChainException if no such packet - is found */ - template 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 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 @@ -279,32 +271,32 @@ namespace senf { \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 bool is() const; ///< Check, whether \c this packet is of the given type template 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. This conversion is - unchecked. 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. */ @@ -322,6 +314,68 @@ namespace senf { ///@} + ///\name Annotations + ///@{ + + template + 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().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 ///@{ @@ -338,17 +392,72 @@ namespace senf { 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 + 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 + 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()) + \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 @@ -428,6 +537,7 @@ namespace senf { // Types typedef PacketType type; + typedef typename PacketType::parser Parser; /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members @@ -452,10 +562,10 @@ namespace senf { 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 size() == 0. - \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 @@ -466,12 +576,19 @@ namespace senf { \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 + static ConcretePacket create( + ForwardReadableRange const & range, + typename boost::disable_if< boost::is_integral >::type * = 0); +#else template static ConcretePacket create(ForwardReadableRange const & range); ///< Create packet from given data @@ -482,6 +599,7 @@ namespace senf { \param[in] range Boost.Range of data to construct packet from. */ +#endif // Create packet as new packet after a given packet @@ -491,14 +609,14 @@ namespace senf { 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 size() == 0. 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 @@ -513,7 +631,7 @@ namespace senf { \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 @@ -521,8 +639,15 @@ namespace senf { 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 + static ConcretePacket createAfter( + Packet packet, + ForwardReadableRange const & range, + typename boost::disable_if< boost::is_integral >::type * = 0); +#else template static ConcretePacket createAfter(Packet packet, ForwardReadableRange const & range); @@ -537,6 +662,7 @@ namespace senf { \param[in] range Boost.Range of data to construct packet from. */ +#endif // Create packet as new packet (header) before a given packet @@ -547,7 +673,7 @@ namespace senf { 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 @@ -563,7 +689,7 @@ namespace senf { // 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 packet->field(). The fields of the packet are specified by the PacketType's @@ -575,6 +701,13 @@ namespace senf { / 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: