\autotoc
- \section packet_intro_arch Overall Architecture
+ \section packet_intro_arch Introduction
+ \seechapter \ref packet_arch
The Packet library consists of several components:
All these components work together to provide a hopefully simple and intuitive interface to
packet parsing and creation.
- \see \ref packet_arch
-
- \section packet_intro_usage Using the packet library
+ \section packet_intro_usage Tutorial
+ \seechapter \ref packet_usage
This chapter discusses the usage of the packet library from a high level view.
- \see \ref packet_usage
-
- \section packet_intro_parser Parsing packet data
+ \section packet_intro_api The packet API
- This chapter goes into more detail discussing the usage of packet parsers.
-
- \li categorizing packet parsers
- \li reading and writing values
- \li using complex parsers
+ The packet library API is divided into three areas
- \see \ref packetparser
+ \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
\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 paceket.
+ is quite some information needed to completely specify a specific type of packet.
- \see \ref packet_new
*/
/** \page packet_arch Overall Packet library Architecture
udp.first<IPv4Packet>() // throws InvalidPacketChainException
udp.prev() == ip // true
- udp.prev<EthernetPacket>() // throws Inv
+ udp.prev<EthernetPacket>() // throws InvalidPacketChainException
\endcode
\see \ref packet_module
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 Etheret / IP / UDP
+ to easily interpret or create packets. Here an example on how to create a new Ethernet / IP / UDP
/ Payload packet interpreter chain:
\code
Each Record is a composite with the following relevant fields:
<table class="fields">
- <tr><td>nrSources</td><td>Integer</td><td>Number of sources in this record</td></tr>
+ <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>
for (MLDv2ReportPacket::Parser::records_t::container::iterator i (records.begin());
i != records.end(); ++i) {
// Allocate a collection wrapper for the multicast address record
- typedef MLDv2ReportPackte::Parser::records_t::value_type::sources_t Sources;
+ typedef MLDv2ReportPacket::Parser::records_t::value_type::sources_t Sources;
Sources::container sources (i->sources());
// Iterate over the sources in this record
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).
+
+ \see senf::Packet::annotation()
*/
/** \page packet_new Defining new Packet types