senf::RawV6ClientSocketHandle isock (47u); // 47 = Read GRE packets
senf::PacketSocketHandle osock;
- while (1) {
+ while (true) {
try {
GREPacket gre (GREPacket::create(senf::noinit));
isock.read(gre.data(),0u);
senf::TapSocketHandle tap ("tap0");
senf::ConnectedRawV6ClientSocketHandle osock (47u, senf::INet6SocketAddress(argv[1]));
- while (1) {
+ while (true) {
senf::EthernetPacket eth (senf::EthernetPacket::create(senf::noinit));
isock.read(eth.data(),0u);
GREPacket gre (senf::GREPacket::createBefore(eth));
\section howto_newpacket_further Further reading
- Lets start with references to the important API's (Use the 'Show all members' link to get the
- complete API of one of the classes and templates):
+ Lets start with references to the important API's (Use the <i>List of all members</i> link to
+ get the complete API of one of the classes and templates):
- \li senf::ConcretePacket : this is the API provided by the packet handles.
- \li senf::PacketData : this API provides raw data access accessible via the handles 'data'
- member.
- \li senf::PacketParserBase : this is the generic parser API. This API is accessible via the
- packets \c -> operator or via the sub-parsers returned by the field accessors.
+ <table class="senf fixedcolumn">
+
+ <tr><td>senf::ConcretePacket</td> <td>this is the API provided by the packet handles.</td></tr>
+
+ <tr><td>senf::PacketData</td> <td>this API provides raw data access accessible via the handles
+ 'data' member.</td></tr>
+
+ <tr><td>senf::PacketParserBase</td> <td>this is the generic parser API. This API is accessible
+ via the packets \c -> operator or via the sub-parsers returned by the field accessors.</td></tr>
+
+ </table>
When implementing new packet's, the following information will be helpful:
- \li senf::PacketTypeBase : here you find a description of the members which need to be
- implemented to provide a 'packet type'. Most of these members will normally be provided by
- the mixin helper.
- \li senf::PacketTypeMixin : here you find all about the packet type mixin and how to use it.
- \li \ref packetparser : This section describes the packet parser facility.
- \li \ref packetparsermacros : A complete list and documentation of all the packet parser macros.
- \li There are several lists of available reusable packet parsers: \ref parseint, \ref
- parsecollection. However, this list is not complete as there are other protocol specific
- reusable parsers (without claiming to be exhaustive: senf::INet4AddressParser,
- senf::INet6AddressParser, senf::MACAddressParser)
+ <table class="senf fixedcolumn">
+
+ <tr><td>senf::PacketTypeBase</td> <td>here you find a description of the members which need to
+ be implemented to provide a 'packet type'. Most of these members will normally be provided by
+ the mixin helper.</td></tr>
+
+ <tr><td>senf::PacketTypeMixin</td> <td>here you find all about the packet type mixin and how to
+ use it.</td></tr>
+
+ <tr><td>\ref packetparser</td> <td>This section describes the packet parser facility.</td></tr>
+
+ <tr><td>\link packetparsermacros Packet parser macros\endlink</td> <td>A complete list and
+ documentation of all the packet parser macros.</td></tr>
+
+ <tr><td>\ref parseint, \n \ref parsecollection</td> <td>There are several lists of available
+ reusable packet parsers: . However, this list is not complete as there are other protocol
+ specific reusable parsers (without claiming to be exhaustive: senf::INet4AddressParser,
+ senf::INet6AddressParser, senf::MACAddressParser)</td></tr>
+
+ </table>
*/
// Field access
template <class PacketType>
-prefix_ typename senf::ConcretePacket<PacketType>::type::parser *
+prefix_ typename senf::ConcretePacket<PacketType>::Parser *
senf::ConcretePacket<PacketType>::operator->()
const
{
return ptr()->fields_p();
}
+template <class PacketType>
+prefix_ typename senf::ConcretePacket<PacketType>::Parser
+senf::ConcretePacket<PacketType>::parser()
+ const
+{
+ return ptr()->fields();
+}
+
// private members
template <class PacketType>
/ recreation ...)
\see \ref packetparser for the parser interface. */
+ Parser parser() const; ///< Access packet field parser directly
+ /**< Access the parser of the packet. This is the same
+ object returned by the operator->() operator. The
+ operator however does not allow to access this object
+ itself, only it's members.
+ \see \ref packetparser for the parser interface */
+
protected:
private:
using senf::PacketTypeMixin<FooPacketType>::nextPacketRange;
using senf::PacketTypeMixin<FooPacketType>::initSize;
using senf::PacketTypeMixin<FooPacketType>::init;
- typedef senf::PacketInterpreter<FooPacketType> interpreter;
- static interpreter::size_type initSize()
+ static size_type initSize()
{ return 4u; }
+
+ // We need to implement initHeadSize() to force the mixin to switch into 'fixed-size'
+ // mode. Otherwise, mixin::nextPacketRange() would query the parser for it's size to find
+ // the header size. Since the parser is VoidPacketParser, the header size would therefore be
+ // 0
+ static size_type initHeadSize()
+ { return initSize(); }
};
typedef senf::ConcretePacket<FooPacketType> FooPacket;
SENF_PARSER_FIELD( length, senf::Int32Parser );
SENF_PARSER_FIELD( reserved, senf::UInt16Parser );
+ SENF_PARSER_INIT() {
+ reserved() << 0xA0A0u;
+ }
+
SENF_PARSER_FINALIZE(BarPacketParser);
};
using mixin::nextPacketType;
using mixin::initSize;
using mixin::init;
- static size_type initSize()
- { return 8u; }
- static void init(packet p) {
- p->reserved() = 0xA0A0u;
- }
static void dump(packet p, std::ostream & os) {
os << "BarPacket:\n"
<< "type: " << p->type() << "\n"
BOOST_CHECK( ! packet.prev(senf::nothrow) );
BOOST_CHECK( packet.next().prev() == packet );
BOOST_CHECK( packet.next() != packet );
+ BOOST_CHECK_EQUAL( std::distance(packet.data().begin(), packet.next().data().begin()), 4 );
+ BOOST_CHECK_EQUAL( std::distance(packet.data().begin(), packet.data().end()), 12 );
+ BOOST_CHECK_EQUAL( std::distance(packet.next().data().begin(), packet.next().data().end()), 8 );
+ BOOST_CHECK( packet.data().end() == packet.next().data().end() );
BOOST_CHECK_EQUAL( packet.size(), 12u );
BOOST_CHECK_EQUAL( packet.next().size(), 8u );
BOOST_CHECK( packet.is<FooPacket>() );
///\idea This if condition could be replaced with a compile time switch by checking, wether
/// (the function address) Self::initHeadSize is different from PacketTypeBase::initHeadSize
if (sz == PacketTypeBase::size_type(-1))
- return PacketTypeBase::range(boost::next(p.data().begin(),Self::initSize()),
+ return PacketTypeBase::range(boost::next(p.data().begin(),
+ bytes(p.as< ConcretePacket<Self> >().parser())),
p.data().end());
else
+ // If we have a trailer, we do *not* use the 'bytes' value but initSize/initHeadSize, this
+ // is much safer since the bytes() value will probably not be very correct anyways (what
+ // should it return ? the size of the header only, the combined size of header and trailer
+ // or the size of the packet from header to trailer including payload?).
+ //
+ // So, the helper only works with fixed-size parsers if the packet has a trailer.
return PacketTypeBase::range(boost::next(p.data().begin(),sz),
boost::prior(p.data().end(),Self::initSize()-sz));
}
/** \brief Mixin to provide standard implementations for nextPacketRange and nextPacketType
- This mixin class simplifies the definition of simple packets with fixed-size (!) headers
- and/or trailers. For this type of Packet, this mixin provides the nextPacketRange()
- member. If you additionally provide the optional \a Registry argument, PacketTypeMixin
- provides a simple implementation of nextPacketType. When using the PacketTypeMixin, the
- implementation of a packet is simplified to:
+ This mixin class simplifies the definition of simple packets:
+
+ \li The packets consist of three sections: The header, the payload and an optional trailer.
+ \li If the packet has a trailer, both the header and the trailer must have a fixed size.
+
+ This mixin provides the nextPacketRange() member as well as initSize() and init(). If you
+ additionally provide the optional \a Registry argument, PacketTypeMixin provides a simple
+ implementation of nextPacketType().
+
+ When using the PacketTypeMixin, the implementation of a packet is simplified to:
\code
// Here 'SomeRegistryTag' is optional
struct SimplePacketType
typedef SomePacketParser parser;
using mixin::nextPacketRange;
- // Only if the optional 'Registry' argument is provided
- using mixin::nextPacketType;
- // Only if using the default implementation
+ using mixin::nextPacketType; // Only if the optional 'Registry' argument is provided
using mixin::initSize;
- // Only if using the default implementation
- using mixin::init;
-
- static interpreter::size_type initSize()
- {
- // This member is optional. If it is not defined, 'senf::init_size<parser>::value'
- // will be returned.
-
- // The value returned is the length of the header if initHeadSize() is not defined.
- // If initHeadSize is defined, this value is the combined size of the header
- // and trailer while initHeadSize() will return the size of the header only.
- return packet_size;
- }
-
- static interpreter::size_type initHeadSize()
- {
- // This member is optional. It returns the header size if the packet has a
- // trailer.
- return header_size;
- }
-
- static void init(packet p)
- {
- // This member is optional. The default implementation calls the parsers init()
- // member.
- }
+ using mixin::init;
static key_t nextPacketKey(packet p)
{
{
// Write out a readable representation of the packet for debug purposes
}
+
+ static interpreter::size_type initHeadSize()
+ {
+ // This member is optional. It returns the \e fixed header size if the packet has a
+ // trailer.
+ return header_size;
+ }
+
};
\endcode
- Most of the members are optional, which reduces the implementation of a fixed-sized header
- packet with no trailer and a simple next-packet header to
+ Most of the members are optional, which reduces the minimal implementation of a packet to:
\code
struct SimplePacketType
using mixin::nextPacketRange;
using mixin::nextPacketType;
using mixin::initSize;
- using mixin::init;
+ using mixin::init;
- static key_t nextPacketKey(packet p)
- { return p->typeField(); }
+ // 'typeField()' is one of the fields defined in the parser which holds
+ // the next-header information
+
+ static key_t nextPacketKey(packet p) { return p->typeField(); }
+ static void finalize(packet p) { p->typeField() << key(p.next(senf::nothrow)); }
+
+ static void dump(packet p) {
+ // should always be implemented although optional
+ }
};
\endcode
- If needed, you may additionally add a \c finalize() member. You also should add a \c dump()
- member to help debugging but both members are optional.
-
\ingroup packet_module
*/
template <class Self, class Registry=void>
font-size: 10pt;
}
+/* Argh .. doxygen.css has font-size:90% for td ... */
+td {
+ font-size: 100%;
+}
+
#head {
height: 62px;
border-top: 5px solid #DECD40;
font-weight: bold;
}
+table.fixedcolumn td:first-child {
+ width: 35%;
+}
+
table.ebnf {
margin: 0;
padding: 0;
border-spacing: 0;
border: none;
- font-size: 120%; /* ???????? Why is THIS needed ?? */
}
table.ebnf td {
padding: 0;
border-spacing: 0;
border: none;
- font-size: 120%; /* ???????? Why is THIS needed ?? */
}
table.listing td {