X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Packets%2FPacket.hh;h=f4bc724f251d04a8262af24390176d3b96a206ee;hb=47368f306a577d1e46df69a7f729bd3893cbe5e7;hp=64fcb78bb67eb93b6ab13a5f4481e59f0c38420f;hpb=9e333f86141055c5248a46028a571c932648696a;p=senf.git diff --git a/Packets/Packet.hh b/Packets/Packet.hh index 64fcb78..f4bc724 100644 --- a/Packets/Packet.hh +++ b/Packets/Packet.hh @@ -1,9 +1,7 @@ -// $Id$ -// -// Copyright (C) 2006 +// Copyright (C) 2007 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) // Kompetenzzentrum fuer Satelitenkommunikation (SatCom) -// Stefan Bund +// 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 @@ -21,602 +19,213 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief Main packet interface - - \todo Implement assign() method akin to reinterpret(). However, - instead of using the data already present, assign() will replace - the date of the current packet with the given Packet. - - \todo Implement wrapping-constructor. Somehow we want to have a - constructor, which allows creating a chain of packet interpreters - with as little overhead as possible. - - \todo Document the additional concrete Packet facade requirements - explicitly and not only within the Parser requirements (check(), - bytes() and min_bytes() members ...) - - \todo Implement special container replacing vector which manages - some headroom to allow efficient insertion of elements at the - beginning. This really is just another type of dequeue - implementation. - */ + \brief Packet public header */ #ifndef HH_Packet_ #define HH_Packet_ 1 // Custom includes -#include // for boost::noncopyable -#include -#include -#include -#include -#include -#include +#include + +#include "Utils/Exception.hh" +#include "Utils/SafeBool.hh" +#include "PacketInterpreter.hh" -#include "Packet.mpp" -// ////////////////////////////hh.p//////////////////////////////////////// +//#include "Packet.mpp" +///////////////////////////////hh.p//////////////////////////////////////// namespace senf { - namespace impl { template class PkReg_EntryImpl; } - namespace impl { class PacketImpl; } - - /** \brief Basic interface to all packet facades - - \section packet_overview Overview - - This class is the base class of all Packets. It implements the - generic Packet interface and provides the packet management - framework. senf::Packet manages the necessary memory - resources and controls the chain of packet interpreters. - - The Packet user always interfaces with the pkf via a Packet - derived class. This is the only external entity ever held by a - library user. The interface is implemented using a reference - counted smart pointer, so resource management is quasi - automatic. - - \image html structure.png Overview - - Internally, every Packet references a PacketImpl instance which - manages the raw packet data and the interpreter list. This raw - data is interpreted by the concrete Packet derived class - according to the definition of that derived classes packet - type (i.e. EthernetPacket or UDPPacket). - - Packet provides several interfaces: - - - Creation of Packet instances: create() - - - Access to the chain of interpreters: next(), prev(), head(), - last(), find_next(), find_prev(), get_next(), get_prev(), - is(), as() and reinterpret() - - - Access to the raw packet data: begin(), end(), size(), - insert() and erase() - - - An interface to the derived class: v_nextInterpreter(), - v_finalize(), registerInterpreter() - - - \section packet_der Implementing new Packet facades - - To implement a new Packet facade, publically derive from - Packet. You need to implement the following minimal interface: - - - You need to provide a new #ptr typedef - - - You have to implement v_nextInterpreter() and v_finalize() - - - The constructor should be private - - - You must make Packet a \c friend of the new Packet facade - - - You must implement a static check() method which validates - a byte region as your new Packet - - \code - class ExamplePacket - : public senf::Packet - { - public: - typedef ptr_t::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 ... ]) - : senf::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 senf::Packet; - }; - \endcode - - Please do not implement the methods inline to not clutter up - the header file. This is done here in the example to simplify - it. If a class is to be registered in some - senf:PacketRegistry, it must not take any additional - constructor parameters. - - After having implemented the bare framework, the most common - way to implement access to the packets specific data is to use - the parser framework by additionally inheriting a - corresponding parser. This also automatically implements the - check() method, which is provided by the Parser. - - In the following example we only show the differences from the - previous example: - - \code - class ExamplePacket - : public senf::Packet, - public Parse_Example - { - - // check does not need to be implemented here, it is - // inherited from the parser - - private: - template - ExamplePacket(InputIterator begin, InputIterator end) - : senf::Packet(begin,end) - {} - }; - \endcode - - See the senf::ParserBase Documentation for how to - implement Parse_Example. - - The implementation of v_nextInterpreter most of the time - relies on some packet registry. This is simplified using the - senf::PacketRegistryMixin class as follows. Again, we - only show the differences from the preceding Example: - - \code - struct ExampleRegistry { - type boost::uint16_t key_t; - }; - - class ExamplePacket - : public senf::Packet, - public Parse_Example, - public senf::PacketRegistryMixin - { - using senf::Packet::registerInterpreter; - using senf::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 - senf::PacketRegistry. - - \section packet_impl Implementation details - - The Packet interface is implemented to minimize overhead as - far as possible without getting to complex. One area for - improvement is the container class used to hold the raw - data. This currently is an \a std::vector. This could be - improved by either allocating some headroom/tailroom in the - vector and using this when inserting data at the beginning or - end. Alternatively, a new container class (like the - senf::deque_list) could be used to support zero-copy - semantics. - - At the moment, we leave the implementation at - std::vector. This container is very simple and especially it - can directly be sent out using the operating system since a \a - vector stores data at contiguous memory locations. An \a - std::deque could be used with \a writev(), however since we - have no access to the implementation details of the \a deque, - we cannot construct the \a writev() data structures. - - The interpreter list managed by Packet is lazy, meaning packet - interpreter facades are added only when requested by next(), - last() or find_next(). v_nextInterpreter() is called if - necessary by these methods to complete the interpreter chain. - - To implement the automatic memory management, every Packet - facade is reference counted. Additionally, the number of - (indirect) references to PacketImpl is counted. This allows to - manage the PacketImpl instance automatically. To make this - work, it is necessary to ensure throughout the Packet code, - that the reference count of a Packet is not accidentally - decremented to zero. Also, the internal pointers from the - interpreter list to the Packet facades must not be - counted. They are therefore implemented differently ( - boost::shared_ptr vs. boost::intrusive_ptr). The choice of - boost::intrusive_ptr for the externally visible smart pointer - for all Packet facades is taken to reduce the overhead (an - intrusive_ptr is only the size of an ordinary pointer, a - smart_ptr has the size of two pointers). - - \nosubgrouping + template class ConcretePacket; + + /** \brief */ - class Packet : boost::noncopyable + class Packet + : public SafeBool, + 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; + typedef senf::detail::packet::iterator iterator; + typedef senf::detail::packet::const_iterator const_iterator; + typedef senf::detail::packet::size_type size_type; + typedef senf::detail::packet::difference_type difference_type; + typedef senf::detail::packet::byte byte; + typedef PacketInterpreterBase::factory_t factory_t; + + enum NoInit_t { noinit }; /////////////////////////////////////////////////////////////////////////// - ///\name Types + ///\name Structors and default members ///@{ - /** \brief smart pointer template for all Packet classes - - This struct is just a template typedef. It defines the - smart pointer used for all Packet classes. - */ - template struct ptr_t { typedef boost::intrusive_ptr ptr; }; + // default copy constructor + // default copy assignment + // default destructor + + Packet(); + Packet clone() const; - /** \brief smart pointer to the Packet facades + // conversion constructors - 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; + template + Packet(ConcretePacket packet); ///@} + /////////////////////////////////////////////////////////////////////////// - // //////////////////////////////////////////////////////////////////////// - - ///\name Creating packets + ///\name Interpreter chain access ///@{ - /** \brief create new Packet + Packet next() const; + template OtherPacket next() const; + template OtherPacket next(NoThrow_t) const; + template OtherPacket findNext() const; + template OtherPacket findNext(NoThrow_t) const; + + Packet prev() const; + template OtherPacket prev() const; + template OtherPacket prev(NoThrow_t) const; + template OtherPacket findPrev() const; + template OtherPacket findPrev(NoThrow_t) const; + + Packet first() const; + template OtherPacket first() const; + template OtherPacket first(NoThrow_t) const; - 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. + Packet last() const; + template OtherPacket last() const; + template OtherPacket last(NoThrow_t) const; - \param OtherPacket Type of Packet to create, a Packet - derived class - \param b begin iterator of byte range to create the Packet - from - \param e corresponding end iterator - \return smart pointer to new packet - \throws TruncatedPacketException The data cannot be parsed - securely (the data might be truncated or just - plain invalid) - */ - template - static typename ptr_t::ptr create(InputIterator b, InputIterator e); - template - static typename ptr_t::ptr create(); + template OtherPacket parseNextAs() const; + Packet parseNextAs(factory_t factory) const; + template bool is() const; + template OtherPacket as() const; - template - static typename ptr_t::ptr create(Packet::ptr payload); + Packet append(Packet packet) const; ///@} - ///\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, whether the packet is of the given type - \return true, if packet 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 safely interpret the packet as the given type. The - original packet is \e not invalidated - */ - template - typename ptr_t::ptr reinterpret(); - + PacketData & data() const; + size_type size() const; + ///@} - ///\name Raw packet data + ///\name Other methods ///@{ - /** \brief begin iterator of raw packet data - - This iterator allows access to the raw data interpreted by - the packet facade. This \e includes any header possibly - interpreted by the derived packet instance. To access the - payload of the packet, use next()->begin(). - - \return random access iterator to the begin of the raw - data */ - iterator begin() const; - /** \brief past-the-end iterator of raw packet data - - This iterator allows access to the raw data interpreted by - the packet facade. This \e includes any header possibly - interpreted by the derived packet instance. To access the - payload of the packet, use next()->end(). - - \return random access past-the-end iterator of the raw - data */ - iterator end() const; - /** \brief raw data size of packet - \return size of the raw data interpreted by this - packet in bytes. This is \e not necessarily the size of - the complete packet, use head()->size() for this. */ - size_t size() const; - - // Modifying the raw packet data - - typedef enum { AUTO, BEFORE, INSIDE, OUTSIDE, AFTER } Whence; - - /** \brief insert single byte \a v before pos - - \attention The change will \e not be validated by the - derived packet instance. This method is mostly to be used - by the derived class implementation and their helper - classes. */ - void insert(iterator pos, byte v, Whence whence = AUTO); - /** \brief insert \a n copies of byte \a v before pos - - \attention The change will \e not be validated by the - derived packet instance. This method is mostly to be used - by the derived class implementation and their helper - classes. */ - void insert(iterator pos, size_type n, byte v, Whence whence = AUTO); - /** \brief insert a copy of the given range before pos - - \attention The change will \e not be validated by the - derived packet instance. This method is mostly to be used - by the derived class implementation and their helper - classes. */ - template - void insert(iterator pos, InputIterator f, InputIterator l, Whence whence = AUTO); - - /** \brief erase single byte - - \attention The change will \e not be validated by the - derived packet instance. This method is mostly to be used - by the derived class implementation and their helper - classes. */ - void erase(iterator pos); - /** \brief erase range - - \attention The change will \e not be validated by the - derived packet instance. This method is mostly to be used - by the derived class implementation and their helper - classes. */ - void erase(iterator first, iterator last); + bool operator==(Packet other) const; + bool boolean_test() const; - ///@} + void finalize() const; void dump(std::ostream & os) const; - protected: - ///\name Derived class interface - ///@{ + TypeIdValue typeId() const; + factory_t factory() const; + + ///@} - /** \brief create new interpreter facade for an existing packet + protected: + explicit Packet(PacketInterpreterBase::ptr packet); - This constructor is called, when a new interpreter is to - be added to the interpreter chain. The constructor is - called indirectly from registerInterpreter() or - reinterpret() via the derived classes template - constructor. - */ - template - Packet(Operation const & arg); - virtual ~Packet(); + PacketInterpreterBase::ptr ptr() const; private: - /** \brief create next packet interpreter + Packet checkNext() const; + Packet checkLast() const; + + PacketInterpreterBase::ptr packet_; + + template + friend class ConcretePacket; + }; - 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. + /** \brief + */ + template + class ConcretePacket + : public Packet + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef PacketType type; + typedef PacketInterpreter interpreter; - 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. + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ - See also senf::PacketRegistryMixin on how to - use a Registry to find the next interpreters implementing - class. - */ - virtual void v_nextInterpreter() const = 0; + // default copy constructor + // default copy assignment + // default destructor + // no conversion constructors - /** \brief finalize packet for sending + ConcretePacket(); - This method is called by the packet framework to let the - interpreter facade do some final calculations/packet - cleanup before the packet is sent out or digested in some - other way. This is the place to calculate checksums and - such. + static factory_t factory(); - This method is automatically called for all interpreters on - the interpreter chain. - */ - virtual void v_finalize() = 0; + // Create completely new packet - virtual void v_dump(std::ostream & os) const = 0; + static ConcretePacket create(); + static ConcretePacket create(NoInit_t); + static ConcretePacket create(size_type size); + static ConcretePacket create(size_type size, NoInit_t); + template + static ConcretePacket create(ForwardReadableRange const & range); - 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() + // Create packet as new packet after a given packet - ///@} + static ConcretePacket createAfter(Packet packet); + static ConcretePacket createAfter(Packet packet, NoInit_t); + static ConcretePacket createAfter(Packet packet, size_type size); + static ConcretePacket createAfter(Packet packet, size_type size, NoInit_t); + template + static ConcretePacket createAfter(Packet packet, + ForwardReadableRange const & range); - private: + // Create packet as new packet (header) before a given packet - ///\name Implementation - ///@{ - - void add_ref() const; - bool release(); - bool unlink(); - - struct PacketOp_register; - friend class PacketOp_register; - void i_registerInterpreter(Packet * p) const; + static ConcretePacket createBefore(Packet packet); + static ConcretePacket createBefore(Packet packet, NoInit_t); - struct PacketOp_replace; - friend class PacketOp_replace; - void i_replaceInterpreter(Packet * p); + // Create a clone of the current packet - struct PacketOp_set; - friend class PacketOp_set; - void i_setInterpreter(impl::PacketImpl * i); + ConcretePacket clone() const; - private: - friend class impl::PacketImpl; - template friend class impl::PkReg_EntryImpl; + ///@} + /////////////////////////////////////////////////////////////////////////// - impl::PacketImpl* impl_; - size_type begin_; - size_type end_; - interpreter_list::iterator self_; - mutable bool parsed_; - mutable refcount_t refcount_; + // Field access - ///@} - }; + typename interpreter::parser * operator->() const; - /** \brief dump packet to stream - \related Packet */ - // std::ostream & operator<<(std::ostream & os, Packet const & packet); + protected: - /** \brief smart pointer handling - \relates Packet */ - void intrusive_ptr_add_ref(Packet const *); - /** \brief smart pointer handling - \relates Packet */ - void intrusive_ptr_release(Packet *); + private: + ConcretePacket(typename interpreter::ptr packet_); + + typename interpreter::ptr ptr() const; - struct TruncatedPacketException : public std::exception - { virtual char const * what() const throw() { return "truncated packet"; } }; + friend class Packet; + friend class PacketInterpreter; + }; } -// ////////////////////////////hh.e//////////////////////////////////////// +///////////////////////////////hh.e//////////////////////////////////////// #include "Packet.cci" #include "Packet.ct" #include "Packet.cti" - -#include "Packet.mpp" #endif @@ -626,4 +235,5 @@ namespace senf { // c-file-style: "senf" // indent-tabs-mode: nil // ispell-local-dictionary: "american" +// compile-command: "scons -u test" // End: