X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Packets%2FPacket.hh;h=d1485984cffe316497da488b3dea81abdb6ff00c;hb=5443435c4c2b6e4386c5334b5b8358273f2bae93;hp=ef25f14b4002410450d0865cc6a97f03fadd5fb3;hpb=c52cd7d87dbb525c1267aad27391b8b7365dbb57;p=senf.git diff --git a/Packets/Packet.hh b/Packets/Packet.hh index ef25f14..d148598 100644 --- a/Packets/Packet.hh +++ b/Packets/Packet.hh @@ -1,9 +1,9 @@ // $Id$ // -// Copyright (C) 2006 -// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) -// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) -// Stefan Bund +// 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 // it under the terms of the GNU General Public License as published by @@ -20,687 +20,754 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// 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 deque -// implementation. - - -/** \mainpage The SatCom Packet Framework - - \section arch Overall Architecture - - The general Architecture of the Packet Framework (pkf for short) - is seperated into two components: The basic packet handling and - the parser framework. - - The basic packet handling implements a packet interpreter - chain. Every packet is represented as a chain of interpreters - where each interpreter is a facade looking into the same - packet. Each interpreter will interpret a specific header of a - packet. For example, an ethernet frame might have an interpreter - chain consisting of EthernetPacket, IPPacket, UDPPacket and - DataPacket. Each of these interpreters will interpret a section of - the raw data bytes. The interpreter ranges overlap since every - packet also includes it's payload. - - The parser framework is used to interpret the raw bytes of a - specific packet and parse the values present in that packet. For - example, Parse_Ethernet will parse the ethernet source MAC, - destination MAC and ethertype given any random access iterator to - the first byte of the ethernet frame. Parsers are extremely light - classes. They are temporary classes passed around by value. In - most cases, they are just comprised of a single pointer adorned - with type information. - - \section handling Packet Handling - - The packet handling is implemented within - satcom::pkf::Packet. This class is the baseclass to all packet - interpreter facades. To implement a new packet type, publically - derive from satcom::pkf::Packet and implement the virtual - interface (see the class documentation for details). - - \section framework Parser Framework - - The parser framework provides an abstract framwork to parse packet - oriented data. A Parser is a template class taking an arbitrary - iterator as input and allowing random access to data elements of - the interpreted type, like source and destination MAC of an - ethernet frame. The parser framework is to be used hierarchically - and recursively, the parser methods should return further parsers - which can return further parsers and so on. +/** \file + \brief Packet public header */ - The parser framework contains some basic parsers to be used to - build up more complex parsers: +#ifndef HH_SENF_Packets_Packet_ +#define HH_SENF_Packets_Packet_ 1 - - ParseInt.hh: Lots of parsers for integer numbers like - satcom::pkf::Parse_UInt8, for integer bitfields like - satcom::pkf::Parse_UIntField and satcom::pkf::Parse_Flag to - parse boolean flags. +// Custom includes +#include +#include +#include +#include "../Utils/Exception.hh" +#include "../Utils/Tags.hh" +#include "../Utils/safe_bool.hh" +#include "PacketInterpreter.hh" - - ParseArray.hh: The satcom::pkf::Parse_Array parser to parse - arbitrary fixed-size arrays of fixed-size elements (that is - sub-parsers). +//#include "Packet.mpp" +///////////////////////////////hh.p//////////////////////////////////////// - - ParseVec.hh: The satcom::pkf::Parse_Vector parser to parse - dynamically sized arrays of fixed-size elements (that is - sub-parsers). +namespace senf { - See satcom::pkf::ParserBase for further information. + /** \defgroup packet_module Packet Handling - \section stuff Other Utilities + The basic groundwork of the %Packet library is the packet handling: - The pkf also comprises some additional utilities to support the - development of packet classes. + \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. - The satcom::pkf::PacketRegistry implements a registry of packets - keyed by an arbitrary type. The registry is used to find a packet - type given some kind of id (like the ethertype value from the - ethernet header). Together with it's support classes (especially - satcom::pkf::PacketRegistryMixin) this class greatly simplifies - implementing the needed table lookups. - */ + \section packet_module_chain The Interpreter Chain -/** \file - \brief Main packet interface - */ + The central data structure for a packet is the interpreter chain -#ifndef HH_Packet_ -#define HH_Packet_ 1 + \image html structure.png The Interpreter Chain -// Custom includes -#include // for boost::noncopyable -#include -#include -#include -#include -#include -#include - -#include "Packet.mpp" -// ////////////////////////////hh.p//////////////////////////////////////// - -namespace satcom { -namespace pkf { + 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. - namespace impl { template class PkReg_EntryImpl; } - namespace impl { class PacketImpl; } + 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 ConcretePacket; + + ///\addtogroup packet_module + ///@{ + + /** \brief Main %Packet class - /** \brief Basic interface to all packet facades + %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. - \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. satcom::pkf::Packet manages the necessary memory - resources and controlls 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 class's packet - type (i.e. EthernetPacket or UDPPacket). + %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. - Packet provides several interfaces: + \section packet_semantics Semantics - - 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 satcom::pkf::Packet - { - public: - typedef ptr_t::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 - ExamplePacket(Arg arg [, other args ... ]) - : satcom::pkf::Packet(arg) - {} - - virtual void v_nextInterpreter() const - { - // NextPacketType and header_length of course - // depend on the packet type - registerInterpreter(begin()+header_length, end()); - } - - virtual void v_finalize() - { - // calculate checksum etc - } - - friend class satcom::pkf::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 - satcom:pkf::PacketRegistry, it must not take any additional - constructor parameters. - - After having implemented the bare framework, the most comman - 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 satcom::pkf::Packet, - public Parse_Example - { - - // check does not need to be implemented here, it is - // inherited from the parser - - private: - template - ExamplePacket(InputIterator begin, InputIterator end) - : satcom::pkf::Packet(begin,end) - {} - }; - \endcode - - See the satcom::pkf::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 - satcom::pkf::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 satcom::pkf::Packet, - public Parse_Example, - public satcom::pkf::PacketRegistryMixin - { - using satcom::pkf::Packet::registerInterpreter; - using satcom::pkf::PacketRegsitryMixin::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 - satcom::pkf::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 ist the container class used to hold the raw - data. This currently is an \a std::vector. This could be - imporved 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 - satcom::lib::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 requestd 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 externaly 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 - */ - class Packet : boost::noncopyable + 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 + : public safe_bool, + public boost::equality_comparable { 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 raw_container; - typedef boost::shared_ptr interpreter_list_ptr; - typedef std::list interpreter_list; - typedef unsigned refcount_t; - - ///@} - - public: + /////////////////////////////////////////////////////////////////////////// + // 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) /////////////////////////////////////////////////////////////////////////// - ///\name Types + ///\name Structors and default members ///@{ + + // default copy constructor + // default copy assignment + // default destructor - /** \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 struct ptr_t { typedef boost::intrusive_ptr 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::ptr ptr - \endcode - */ - typedef ptr_t::ptr ptr; - typedef raw_container::iterator iterator; //!< raw data iterator - typedef raw_container::size_type size_type; - typedef raw_container::difference_type difference_type; + 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 + Packet(ConcretePacket 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 trunctated or just - plain invalid) - */ - template - static typename ptr_t::ptr create(InputIterator b, InputIterator e); - - template - static typename ptr_t::ptr create(); - - template - static typename ptr_t::ptr create(Packet::ptr payload); + 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 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 + \throws InvalidPacketChainException if no next packet + exists */ + template 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 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 + /**< \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 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 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 in chain and cast + /**< \throws std::bad_cast if the last() packet is not of + type \a OtherPacket */ + + + template 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. + \throws InvalidPacketChainException if no next + packet header is allowed (viz. nextPacketRange() of the the current + PacketType returns no_range() ) */ + 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. + \throws InvalidPacketChainException if no next + packet header is allowed (viz. nextPacketRange() of the the current + PacketType returns no_range() ) */ + + 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. + \throws std::bad_cast if the current packet is not of + type \a OtherPacket */ + + Packet append(Packet const & 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 typename ptr_t::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 typename ptr_t::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 typename ptr_t::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 typename ptr_t::ptr get_prev() const; - - /** \brief check, wether the packet is of the given type - \return true, if packt is of type \a OtherPacket, false - otherwise */ - template 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 typename ptr_t::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 savely interpret the packet as the given type. The - original packet is \e not invalidated - */ - template - typename ptr_t::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 Annotations ///@{ - /** \brief begin interator 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 - - // FIXME: Make all data mutators protected - - 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 - 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); + 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. + */ ///@} - void dump(std::ostream & os) const; + template + Annotation const & annotation() const; ///< Get packet annotation + /**< \see annotation() */ - protected: - ///\name Derived class interface + ///\name Other methods ///@{ - /** \brief create new interpreter facade for an existing 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 - Packet(Operation const & arg); - virtual ~Packet(); - - private: - /** \brief create next packet interpreter + bool operator==(Packet const & 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 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 const & 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 + (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 + 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. */ - 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 satcom::pkf::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 + protected: + explicit Packet(PacketInterpreterBase::ptr packet); - 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 calcaulate checksums and - such. + PacketInterpreterBase::ptr ptr() const; - This method is autmatically called for all interpreters on - the interpreter chain. - */ - virtual void v_finalize() = 0; + private: + Packet checkNext() const; + Packet checkLast() const; - virtual void v_dump(std::ostream & os) const = 0; + PacketInterpreterBase::ptr packet_; - 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 - typename ptr_t::ptr registerInterpreter( - raw_container::iterator begin, raw_container::iterator end) const; - template - typename ptr_t::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() + template + friend class ConcretePacket; + friend class PacketParserBase; + }; - ///@} + /** \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 ConcretePacket + : public Packet + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types - private: + typedef PacketType type; + typedef typename PacketType::parser Parser; - ///\name Implementation + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members ///@{ - void add_ref() const; - bool release(); - bool unlink(); + // 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(senf::NoInit_t); ///< Create uninitialized empty packet + /**< This will create a completely empty and uninitialized + packet with size() == 0. + \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 + 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, 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] 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 + /**< 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 Boost.Range + of data to construct packet from. */ +#endif - struct PacketOp_register; - friend class PacketOp_register; - void i_registerInterpreter(Packet * p) const; + // Create packet as new packet after a given packet + + static ConcretePacket createAfter(Packet const & 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 const & 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] senf::noinit This parameter must always have the + value \c senf::noinit. */ + static ConcretePacket createAfter(Packet const & 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 const & 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 + 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] senf::noinit This parameter must always have the + value \c senf::noinit. */ +#ifndef DOXYGEN + template + static ConcretePacket createAfter( + Packet const & packet, + ForwardReadableRange const & range, + typename boost::disable_if< boost::is_integral >::type * = 0); +#else + template + static ConcretePacket createAfter(Packet const & 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 Boost.Range + of data to construct packet from. */ +#endif - struct PacketOp_replace; - friend class PacketOp_replace; - void i_replaceInterpreter(Packet * p); + // Create packet as new packet (header) before a given packet + + static ConcretePacket createBefore(Packet const & 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 const & 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 + \a packet in that packets interpreter chain. + \param[in] packet Packet to prepend new packet to. */ + + // Create a clone of the current packet - struct PacketOp_set; - friend class PacketOp_set; - void i_setInterpreter(impl::PacketImpl * i); + ConcretePacket clone() const; + + ///@} + /////////////////////////////////////////////////////////////////////////// + + // Field access + + struct ParserProxy + { + ParserProxy(Parser const & p) : p_ (p) {} + Parser * operator->() { return &p_; } + Parser p_; + }; + + ParserProxy 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 + \c parser member. + + 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. */ + + 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: - friend class impl::PacketImpl; - template friend class impl::PkReg_EntryImpl; + typedef PacketInterpreter 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; }; - /** \brief dump packet to stream - \related Packet */ - // std::ostream & operator<<(std::ostream & os, Packet const & packet); + /** \brief Generic parser copying - /** \brief smart pointer handling - \relates Packet */ - void intrusive_ptr_add_ref(Packet const *); - /** \brief smart pointer handling - \relates Packet */ - void intrusive_ptr_release(Packet *); + This operator allows to copy the value of identical parsers. This operation does \e not + depend on the parsers detailed implementation, it will just replace the data bytes of the + target parser with those from the source packet. + */ + template + Parser operator<<(Parser target, ConcretePacket const & packet); - struct TruncatedPacketException : public std::exception - { virtual char const * what() const throw() { return "truncated packet"; } }; + ///@} -}} +} -// ////////////////////////////hh.e//////////////////////////////////////// +///////////////////////////////hh.e//////////////////////////////////////// +#endif +#if !defined(HH_SENF_Packets_Packets__decls_) && !defined(HH_SENF_Packets_Packet_i_) +#define HH_SENF_Packets_Packet_i_ #include "Packet.cci" #include "Packet.ct" #include "Packet.cti" - -#include "Packet.mpp" #endif // Local Variables: // mode: c++ -// c-file-style: "satcom" +// fill-column: 100 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// comment-column: 40 // End: +