Overall Packet library Architecture

The packet library handles network packets of a large number of protocols. We work with a packet on three levels

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.

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.
Packet p = ...;
// Change first byte of packet to 1
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());
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

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:
// 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
\see \ref packet_module

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:
// EthernetPacket, IPv4Packet, UDPPacket and DataPacket are typedefs for corresponding
// ConcretePacket instantiations
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();
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