+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
/** \mainpage The SENF Packet Library
- \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
- senf::Packet. This class is the baseclass to all packet
- interpreter facades. To implement a new packet type, publically
- derive from senf::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.
-
- The parser framework contains some basic parsers to be used to
- build up more complex parsers:
-
- - ParseInt.hh: Lots of parsers for integer numbers like
- senf::Parse_UInt8, for integer bitfields like
- senf::Parse_UIntField and senf::Parse_Flag to
- parse boolean flags.
-
- - ParseArray.hh: The senf::Parse_Array parser to parse
- arbitrary fixed-size arrays of fixed-size elements (that is
- sub-parsers).
-
- - ParseVec.hh: The senf::Parse_Vector parser to parse
- dynamically sized arrays of fixed-size elements (that is
- sub-parsers).
-
- See senf::ParserBase for further information.
-
- \section stuff Other Utilities
-
- The pkf also comprises some additional utilities to support the
- development of packet classes.
-
- The senf::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
- senf::PacketRegistryMixin) this class greatly simplifies
- implementing the needed table lookups.
-
- \todo The Packet Libarary really needs a refactoring of the public
- interfaface ...
-
- \idea Add the Handle-Body idiom to the mix with a PacketRef (or
- HeaderRef or InterpreterRef or whatever class). This would
- have members for all the API defined in Packet now. \c
- operator-> would return a parser object to interpret the
- data. This would make awayy with the inheritance relationship
+ The SENF Packet library provides facilities to analyze, manipulate and create structured packet
+ oriented data (e.g. network packets).
+
+ \autotoc
+
+
+ \section packet_intro_arch Introduction
+ \seechapter \ref packet_arch
+
+ The Packet library consists of several components:
+
+ \li The \ref packet_module manages the packet data and provides the framework for handling the
+ chain of packet headers. The visible interface is provided by the Packet class.
+ \li \ref packetparser provides the framework for interpreting packet data. It handles
+ parsing the packet information into meaningful values.
+ \li The \ref protocolbundles provide concrete implementations for interpreting packets of
+ some protocol. The Protocol Bundles are built on top of the basic packet library.
+
+ All these components work together to provide a hopefully simple and intuitive interface to
+ packet parsing and creation.
+
+
+ \section packet_intro_usage Tutorial
+ \seechapter \ref packet_usage
+
+ This chapter discusses the usage of the packet library from a high level view.
+
+
+ \section packet_intro_api The packet API
+
+ The packet library API is divided into three areas
+
+ \li the \ref senf::PacketData API for accessing the raw data container
+ \li the packet interpreter chain providing \ref packet_module
+ \li and \ref packetparser which provides access to protocol specific packet fields.
+
+
+ \section protocolbundles Supported packet types (protocols)
+
+ Each protocol bundle provides a collection of related concrete packet classes for a group of
+ related protocols:
+
+ \li \ref protocolbundle_default : Some basic default protocols: Ethernet, Ip, TCP, UDP
+ \li \ref protocolbundle_mpegdvb : MPEG and DVB protocols
+ \li \ref protocolbundle_80211 : 802.11 protocols
+
+ There are two ways to link with a bundle
+
+ \li If you only work with known packets which you explicitly reference you may just link with
+ the corresponding library.
+ \li If you need to parse unknown packets and want those to be parsed as complete as possible
+ without explicitly referencing the packet type, you will need to link against the combined
+ object file built for every bundle. This way, all packets defined in the bundle will be
+ included whether they are explicitly referenced or not (and they will all automatically be
+ registered).
+
+
+ \section packet_intro_new Defining new packet types
+ \seechapter \ref packet_new
+
+ The packet library provides the framework which allows to define arbitrary packet types. There
+ is quite some information needed to completely specify a specific type of packet.
+
+ */
+
+/** \page packet_arch Overall Packet library Architecture
+
+ The packet library handles network packets of a large number of protocols. We work with a packet
+ on three levels
+
+ \autotoc
+
+
+ \section packet_arch_handle The Packet handle
+
+ Whenever we are using a Packet, we are talking about a senf::Packet (or a
+ senf::ConcretePacket). This class is a \e handle referencing an internally managed packet data
+ structure. So even though we pass senf::Packet instances around by value, they work like
+ references. The packet library automatically manages all required memory resources using
+ reference counting.
+
+ Different Packet handles may really internally share one Packet data structure if they both
+ point to the same packet.
+
+
+ \section packet_arch_data The Packet as a 'bunch of bytes'
+
+ From the outside, a packet is just a bunch of bytes just as it is read from (or will be
+ written to) the wire. At this low-level view, we can access the data in it's raw form but
+ have no further information about what kind of packet we have.
+
+ The packet library provides a consistent container interface for this representation.
+
+ \code
+ Packet p = ...;
+
+ // Change first byte of packet to 0
+ p.data()[0] = 1u;
+
+ // Copy packet data into a vector
+ std::vector<char> data (p.data().size());
+ std::copy(p.data().begin(), p.data().end(), data.begin());
+ \endcode
+
+ This type of access is primarily needed when reading or writing packets (e.g. to/from the
+ network).
+
+ \see senf::Packet::data() \n
+ senf::PacketData
+
+
+ \section packet_arch_chain The Interpreter Chain
+
+ On the next level, the packet is divided into a nested list of sub-packets (or headers) called
+ interpreters. Each senf::Packet handle internally points to an interpreter or header. This
+ allows us to access one and the same packet in different ways.
+
+ Consider an Ethernet Packet with an IP payload holding a UDP packet. We may reference either the
+ Ethernet packet as a whole or we may reference the IP or UDP interpreters (sub-packets or
+ headers). All handles really refer to the \e same data structure but provide access to a
+ different (sub-)range of the data in the packet.
+
+ We can navigate around this chained structure using appropriate members:
+
+ \code
+ // eth, ip and udp all reference the same internal packet data albeit at different data ranges
+ Packet eth = ...;
+ Packet ip = eth.next();
+ Packet udp = ip.next();
+
+ eth.next() == ip // true
+ eth.next().is<IPv4Packet>() // true
+ eth.next().next() == udp // true
+ eth.next().is<UDPPacket>() // false
+ eth.find<UDPPacket>() == udp // true
+
+ udp.find<EthernetPacket>() // throws InvalidPacketChainException
+ udp.find<EthernetPacket>(senf::nothrow) // An in-valid() senf::Packet which tests as 'false'
+ udp.find<UDPPacket> == udp // true
+ udp.first<IPv4Packet>() // throws InvalidPacketChainException
+
+ udp.prev() == ip // true
+ udp.prev<EthernetPacket>() // throws InvalidPacketChainException
+ \endcode
+
+ \see \ref packet_module
+
+
+ \section packet_arch_parser Parsing specific Protocols
+
+ On the next level, the packet library allows us to parse the individual protocols. This gives us
+ access to the protocol specific data members of a packet and allows us to access or manipulate a
+ packet in a protocol specific way.
+
+ To access this information, we need to use a protocol specific handle, the senf::ConcretePacket
+ which takes as a template argument the specific type of packet to be interpreted. This allows us
+ to easily interpret or create packets. Here an example on how to create a new Ethernet / IP / UDP
+ / Payload packet interpreter chain:
+
+ \code
+ // EthernetPacket, IPv4Packet, UDPPacket and DataPacket are typedefs for corresponding
+ // ConcretePacket instantiations
+ senf::EthernetPacket eth (senf::EthernetPacket::create());
+ senf::IPv4Packet ip (senf::IPv4Packet ::createAfter(eth));
+ senf::UDPPacket udp (senf::UDPPacket ::createAfter(ip));
+ senf::DataPacket payload (senf::DataPacket ::createAfter(udp,
+ std::string("Hello, world!")));
+
+ udp->source() = 2000u;
+ udp->destination() = 2001u;
+ ip->ttl() = 255u;
+ ip->source() = senf::INet4Address::from_string("192.168.0.1");
+ ip->destination() = senf::INet4Address::from_string("192.168.0.2");
+ eth->source() = senf::MACAddress::from_string("00:11:22:33:44:55");
+ eth->destination() = senf::MACAddress::from_string("00:11:22:33:44:66");
+
+ eth.finalizeAll();
+ \endcode
+
+ Again, realize, that \a eth, \a ip, \a udp and \a payload share the same internal packet
+ data structure (the respective \c data() members all provide access to the same underlying
+ container however at different byte ranges): The complete packet can be accessed at
+ <tt>eth.data()</tt> whereas <tt>payload.data()</tt> only holds UDP payload (in this case the
+ string "Hello, world!").
+
+ \see \ref packetparser \n
+ \ref protocolbundles
+ */
+
+/** \page packet_usage Using the packet library
+
+ \autotoc
+
+ \section packet_usage_intro Includes
+
+ To use the library, you need to include the appropriate header files. This will probably happen
+ automatically when including the specific protocol headers. If needed, you may explicitly use
+
+ \code
+ #include "Packets.hh"
+ \endcode
+
+ explicitly.
+
+ \warning Never include any other Packets library header directly, only include \c
+ Packets.hh or one (or several) protocol headers from the protocol bundles.
+
+ Most every use of the packet library starts with some concrete packet typedef. Some fundamental
+ packet types are provided by \ref protocolbundle_default.
+
+
+ \section packet_usage_create Creating a new packet
+
+ Building on those packet types, this example will build a complex packet: This will be an
+ Ethernet packet containing an IPv4 UDP packet. We begin by building the raw packet skeleton:
+
+ \code
+ #include "Packets/DefaultBundle/EthernetPacket.hh"
+ #include "Packets/DefaultBundle/IPv4Packet.hh"
+ #include "Packets/DefaultBundle/UDPPacket.hh"
+
+ senf::EthernetPacket eth (senf::EthernetPacket::create());
+ senf::IPv4Packet ip (senf::IPv4Packet ::createAfter(eth));
+ senf::UDPPacket udp (senf::UDPPacket ::createAfter(ip));
+ senf::DataPacket payload (senf::DataPacket ::createAfter(udp,
+ std::string("Hello, world!")));
+ \endcode
+
+ These commands create what is called an interpreter chain. This chain consists of four
+ interpreters. All interpreters reference the same data storage. This data storage is a random
+ access sequence which contains the data bytes of the packet.
+
+ \note The data structures allocated are automatically managed using reference counting. In this
+ example we have four packet references each referencing the same underlying data
+ structure. This data structure will be freed when the last reference to it goes out of
+ scope.
+
+ The packet created above already has the correct UDP payload (The string "Hello, world!")
+ however all protocol fields are empty. We need to set those protocol fields:
+
+ \code
+ udp->source() = 2000u;
+ udp->destination() = 2001u;
+ ip->ttl() = 255u;
+ ip->source() = senf::INet4Address::from_string("192.168.0.1");
+ ip->destination() = senf::INet4Address::from_string("192.168.0.2");
+ eth->source() = senf::MACAddress::from_string("00:11:22:33:44:55");
+ eth->destination() = senf::MACAddress::from_string("00:11:22:33:44:66");
+
+ eth.finalizeAll();
+ \endcode
+
+ As seen above, packet fields are accessed using the <tt>-></tt> operator whereas other packet
+ facilities (like \c finalizeAll()) are directly accessed using the member operator. The field
+ values are simply set using appropriately named accessors. As a last step, the \c finalizeAll()
+ call will update all calculated fields (fields like next-protocol, header or payload length,
+ checksums etc). Now the packet is ready. We may now send it out using a packet socket
+
+ \code
+ senf::PacketSocketHandle sock ("eth0");
+ sock.write(eth.data());
+ \endcode
+
+
+ \section packet_usage_read Reading and parsing packets
+
+ The chain navigation functions are also used to parse a packet. Let's read an Ethernet packet
+ from a packet socket handle:
+
+ \code
+ senf::PacketSocketHandle sock ("eth0");
+ senf::EthernetPacket packet (senf::EthernetPacket::create(senf::noinit));
+ sock.read(packet.data(),0u);
+ \endcode
+
+ This first creates an uninitialized Ethernet packet and then reads into this packet. We can now
+ parse this packet. Let's find out, whether this is a UDP packet destined to port 2001:
+
+ \code
+ try {
+ senf::UDPPacket udp (packet.find<UDPPacket>());
+ if (udp->destination() == 2001u) {
+ // Voila ...
+ }
+ } catch (senf::TruncatedPacketException &) {
+ std::cerr << "Ooops !! Broken packet received\n";
+ } catch (senf::InvalidPacketChainException &) {
+ std::cerr << "Not a udp packet\n";
+ }
+ \endcode
+
+ TruncatedPacketException is thrown by <tt>udp->destination()</tt> if that field cannot be
+ accessed (that is it would be beyond the data read which means we have read a truncated
+ packet). More generally, whenever a field cannot be accessed because it would be out of bounds
+ of the data read, this exception is generated.
+
+
+ \section packet_usage_container The raw data container
+
+ Every packet is based internally on a raw data container holding the packet data. This container
+ is accessed via senf::Packet::data() member.
+
+ This container is a random access container. It can be used like an ordinary STL container and
+ supports all the standard container members.
+
+ \code
+ Packet p = ...;
+
+ // Insert 5 0x01 bytes
+ p.data().insert(p.data().begin()+5, 5, 0x01);
+
+ // Insert data from another container
+ p.data().insert(p.data().end(), other.begin(), other.end());
+
+ // Erase a single byte
+ p.data().erase(p.data().begin()+5);
+
+ // XOR byte 5 with 0xAA
+ p.data()[5] ^= 0xAA;
+ \endcode
+
+ A packet consists of a list of interpreters (packet headers or protocols) which all reference
+ the same data container at different byte ranges. Each packet consists of the protocol header \e
+ plus the packets payload. This means, that the data container ranges of successive packets from
+ a single interpreter chain are nested.
+
+ Example: The packet created above (the Ethernet-IP-UDP packet with payload "Hello, world!") has
+ 4 Interpreters: Ethernet, IPv4, UDP and the UDP payload data. The nested data containers lead to
+ the following structure
+
+ \code
+ // The ethernet header has a size of 14 bytes
+ eth.data().begin() + 14 == ip.data().begin()
+ eth.data().end() == ip.data().end()
+
+ // The IP header has a size of 20 bytes and therefore
+ ip.data().begin() + 20 == udp.data().begin()
+ ip.data().end() == udp.data().end()
+
+ // The UDP header has a size of 8 bytes and thus
+ udp.data().begin() + 8 == payload.data().begin()
+ udp.data().end() == payload.data().end()
+ \endcode
+
+ This nesting will (and must) always hold: The data range of a subsequent packet will always be
+ within the range of it's preceding packet.
+
+ \warning It is forbidden to change the data of a subsequent packet interpreter from the
+ preceding packet even if the data container includes this data. If you do so, you may
+ corrupt the data structure (especially when changing it's size).
+
+ Every operation on a packet is considered to be \e within this packet and \e without and
+ following packet. When inserting or erasing data, the data ranges are all adjusted
+ accordingly. So the following are \e not the same even though \c eth.end(), \c ip.end() and \c
+ udp.end() are identical.
+
+ \code
+ eth.data().insert(eth.data().end(), 5, 0x01);
+ assert( eth.data().end() == ip.data().end() + 5
+ && ip.data().end() == udp.data().end() );
+
+ // Or alternatively: (You could even use eth.data().end() here ... it's the same)
+ ip.data().insert(ip.data().end(), 5, 0x01);
+ assert( eth.data().end() == ip.data().end()
+ && ip.data().end() == udp.data().end() + 5 );
+ \endcode
+
+ \warning When accessing the packet data via the container interface, you may easily build
+ invalid packets since the packet will not be validated against it's protocol.
+
+
+ \section packet_usage_fields Field access
+
+ When working with concrete protocols, the packet library provides direct access to all the
+ protocol information.
+
+ \code
+ udp->source() = 2000u;
+ udp->destination() = 2001u;
+ ip->ttl() = 255u;
+ ip->source() = senf::INet4Address::from_string("192.168.0.1");
+ ip->destination() = senf::INet4Address::from_string("192.168.0.2");
+ eth->source() = senf::MACAddress::from_string("00:11:22:33:44:55");
+ eth->destination() = senf::MACAddress::from_string("00:11:22:33:44:66");
+ \endcode
+
+ The protocol field members above do \e not return references, they return parser instances.
+ Protocol fields are accessed via parsers. A parser is a very lightweight class which points into
+ the raw packet data and converts between raw data bytes and it's interpreted value: For example
+ a senf::UInt16Parser accesses 2 bytes (in network byte order) and converts them to or from a 16
+ bit integer. There are a few properties about parsers which need to be understood:
+
+ \li Parsers are created only temporarily when needed. They are created when accessing a protocol
+ field and are returned by value.
+
+ \li A parser never contains a value itself, it just references a packets data container.
+
+ \li Parsers can be built using other parsers and may have members which return further parsers.
+
+ The top-level interface to a packets protocol fields is provided by a protocol parser. This
+ protocol parser is a composite parser which has members to access the protocol fields (compare
+ with the example code above). Some protocol fields may be more complex than a simple value. In
+ this case, those accessors may return other composite parsers or collection parsers. Ultimately,
+ a value parser will be returned.
+
+ The simple value parsers which return plain values (integer numbers, network addresses etc) can
+ be used like those values and can also be assigned corresponding values. More complex parsers
+ don't allow simple assignment. However, they can always be copied from another parser <em>of the
+ same type</em> using the generalized parser assignment. This type of assignment also works for
+ simple parsers and is then identical to a normal assignment.
+
+ \code
+ // Copy the complete udp parser from udp packet 2 to packet 1
+ udp1.parser() << udp2.parser();
+ \endcode
+
+ Additionally, the parsers have a parser specific API which allows to manipulate or query the
+ value.
+
+ This is a very abstract description of the parser structure. For a more concrete description, we
+ need to differentiate between the different parser types
+
+ \subsection packet_usage_fields_value Simple fields (Value parsers)
+
+ We have already seen value parsers: These are the lowest level building blocks witch parse
+ numbers, addresses etc. They return some type of value and can be assigned such a value. More
+ formally, they have a \c value_type typedef member which gives the type of value they accept and
+ they have an overloaded \c value() member which is used to read or set the value. Some parsers
+ have additional functionality: The numeric parser for Example provide conversion and arithmetic
+ operators so they can be used like a numeric value.
+
+ If you have a value parser \c valueParser with type \c ValueParser, the following will always be
+ valid:
+ \code
+ // You can read the value and assign it to a variable of the corresponding value_type
+ ValueParser::value_type v (valueParser.value());
+
+ // You can assign that value to the parser
+ valueParser.value(v);
+
+ // The assignment can also be done using the generic parser assignment
+ valueParser << v;
+ \endcode
+
+
+ \subsection packet_usage_fields_composite Composite and protocol parsers
+
+ A composite parser is a parser which just combines several other parsers into a structure: For
+ example, the senf::EthernetPacketParser has members \c destination(), \c source() and \c
+ type_length(). Those members return parsers again (in this case value parsers) to access the
+ protocol fields.
+
+ Composite parsers can be nested; A composite parser may be returned by another composite
+ parser. The protocol parser is a composite parser which defines the field for a specific
+ protocol header like Ethernet.
+
+ \subsection packet_usage_fields_collection Collection parsers
+
+ Besides simple composites, the packet library has support for more complex collections.
+
+ \li The senf::ArrayParser allows to repeat an arbitrary parser a fixed number of times.
+ \li senf::VectorParser and senf::ListParser are two different types of lists with variable
+ number of elements
+ \li The senf::VariantParser is a discriminated union: It will select one of several parsers
+ depending on the value of a discriminant.
+
+
+ \subsubsection packet_usage_collection_vector Vector and List Parsers
+
+ Remember, that a parser does \e not contain any data: It only points into the raw data
+ container. This is also true for the collection parsers. VectorParser and ListParser provide an
+ interface which looks like an STL container to access a sequence of elements.
+
+ We will use an \c MLDv2QueryPacket as an example (see <a
+ href="http://tools.ietf.org/html/rfc3810#section-5">RFC 3810</a>). Here an excerpt of the
+ relevant fields:
+
+ <table class="fields">
+ <tr><td>nrOfSources</td><td>Integer</td><td>Number of multicast sources in this packet</td></tr>
+ <tr><td>sources</td><td>Vector of IPv6 Addresses</td><td>Multicast sources</td></tr>
+ </table>
+
+ To demonstrate nested collections, we use the \c MLDv2ReportPacket as an example. The relevant
+ fields of this packet are;
+
+ <table class="fields">
+ <tr><td>nrOfRecords</td><td>Integer</td><td>Number of multicast address records</td></tr>
+ <tr><td>records</td><td>List of Records</td><td>List of multicast groups and sources</td></tr>
+ </table>
+
+ Each Record is a composite with the following relevant fields:
+
+ <table class="fields">
+ <tr><td>nrOfSources</td><td>Integer</td><td>Number of sources in this record</td></tr>
+ <tr><td>sources</td><td>Vector of IPv6 Addresses</td><td>Multicast sources</td></tr>
+ </table>
+
+ The first example will iterate over the sources in a \c MLDv2QueryPacket:
+
+ \code
+ MLDv2QueryPacket mld = ...;
+
+ // Instantiate a collection wrapper for the source list
+ MLDv2QueryPacket::Parser::sources_t::container sources (mld->sources());
+
+ // Iterate over all the addresses in that list
+ for (MLDv2QueryPacket::Parser::sources_t::container::iterator i (sources.begin());
+ i != sources.end(); ++i)
+ std::cout << *i << std::endl;
+ \endcode
+
+ Beside other fields, the MLDv2Query consists of a list of source addresses. The \c sources()
+ member returns a VectorParser for these addresses. The collection parsers can only be accessed
+ completely using a container wrapper. The container wrapper type is available as the \c
+ container member of the collection parser, here it is \c
+ MLDv2QueryPacket::Parser::sources_t::container.
+
+ Using this wrapper, we can not only read the data, we can also manipulate the source list. Here
+ we copy a list of addresses from an \c std::vector into the packet:
+
+ \code
+ std::vector<senf::INet6Address> addrs (...);
+
+ sources.resize(addrs.size());
+ std::copy(addrs.begin(), addrs.end(), sources.begin())
+ \endcode
+
+ Collection parsers may be nested. To access a nested collection parser, a container wrapper must
+ be allocated for each level. An MLD Report (which is a composite parser) includes a list of
+ multicast address records called \c records(). Each record is again a composite which contains a
+ list of sources called \c sources():
+
+ \code
+ MLDv2ReportPacket report = ...;
+
+ // Instantiate a collection wrapper for the list of records:
+ MLDv2ReportPacket::Parser::records_t::container records (report->records());
+
+ // Iterate over the multicast address records
+ for (MLDv2ReportPacket::Parser::records_t::container::iterator i (records.begin());
+ i != records.end(); ++i) {
+ // Allocate a collection wrapper for the multicast address record
+ typedef MLDv2ReportPacket::Parser::records_t::value_type::sources_t Sources;
+ Sources::container sources (i->sources());
+
+ // Iterate over the sources in this record
+ for (Sources::container::iterator i (sources.begin());
+ i != sources.end(); ++i)
+ std::cout << *i << std::endl;
+ }
+ \endcode
+
+ In this example we also see how to find the type of a parser or container wrapper.
+ \li Composite parsers have typedefs for each their fields with a \c _t postfix
+ \li The vector or list parsers have a \c value_type typedef which gives the type of the
+ element.
+
+ By traversing this hierarchical structure, the types of all the fields can be found.
+
+ The container wrapper is only temporary (even though it has a longer lifetime than a
+ parser). Any change made to the packet not via the collection wrapper has the potential to
+ invalidate the wrapper if it changes the packets size.
+
+ \see
+ senf::VectorParser_Container Interface of the vector parser container wrapper \n
+ senf::ListParser_Container Interface of the list parser container wrapper
+
+
+ \subsubsection packet_usage_collection_variant The Variant Parser
+
+ The senf::VariantParser is a discriminated union of parsers. It is also used for optional fields
+ (using senf::VoidPacketParser as one possible variant which is a parser parsing nothing). A
+ senf::VariantParser is not really a collection in the strict sense: It only ever contains one
+ element, the \e type of which is determined by the discriminant.
+
+ For Example, we look at the DTCP HELLO Packet as defined in the UDLR Protocol (see <a
+ href="http://tools.ietf.org/html/rfc3077">RFC 3077</a>)
+
+ \code
+ DTCPHelloPacket hello (...);
+
+ if (hello->ipVersion() == 4) {
+ typedef DTCPHelloPacket::Parser::v4fbipList_t FBIPList;
+ FBIPList::container fbips (hello->v4fbipList());
+ for (FBIPList::container::iterator i (fbips.begin()); i != fbips.end(); ++i)
+ std::cout << *i << std::endl;
+ }
+ else { // if (hello->ipVersion() == 6)
+ typedef DTCPHelloPacket::Parser::v6fbipList_t FBIPList;
+ FBIPList::container fbips (hello->v6fbipList());
+ for (FBIPList::container::iterator i (fbips.begin()); i != fbips.end(); ++i)
+ std::cout << *i << std::endl;
+ }
+ \endcode
+
+ This packet has a field \c ipVersion() which has a value of 4 or 6. Depending on the version,
+ the packet contains a list of IPv4 or IPv6 addresses. Only one of the fields \c v4fbipList() and
+ \c v6fbipList() is available at a time. Which one is decided by the value of \c
+ ipVersion(). Trying to access the wrong one will provoke undefined behavior.
+
+ Here we have used the variants discriminant (the \c ipVersion() field) to select, which field to
+ parse. More generically, every variant field should have a corresponding member to test for it's
+ existence:
+ \code
+ if (hello->has_v4fbipList()) {
...
+ }
+ else { // if (hello->has_v6fbipList())
+ ...
+ }
+ \endcode
+
+ A variant can have more than 2 possible types and you can be sure, that exactly one type will be
+ accessible at any time.
+
+ It is not possible to change a variant by simply changing the discriminant:
+ \code
+ // INVALID CODE:
+ hello->ipVersion() = 6;
+ \endcode
+ Instead, for each variant field there is a special member which switches the variant to that
+ type. After switching the type, the field will be in it's initialized (that is mostly zero)
+ state.
+ \code
+ std::vector<senf::INet6Address> addrs (...);
+
+ // Initialize the IPv6 list
+ hello->init_v6fbipList();
+
+ // Copy values into that list
+ DTCPHelloPacket::Parser::v6fbipList_t::container fbips (hello->v6fbipList());
+ fbips.resize(addrs.size());
+ std::copy(addrs.begin(), addrs.end(), fbips.begin());
+ \endcode
+
+ \note Here we have documented the default variant interface as it is preferred. It is possible
+ to define variants in a different way giving other names to the special members (\c has_\e
+ name or \c init_\e name etc.). This must be documented with the composite or protocol parser
+ which defines the variant.
+
+ \section packet_usage_annotation Annotations
+
+ Sometimes we need to store additional data with a packet. Data, which is not part of the packet
+ itself but gives us some information about the packet: A timestamp, the interface the packet was
+ received on or other processing related information.
+
+ This type of information can be stored using the annotation interface. The following example
+ will read packet data and will store the read timestamp as a packet annotation.
+
+ \code
+ struct Timestamp {
+ senf::ClockService::clock_t value;
+ };
+
+ senf::EthernetPacket packet (senf::EthernetPacket::create(senf::noinit));
+ sock.read(packet.data(), 0u);
+ packet.annotation<Timestamp>().value = senf::ClockService::now();
+ \endcode
+
+ In the same way, the annotation can be used later
+
+ \code
+ if (senf::ClockService::now() - packet.annotation<Timestamp>().value
+ > senf::ClockService::seconds(1)) {
+ // Ouch ... this packet is to old
+ // ...
+ }
+ \endcode
+
+ It is very important to define a specific structure (or class or enum) type for each type of
+ annotation. \e Never directly store a fundamental type as an annotation: The name of the type is
+ used to look up the annotation, so you can store only one annotation for each built-in type. \c
+ typedef does not help since \c typedef does not introduce new type names, it only defines an
+ alias.
+
+ Of course, the annotation structure can be arbitrary. However, one very important caveat: If the
+ annotation is not a POD type, it needs to inherit from senf::ComplexAnnotation. A type is POD,
+ if it is really just a bunch of bytes: No (non-static) members, no constructor or destructor and
+ no base classes and all it's members must be POD too. So the following annotation is complex
+ since \c std::string is not POD
+
+ \code
+ struct ReadInfo : senf::ComplexAnnotation
+ {
+ std::string interface;
+ senf::ClockService::clock_t timestamp;
+ };
+
+ // ...
+
+ packet.annotation<ReadInfo>().interface = "eth0";
+ packet.annotation<ReadInfo>().timestamp = senf::ClockService::now();
+
+ // Or store a reference to the annotation for easier access
+
+ ReadInfo & info (packet.annotation<ReadInfo>());
+
+ if (info.interface == "eth0") {
+ // ...
+ }
+ \endcode
+
+ Every annotation is automatically default-initialized, there is no way to query, whether a
+ packet holds a specific annotation -- every packet conceptually always holds all annotations.
+
+ You should use annotations economically: Every annotation type used in your program will
+ allocate an annotation slot in \e all packet data structures. So don't use hundreds of different
+ annotation types if this is not really necessary: Reuse annotation types where possible or
+ aggregate data into larger annotation structures. The best solution is to use annotations only
+ for a small number of packet specific informations. If you really need to manage a train-load of
+ data together with the packet consider some other way (e.g. place the packet into another class
+ which holds that data).
- \idea Templating the parsers on the iterator type does not
- introduce additional coupling (because of the inlining) but
- looking at it after the fact it looks like severe overdesign
- and it does introduce some problems (e.g. rebind and all this
- entails). If we just implement all parsers for
- Packet::byte_iterator they are no tmplates any more which
- should simplify things a log.
-
- \idea we need some better and automatic checking on data access
- especially after data has changed. Idea 1: give the parser the
- end iterator as additional member. Enforce, that all parsers
- must ultimately be based on ParseInt and have ParseInt check
- against end() at construction time. Idea 2: add a dirty flag
- to the interpreters. Set this flag whenever the packet is
- changed and recall check() in operator-> of the PacketRef
- object if the packet is dirty. Maybe we need both and make
- them tunable.
+ \see senf::Packet::annotation()
+ */
+
+/** \page packet_new Defining new Packet types
+
+ Each packet is specified by the following two components:
+
+ \li A protocol parser which defines the protocol specific fields
+ \li A packet type class which is a policy class defining the packet
+
+ \autotoc
+
+ \see <a href="../../../HowTos/NewPacket/doc/html/index.html">NewPacket HowTo</a>
+
+ \section packet_new_parser The protocol parser
+
+ The protocol parser is simply a composite parser. It defines all the protocol
+ fields. Additionally, the protocol parser may have additional members which will then be
+ accessible via the \c -> operator of the packet. Possibilities here are e.g. checksum
+ calculation and validation, packet validation as a whole and so on.
+
+ Defining a protocol parser is quite simple:
+ \code
+ struct EthernetPacketParser : public PacketParserBase
+ {
+ # include SENF_FIXED_PARSER()
+
+ SENF_PARSER_FIELD( destination, MACAddressParser );
+ SENF_PARSER_FIELD( source, MACAddressParser );
+ SENF_PARSER_FIELD( type_length, UInt16Parser );
+
+ SENF_PARSER_FINALIZE(EthernetPacketParser);
+ };
+ \endcode
+
+ There are a lot of other possibilities to define fields. See \ref packetparsermacros for a
+ detailed description of the macro language which is used to define composite parsers.
+
+ \see
+ \ref packetparsermacros
+
+ \section packet_new_type The packet type policy class
+
+ This is a class which provides all the information needed to integrate the new packet type into
+ the packet library:
+
+ \li It provides the type of the protocol parser to use
+ \li It provides information on how the next protocol can be found and where the payload resides
+ in this packet
+ \li It provides methods to initialize a new packet and get information about the packet size
+
+ All this information is provided via static or typedef members.
+
+ \code
+ struct EthernetPacketType
+ : public PacketTypeBase,
+ public PacketTypeMixin<EthernetPacketType, EtherTypes>
+ {
+ typedef PacketTypeMixin<EthernetPacketType, EtherTypes> mixin;
+ typedef ConcretePacket<EthernetPacketType> packet;
+ typedef EthernetPacketParser parser;
+
+ using mixin::nextPacketRange;
+ using mixin::initSize;
+ using mixin::init;
+
+ static factory_t nextPacketType(packet p);
+ static void dump(packet p, std::ostream & os);
+ static void finalize(packet p);
+ };
+
+ typedef EthernetPacketType::packet EthernetPacket;
+ \endcode
+
+ The definition of senf::EthernetPacket is quite straight forward. This template works for most
+ simple packet types.
+
+ \see \ref senf::PacketTypeMixin \n
+ \ref senf::PacketTypeBase \n
+ \ref senf::PacketRegistry
*/
\f
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
-// mode: flyspell
// mode: auto-fill
+// compile-command: "scons -u doc"
// End:
+