\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
///\name Annotations
///@{
-
+
template <class Annotation>
- Annotation & annotation();
+ 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<MyAnnotation>().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), 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
+
+ \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).
+ */
///@}
}
struct IntAnnotation {
- int value;
+ unsigned value;
+ };
+
+ struct LargeAnnotation {
+ char value[32];
};
- struct ComplexAnnotation {
+ struct ComplexAnnotation : senf::ComplexAnnotation
+ {
std::string s;
int i;
};
+ struct ComplexEmptyAnnotation : senf::ComplexAnnotation
+ {};
+
}
BOOST_AUTO_UNIT_TEST(packet)
senf::Packet packet (FooPacket::create());
BarPacket::createAfter(packet);
- SENF_CHECK_NO_THROW( packet.annotation<IntAnnotation>().value = 0xDEADBEEF );
- ComplexAnnotation & ca (packet.annotation<ComplexAnnotation>());
- ca.s = "dead beef";
- ca.i = 0x12345678;
BOOST_REQUIRE( packet );
BOOST_CHECK( packet.next() );
BOOST_CHECK( ! packet.next().next(senf::nothrow) );
BOOST_CHECK_EQUAL( BarPacket::create()->reserved(), 0xA0A0u );
}
+BOOST_AUTO_UNIT_TEST(packetAnnotation)
+{
+ senf::Packet packet (FooPacket::create());
+ BarPacket::createAfter(packet);
+
+ ComplexAnnotation & ca (packet.annotation<ComplexAnnotation>());
+ ca.s = "dead beef";
+ ca.i = 0x12345678;
+ SENF_CHECK_NO_THROW( packet.annotation<IntAnnotation>().value = 0xDEADBEEF );
+
+ senf::Packet p2 (packet.next());
+
+ BOOST_CHECK_EQUAL( p2.annotation<IntAnnotation>().value, 0xDEADBEEFu );
+ BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().s, "dead beef" );
+ BOOST_CHECK_EQUAL( p2.annotation<ComplexAnnotation>().i, 0x12345678 );
+
+ BOOST_CHECK( senf::detail::AnnotationIndexer<IntAnnotation>::Small );
+ BOOST_CHECK( ! senf::detail::AnnotationIndexer<LargeAnnotation>::Small );
+ BOOST_CHECK( ! senf::detail::AnnotationIndexer<ComplexAnnotation>::Small );
+ BOOST_CHECK( ! senf::detail::AnnotationIndexer<ComplexEmptyAnnotation>::Small );
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
Annotations::const_iterator const i_end (annotations_.end());
std::vector<bool>::iterator small (AnnotationIndexerBase::small().begin());
for (; i != i_end; ++i, ++small)
- if (! *small && *i)
- delete *i;
+ if (! *small && i->p)
+ delete i->p;
}
// This function has a problem being inlined. Somehow, often when calling this, the size of the
// senf::detail::PacketImpl
prefix_ senf::detail::PacketImpl::PacketImpl()
- : refcount_(0), annotations_(AnnotationIndexerBase::maxAnnotations, 0)
+ : refcount_(0), annotations_(AnnotationIndexerBase::maxAnnotations)
{}
prefix_ senf::detail::PacketImpl::PacketImpl(size_type size, byte initValue)
- : refcount_(0), data_(size,initValue), annotations_(AnnotationIndexerBase::maxAnnotations, 0)
+ : refcount_(0), data_(size,initValue), annotations_(AnnotationIndexerBase::maxAnnotations)
{}
// rerference/memory management
// senf::detail::GetAnnotation<Annotation,Small>
template <class Annotation, bool Small>
-prefix_ Annotation & senf::detail::GetAnnotation<Annotation,Small>::get(AnnotationP * & p)
+prefix_ Annotation & senf::detail::GetAnnotation<Annotation,Small>::get(AnnotationEntry & e)
{
- if (!p)
- p = new TAnnotationP<Annotation>();
- return static_cast< TAnnotationP<Annotation>* >(p)->annotation;
+ if (!e.p)
+ e.p = new TAnnotationP<Annotation>();
+ return static_cast< TAnnotationP<Annotation>* >(e.p)->annotation;
}
-/*
template <class Annotation>
-prefix_ Annotation & senf::detail::GetAnnotation<Annotation, true>::get(AnnotationP * & p)
+prefix_ Annotation & senf::detail::GetAnnotation<Annotation, true>::get(AnnotationEntry & e)
{
- return * reinterpret_cast<Annotation*>(p);
+ return * static_cast<Annotation*>(static_cast<void*>(& e.i));
}
-*/
///////////////////////////////////////////////////////////////////////////
// senf::detail::PacketImpl
template <class InputIterator>
prefix_ senf::detail::PacketImpl::PacketImpl(InputIterator first, InputIterator last)
- : refcount_(0), data_(first,last), annotations_(AnnotationIndexerBase::maxAnnotations, 0)
+ : refcount_(0), data_(first,last), annotations_(AnnotationIndexerBase::maxAnnotations)
{}
// Annotations
#include <memory>
#include <vector>
#include <boost/utility.hpp>
+#include <boost/type_traits/is_base_of.hpp>
#include "../Utils/pool_alloc_mixin.hh"
#include "PacketTypes.hh"
#include "../Utils/singleton.hh"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
+
+ struct ComplexAnnotation {};
+
namespace detail {
+ struct AnnotationP
+ {
+ virtual ~AnnotationP();
+ };
+
+ template <class Annotation>
+ struct TAnnotationP
+ : public AnnotationP
+ {
+ Annotation annotation;
+ };
+
+ union AnnotationEntry {
+ AnnotationP * p;
+ unsigned long long i;
+ };
+
struct AnnotationIndexerBase
{
static unsigned maxAnnotations;
AnnotationIndexer();
unsigned index_;
static unsigned index();
- static bool const Small = (sizeof(Annotation) <= sizeof(void*));
- };
-
- struct AnnotationP
- {
- virtual ~AnnotationP();
- };
-
- template <class Annotation>
- struct TAnnotationP
- : public AnnotationP
- {
- Annotation annotation;
+ static bool const Small = (sizeof(Annotation) <= sizeof(AnnotationEntry)
+ && ! boost::is_base_of<ComplexAnnotation, Annotation>::value);
};
template <class Annotation, bool Small = AnnotationIndexer<Annotation>::Small>
struct GetAnnotation
{
- static Annotation & get(AnnotationP * & p);
+ static Annotation & get(AnnotationEntry & e);
};
-/*
template <class Annotation>
struct GetAnnotation<Annotation, true>
{
- static Annotation & get(AnnotationP * & p);
+ static Annotation & get(AnnotationEntry & e);
};
-*/
/** \brief Internal: Packet data storage
raw_container data_;
interpreter_list interpreters_;
- typedef std::vector<AnnotationP*> Annotations;
+ typedef std::vector<AnnotationEntry> Annotations;
Annotations annotations_;
void eraseInterpreters(interpreter_list::iterator b, interpreter_list::iterator e);
AddressingPolicy
AddressingPolicyBase
AddressParser
+addrs
addtogroup
aListCollection
alloc
argTokens
ArgumentToken
argv
+ArrayParser
async
attr
Augustin
ConnectedUDPv
const
copyable
+cout
CPPDEFINES
CPPPATH
createAfter
DSENF
DSMCCSection
dt
+DTCP
+DTCPHelloPacket
+DVB
ElementParser
enableChecksum
endcode
eth
ethernet
EthernetPacket
+EthernetPacketParser
EthernetPacketType
EthernetParser
ethertype
EXC
ExceptionMixin
ExtendedParser
+fbipList
+FBIPList
+fbips
FFFF
FileBody
filebody
FileHandle
FileTarget
+finalizeAll
findNext
findPrev
fixedcolumn
hostnames
howto
HowTo
+HowTos
hpp
href
htm
IpV
ipv
IPv
+ipVersion
IPX
isock
iter
linux
ListB
ListN
+ListParser
ListPolicy
localAddr
localhost
memberfn
mixin
mkdir
+mld
+MLDv
+MPEG
+mpegdvb
MPEGDVBBundle
mpp
multicast
netcat
NETwork
newpacket
+NewPacket
NextPacket
nextPacketKey
nextPacketRange
noinit
noroute
nothrow
+nrOfRecords
+nrOfSources
nUsing
ob
ObjectDirectory
ptr
PUSHD
py
+QueryPacket
QueueingDiscipline
queueSize
RateFilter
registerPacketType
registerSomePacket
RegistrationProxy
+ReportPacket
repos
rerference
rfc
ScopeId
screenshot
sec
+seechapter
seekable
senf
senfscons
strerror
struct
structors
+subsubsection
svn
svnbook
svnroot
TypeA
TypeB
typeField
+UDLR
udp
UDPPacket
udpReader
unthrottles
unthrottling
Utils
+valueParser
+ValueParser
var
varadd
varattr
varchange
varChanged
VariableAttributor
+VariantParser
varro
VectorN
+VectorParser
Ver
vlanId
VLanId