Socket: Move protocol into the socket body (as private base class) and allow non...
[senf.git] / HowTos / NewPacket / Mainpage.dox
index 482c84e..e9cca96 100644 (file)
 // Free Software Foundation, Inc.,
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-/** \mainpage libPackets: How to define and use a new Packet Type
+/** \mainpage Defining and using a new 'libPacket' Packet Type 
 
     This howto will introduce the facilities needed to define a new packet type. As example, the
     \c GREPacket type is defined. 
 
+    \autotoc
+
+
     \section howto_newpacket_start Getting started
 
     Before starting with the implementation, we look at the specification of the GRE packet. This is
@@ -46,7 +49,7 @@
     both be omitted.
 
     Another information we take from the RFC is, that the \a Protocol \a Type is used to define the
-    type of payload which directly follows the GRE header. This value is the <a
+    type of payload which directly follows the GRE header. This value is an <a
     href="http://www.iana.org/assignments/ethernet-numbers">ETHERTYPE</a> value. To allow the packet
     library to automatically parse the GRE payload data, we need to tell the packet library which
     ETHERTYPE represents which packet type. This association already exists in form of the
@@ -57,7 +60,8 @@
     \li The GRE packet header is a dynamically sized header.
     \li The GRE packet header utilizes the senf::EtherTypes registry for next-header selection
 
-    \section howto_newpacket_impl Implementing the GRE Parser
+
+    \section howto_newpacket_parser Implementing the GRE Parser
 
     The next step in creating a new packet type is to implement the parser. The parser is
     responsible for turning a bunch of bytes into an interpreted header with specific fields. The
     these members manually but the SENF library provides a large set of helper macros which simplify
     this task considerably.
 
+
+    \subsection howto_newpacket_parser_skeleton The PacketParser skeleton
+
     \code
-    struct GREParser : public senf::PacketParser
+    #include <senf/Packets.hh>
+
+    struct GREPacketParser : public senf::PacketParser
     {
     #   include SENF_PARSER()
 
         // Define fields
 
-        SENF_PARSER_FINALIZE(GREParser);
+        SENF_PARSER_FINALIZE(GREPacketParser);
     };
     \endcode
 
     This is the standard skeleton of any parser class: We need to inherit senf::PacketParser and
     start out by including either \ref SENF_PARSER() or \ref SENF_FIXED_PARSER(). Which, depends on
-    whether we define a fixed size or a dynamically sized parser. As \c GREParser is dynamically
+    whether we define a fixed size or a dynamically sized parser. As \c GREPacketParser is dynamically
     sized, we include \ref SENF_PARSER().
 
     After the fields are defined, we need to call the \ref SENF_PARSER_FINALIZE() macro to close of
@@ -90,6 +99,9 @@
     go back to define the parser fields and begin with the simple part: Those fields which are
     always present.
 
+
+    \subsection howto_newpacket_parser_simple Simple field definitions
+
     \code
     SENF_PARSER_BITFIELD  ( checksumPresent, 1, bool     );
     SENF_PARSER_SKIP_BITS (                 12           );
     SENF_PARSER_BITFIELD  ( protocolType,   16, unsigned );
     \endcode
     
-    This is a direct transcript of the field definition above. However, we can optimize this a
-    little bit: Since the \a protocolType field is aligned on a byte boundary, instead of defining
-    it as a bitfield, we can define it as a UInt16 field:
+    This is a direct transcript of the field definition above. There are quite a number of macros
+    which may be used to define fields. All these macros are documented in '\ref
+    packetparsermacros'.
+
+    This is a correct \c GREPacket header definition but we can optimize a little bit: Since the \a
+    protocolType field is aligned on a byte boundary, instead of defining it as a bitfield, we can
+    define it as a UInt16 field:
     
     \code
     SENF_PARSER_BITFIELD  ( checksumPresent,  1, bool     );
     SENF_PARSER_FIELD     ( protocolType,    senf::UInt16Parser );
     \endcode
 
-    There are quite a number of such \c SENF_PARSER_ macros. They are all listed in \ref
-    packetparsermacros. The basic field types (like senf::UInt16Parser) are listed in \ref parseint.
-
-    What happens in the above macros? Most of the macros define an accessor for a specific field: \a
-    checksumPresent() or \a protocolType(). They also manage a <em>current Offset</em>. This value
-    is advanced according to the field size whenever a new field is defined (and since this parser
-    is defined as a dynamically sized parser, this offset is not a constant, it is an expression
-    which calculates the offset of a field depending on the preceding data).
+    Whereas \ref SENF_PARSER_BITFIELD can define only bit-fields, \ref SENF_PARSER_FIELD can define
+    almost arbitrary field types. The type is specified by passing the name of another parser to
+    \ref SENF_PARSER_FIELD.
 
     It is important to understand, that the accessors do \e not return the parsed field value. They
     return another \e parser which is used to further interpret the value. This is the inherent
     recursive nature of the SENF packet parsers. This allows to define wildly complex header formats
     if needed. Of course, at some point we need the real value. This is, what the so called
     <em>value parsers</em> do: They interpret some bytes or bits and return the value of that field
-    (not a parser). Examples are the bitfield parsers returnd by the accessors generated by
+    (not a parser). Examples are the bitfield parsers returned by the accessors generated by
     SENF_PARSER_BITFIELD (like senf::UIntFieldParser) or the senf::UInt16Parser.
 
+    What happens in the above macros? Most of the macros define an accessor for a specific field: \a
+    checksumPresent() or \a protocolType(). They also manage a <em>current Offset</em>. This value
+    is advanced according to the field size whenever a new field is defined (and since this parser
+    is defined as a dynamically sized parser, this offset is not a constant, it is an expression
+    which calculates the offset of a field depending on the preceding data).
+
+
+    \subsection howto_newpacket_parser_variant Defining optional fields: The 'variant' parser
+
     We now come to the optional fields. Since there are two fields which need to be disabled/enabled
-    together, we first need to define an additional sub-parser which parses those two fields. After
-    this parser is defined, we can use \ref SENF_PARSER_VARIANT() to add this parser as an optional
-    parser to the GRE header.
+    together, we first need to define an additional sub-parser which combines those two
+    fields. After this parser is defined, we can use \ref SENF_PARSER_VARIANT() to add this parser
+    as an optional parser to the GRE header.
     
     \code
-    struct GREParser_OptFields : public senf::PacketParser
+    struct GREPacketParser_OptFields : public senf::PacketParser
     {
     #   include SENF_FIXED_PARSER()
 
         SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
         SENF_PARSER_SKIP  (           2                  );
 
-        SENF_PARSER_FINALIZE(GREParser_OptFields);
+        SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
     };
     \endcode
 
     This parser only parses the two optional fields of which the reserved field is just skipped. The
-    parser this time is a fixed size parser. We can now use this parser to continue the \c GREParser
+    parser this time is a fixed size parser. We can now use this parser to continue the \c GREPacketParser
     implementation:
 
     \code
 
     SENF_PARSER_VARIANT   ( optionalFields,  checksumPresent,
                                              (senf::VoidPacketParser)
-                                             (GREParser_OptFields) );
+                                             (GREPacketParser_OptFields) );
     \endcode
 
-    How does this work? For a variant parser, two things need to be specified: A selector and a list
-    of variant parsers. The selector is another parser field which is used to decide, which variant
-    to choose. In this simple case, the field must be an unsigned integer (more precisely a value
+    For a variant parser, two things need to be specified: A selector and a list of variant
+    parsers. The selector is another parser field which is used to decide, which variant to
+    choose. In this simple case, the field must be an unsigned integer (more precisely a value
     parser which returns a value which is implicitly convertible to \c unsigned). This value is used
     as index into the list of variant types. So in our case, 0 is associated with
-    senf::VoidPacketParser whereas 1 is associated with \c GREParser_OptFields.
+    senf::VoidPacketParser whereas 1 is associated with \c
+    GREPacketParser_OptFields. (senf::VoidPacketParser is a special empty parser which is used in a
+    Variant to denote cases in which the variant parser should not parse anything)
 
-    This parser will work, it is however not very safe and not very usable. If \a p is a GREParser
+    This parser will work, it is however not very safe and not very usable. If \a p is a GREPacketParser
     instance, than we access the fields via:
     \code
-    p.checksumPresent()
-    p.version()
-    p.protocolType()
-    p.optionalFields().get<1>().checksum()
+    p.checksumPresent()                    = true;
+    p.version()                            = 4u;
+    p.protocolType()                       = 0x86dd;
+    p.optionalFields().get<1>().checksum() = 12345u;
     \endcode
     
     There are two problems here:
-    \li accessing the checksum field is not straight forward
+    \li accessing the checksum field is quite unwieldy
     \li changing the checksumPresent() value will break the parser
 
     The reason for the second problem lies in the fact, that the variant parser needs to be informed
     whenever the selector (here \a checksumPresent) is changed since the variant parser must ensure,
     that the header data stays consistent. In this example, whenever the checksumPresent field is
     enabled, the variant parser needs to insert additional 4 bytes of data and remove those bytes,
-    when the checksumPresent field is disabled. We therefore make the checksumPresent field
-    read-only:
+    when the checksumPresent field is disabled. 
+
+
+    \subsection howto_newpacket_parser_fixvariant Fixing access by providing custom accessor members
+
+    Since we don't want to allow the \a checksumPresent() field to be changed directly, we mark this
+    field as read-only:
 
     \code
     SENF_PARSER_BITFIELD_RO ( checksumPresent,  1, bool     );
     \endcode
 
-    To change the checksumPresent value, we now need to use the variant parsers \a init member:
+    To change the \a checksumPresent() value, the variant parser provides special members to change
+    the currently selected variant:
 
     \code
     p.optionalFields().init<0>();
     p.optionalFields().init<1>();
     \endcode
     
-    The first statements switches to the first variant and therefore in this case disables the
-    checksum field. The second statement will switch to the second variant and enable the checksum
-    field. This again is not very usable. So we complete the parser by providing simple additional
-    members which access the fields in a more readable way. While doing this, we also mark the
-    variant as a private field so it is not directly accessible any more. Here the final \c
-    GREParser
+    These statements also change the selector field (in this case \a checksumPresent()) to the
+    correct value: The first statements switches to the first variant and therefore in this case
+    disables the checksum field. The second statement will switch to the second variant and enable
+    the checksum field.
+
+    Again, these statements are relatively complex. So we complete the parser by providing simple
+    additional members which wrap these complicated calls. While doing this, we also mark the
+    variant as a private field so it is not directly accessible any more (since we now have the
+    additional helpers which are used to access the variant, we don't want anyone to mess around
+    with it directly).
 
     \code
-    struct GREParser_OptFields : public senf::PacketParser
+    SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
+                                                     (senf::VoidPacketParser)
+                                                     (GREPacketParser_OptFields)    );
+
+    typedef GREPacketParser_OptFields::checksum_t checksum_t;
+    checksum_t checksum() const
+        { return optionalFields_().get<1>().checksum(); }
+
+    void enableChecksum()  const { optionalFields_().init<1>(); }
+    void disableChecksum() const { optionalFields_().init<0>(); }
+    \endcode
+
+    Above code has one other twist we need to discuss: the \a checksum_t typedef. This is added as a
+    convenience to the user of this parser. The \c SENF_PARSER_* macros which define a field all
+    define some additional symbols providing further information about the field. Of these
+    additional symbols, the most important is <em>field</em><code>_t</code>, which is the (parser)
+    type returned by the field. This helps to work with a parser in more complex situations
+    (e.g. when using \ref parsecollection) since it allows to access the parser type without exact
+    knowledge of this type (which may become quite complex if templates are involved) as long as the
+    field name is known. Since we provide an accessor for the \a checksum field, we also provide the
+    \a checksum_t typedef for this accessor.
+
+    The \c GREPacketParser is now simple and safe to use. The only responsibility of the user now is to
+    only access \a checksum() if the \a checksumPresent() field is set. Otherwise, the behavior is
+    undefined (in debug builds, the parser will terminate the application with an assert).
+
+    
+    \subsection howto_newpacket_parser_add Providing additional functionality
+
+    The \c GREPacketParser is now complete. But we can do better: A packet parser is not restricted
+    to simply parsing data. Depending on the packet type, additional members can be arbitrarily
+    defined. In the case of \c GREPacket, we provide one additional member, \a calculateChecksum()
+    which does just that: It calculates the checksum of the GRE packet.
+
+    \code
+    #include <senf/Utils/IpChecksum.hh>
+
+    checksum_t::value_type calculateChecksum() const 
+    {
+        if (!checksumEnabled()) 
+            return 0;
+
+        senf::IpChecksum cs;
+        cs.feed( i(), i(4) );
+        // Skip even number of 0 bytes (the 2 bytes checksum field)
+        // cs.feed(0); cs.feed(0);
+        cs.feed( i(6), data().end() );
+
+        return cs.sum()
+    }
+    \endcode
+
+    This code just implements what is defined in the RFC: The checksum covers the complete GRE
+    packet including it's header with the checksum field temporarily set to 0. Instead of really
+    changing the checksum field we manually pass the correct data to \a cs. 
+
+    We use the special <tt>i(</tt><i>offset</i><tt>)</tt> helper to get iterators \a offset number
+    of bytes into the data. This helper has the additional benefit of range-checking the returned
+    iterator and thereby safe os from errors due to truncated packets: If the offset is out of
+    range, a TruncatedPacketException will be thrown.
+
+    In this code we utilize some additional information provided by senf::PacketParserBase. The \a
+    i() member returns an iterator to the first byte the parser is interpreting whereas \a data()
+    returns a reference to the packet data container for the packet being parsed. Access to \a
+    data() should be restricted as much as possible. It is safe when defining new packet parsers
+    (like GREPacketParser). It's usage from sub parsers (like GREPacketParser_OptFields or even
+    senf::UInt16Parser) would be much more arcane and should be avoided.
+
+
+    \subsection howto_newpacket_parser_final The complete GREPacketParser implementation
+
+    So this is now the complete implementation of the \c GREPacketParser:
+
+    \code
+    #include <senf/Packets.hh>
+    
+    struct GREPacketParser_OptFields : public senf::PacketParser
     {
     #   include SENF_FIXED_PARSER()
 
-        SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
-        SENF_PARSER_SKIP  (           2                  );
+        SENF_PARSER_FIELD           ( checksum,        senf::UInt16Parser            );
+        SENF_PARSER_SKIP            (                   2                            );
 
-        SENF_PARSER_FINALIZE(GREParser_OptFields);
+        SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
     };
 
-    struct GREParser : public senf::PacketParser
+    struct GREPacketParser : public senf::PacketParser
     {
     #   include SENF_PARSER()
 
-        SENF_PARSER_BITFIELD_RO     ( checksumPresent,  1, bool                   );
-        SENF_PARSER_SKIP_BITS       (                  12                         );
-        SENF_PARSER_BITFIELD        ( version,          3, unsigned               );
+        SENF_PARSER_BITFIELD_RO     ( checksumPresent,  1, bool                      );
+        SENF_PARSER_SKIP_BITS       (                  12                            );
+        SENF_PARSER_BITFIELD        ( version,          3, unsigned                  );
 
-        SENF_PARSER_FIELD           ( protocolType,    senf::UInt16Parser         );
+        SENF_PARSER_FIELD           ( protocolType,    senf::UInt16Parser            );
 
         SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
                                                          (senf::VoidPacketParser)
-                                                         (GREParser_OptFields)    );
+                                                         (GREPacketParser_OptFields) );
 
-        typedef GREParser_OptFields::checksum_t checksum_t;
+        typedef GREPacketParser_OptFields::checksum_t checksum_t;
         checksum_t checksum() const
             { return optionalFields_().get<1>().checksum(); }
 
         void enableChecksum()  const { optionalFields_().init<1>(); }
         void disableChecksum() const { optionalFields_().init<0>(); }
     
-        SENF_PARSER_FINALIZE(GREParser);
+        SENF_PARSER_FINALIZE(GREPacketParser);
+
+        checksum_t::value_type calculateChecksum() const;
     };
+
+    // In the implementation (.cc) file:
+
+    #include <senf/Utils/IpChecksum.hh>
+    
+    GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const
+    {
+        if (!checksumEnabled()) 
+            return 0;
+
+        validate(6);
+        senf::IpChecksum cs;
+        cs.feed( i(), i()+4 );
+        // Skip even number of 0 bytes (the 2 bytes checksum field)
+        // cs.feed(0); cs.feed(0);
+        cs.feed( i()+6, data().end() );
+
+        return cs.sum()
+    }
     \endcode
+
+
+    \section howto_newpacket_type Defining the packet type
+
+    After we have implemented the \c GREPacketParser we now need to build the packet type. This is
+    done by providing a special policy class called the 'packet type'. This class encapsulates all
+    the information the packet library needs to know about a packet:
+
+
+    \subsection howto_newpacket_type_skeleton The packet type skeleton
+
+    For every type of packet, the 'packet type' class will look roughly the same. If the packet
+    utilizes a registry and is not hopelessly complex, the packet type will almost always look like
+    this:
+    \code
+    #include <senf/Packets.hh>
+
+    struct GREPacketType
+        : public senf::PacketTypeBase,
+          public senf::PacketTypeMixin<GREPacketType, EtherTypes>
+    {
+        typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
+        typedef senf::ConcretePacket<GREPacketType> packet;
+        typedef senf::GREPacketParser parser;
+    
+        using mixin::nextPacketRange;
+        using mixin::nextPacketType;
+        using mixin::init;
+        using mixin::initSize;
+
+        // Define members here
+    };
+    \endcode
+    We note, that \c GREPacketType derives from two classes: senf::PacketTypeBase and
+    senf::PacketTypeMixin. senf::PacketTypeBase must be inherited by every packet type class. the
+    senf::PacketTypeMixin provides default implementations for some members which are useful for
+    most kinds of packets. If a packet type is very complex and these defaults don't work, the mixin
+    class can and should be left out.
+
+    Of the typedefs, only \a parser is mandatory. It defines the packet parser to use to interpret
+    this type of packet. \a mixin and \a packet are defined to simplify the following
+    definitions (More on \a packet and senf::ConcretePacket later).
+
+    The next block of statements imports all the default implementations provided by the mixin
+    class:
+    
+    \li \a nextPacketRange provides information about where the next packet lives within the GRE
+        packet.
+    \li \a nextPacketType provides the type of the next packet from information in the GRE packet.
+    \li \a init is called to initialize a new GRE packet. This call is forwarded to \c
+        GREPacketParser::init.
+    \li \a initSize is called to find the size of an empty (newly create) GRE packet. This is also
+        provided by GREPacketParser.
+    
+    With these default implementations provided by the mixin, only a few additional members are
+    needed to complete the \c GREPacketType: \a nextPacketKey, \a finalize, and \a dump
+
+
+    \subsection howto_newpacket_type_registry Utilizing the packet registry
+
+    We want the GRE packet to utilize the senf::EtherTypes registry to find the type of packet
+    contained in the GRE payload. A registry maps an arbitrary key value to a packet type
+    represented by a packet factory instance. The details have already been taken care of by the
+    senf::PacketTypeMixin (it provides the \a nextPacketType member). However, to lookup the packet
+    in the registry, the mixin needs to know the key value. To this end, we implement \a
+    nextPacketKey(), which is very simple:
+
+    \code
+    static key_t nextPacketKey(packet p) { return p->protocolType(); }
+    \endcode
+
+    All \c GREPacketType members are static. They are passed the packet in question as an
+    argument. \a nextPacketKey() just needs to return the value of the correct packet field. And
+    since the \c parser type (as defined as a typedef) allows direct access to the packet parser
+    using the <tt>-></tt> operator, we can simply access that value.
+
+    The \c key_t return type is a typedef provided by the mixin class it is taken from the type of
+    registry, in this case it is senf::EtherTypes::key_t (which is defined as a 16 bit unsigned
+    integer value).
+
+    With this information, the packet library can now find out the type of packet needed to parse
+    the GRE payload -- as long as the protocolType() is registered with the senf::EtherTypes
+    registry. If this is not the case, the packet library will not try to interpret the payload, it
+    will return a senf::DataPacket.
+
+    One special case of GRE encapsulation occurs when layer 2 frames and especially ethernet frames
+    are carried in the GRE payload. The ETHERTYPE registry normally only contains layer 3 protocols
+    (like IP or IPX) however for this special case, the value 0x6558 has been added to the ETHERTYPE
+    registry. So we need to add this value to inform the packet library to parse the payload as an
+    ethernet packet if the \a protocolType() is 0x6558. This happens in the implementation file (the
+    \c .cc file):
+
+    \code
+    #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
+
+    SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
+    \endcode
+
+    This macro registers the value 0x6558 in the senf::EtherTypes registry and associates it with
+    the packet type senf::EthernetPacket. This macro declares an anonymous static variable, it
+    therefore must always be placed in the implementation file and \e never in an include file.
+
+    Additionally, we want the GRE packet to be parsed when present as an IP payload. Therefore we
+    additionally need to register GRE in the senf::IpTypes registry. Looking at the <a
+    href="http://www.iana.org/assignments/protocol-numbers">IP protocol numbers</a>, we find that
+    GRE has been assigned the value 47:
+
+    \code
+    #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
+
+    SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
+    \endcode
+
+    But wait -- what is \c GREPacket ? This question is answered a few section further down.
+
+
+    \subsection howto_newpacket_type_invariants Providing packet invariants
+
+    Many packets have some invariants that must hold: The payload size must be equal to some field,
+    a checksum must match and so on. When packets are newly created or changed, these invariants
+    have to be updated to be correct. This is the responsibility of the \a finalize() member. This
+    is also the place, where the \a protocolType() field is assigned.
+
+    \code
+    static void finalize(packet p) 
+    {
+        p->protocolType() << key(p.next(senf::nothrow));
+        if (p->checksumPresent())
+            p->checksum() << p->calculateChecksum();
+    }
+    \endcode
+    
+    \a finalize() firs sets the \a protocolType() field depending on the \e next packet. The \c
+    key() function is provided by the mixin class: It will lookup the \e type of a packet in the
+    registry and return that packets key in the registry. 
+
+    It then updates the \a checksum() field if present (this always needs to be done last since the
+    checksum depends on the other field values).
+
+    Here we are using the more generic parser assignment expressed using the \c << operator. This
+    operator in the most cases works like an ordinary assignment, however it can also be used to
+    assign parsers to each other efficiently and it supports 'optional values' (as provided by <a
+    href="http://www.boost.org/libs/optional/doc/optional.html">Boost.Optional</a> and as returned
+    by \c key()).
+
+
+    \subsection howto_newpacket_type_dump Writing out a complete packet: The 'dump()' member
+
+    For diagnostic purposes, every packet should provide a meaningful \a dump() member which writes
+    out the complete packet. This member is simple to implement and is often very helpful when
+    tracking down problems.
+    
+    \code
+    #include <boost/io/ios_state.hpp>
+
+    static void dump(packet p, std::ostream & os)
+    {
+        boost::io::ios_all_saver ias(os);
+        os << "General Routing Encapsulation:\n"
+           << "  checksum present              : " << p->checksumPresent() ? "true" : "false" << "\n"
+           << "  version                       : " << p->version() << "\n"
+           << "  protocol type                 : 0x" << std::hex << std::setw(4) << std::setfill('0')
+                                                     << p->protocolType() << "\n";
+        if (p->checksumPresent())
+            os << "  checksum                     : 0x" << std::hex << std::setw(4)
+                                                        << std::setfill('0') << p->checksum() << "\n"; 
+    }
+    \endcode
+    
+    This member is quite straight forward. We should try to adhere to the formating standard shown
+    above: The first line should be the type of packet/header being dumped followed by one line for
+    each protocol field. The colon's should be aligned at column 33 with the field name indented by
+    2 spaces. 
+
+    The \c boost::ios_all_saver is just used to ensure, that the stream formatting state is restored
+    correctly at the end of the method. An instance of this type will save the stream state when
+    constructed and will restore that state when destructed.
+
+    \subsection howto_newpacket_type_final Final touches
+
+    The \c GREPacket implementation is now almost complete. The only thing missing is the \c
+    GREPacket itself. \c GREPacket is just a typedef for a specific senf::ConcretePacket template
+    instantiation. Here the complete GREPacket definition:
+
+    \code
+    #include <senf/Packets.hh>
+
+    struct GREPacketType
+        : public senf::PacketTypeBase,
+          public senf::PacketTypeMixin<GREPacketType, EtherTypes>
+    {
+        typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
+        typedef senf::ConcretePacket<GREPacketType> packet;
+        typedef senf::GREPacketParser parser;
+    
+        using mixin::nextPacketRange;
+        using mixin::nextPacketType;
+        using mixin::init;
+        using mixin::initSize;
+
+        static key_t nextPacketKey(packet p) { return p->protocolType(); }
+    
+        static void finalize(packet p) {
+            p->protocolType() << key(p.next(senf::nothrow)); 
+            if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
+       }
+    
+        static void dump(packet p, std::ostream & os);
+    };
+
+    typedef GREPacketType::packet GREPacket;
+    
+    // In the implementation (.cc) file:
+
+    #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
+    #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
+
+    SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
+    SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
+
+    void GREPacketType::dump(packet p, std::ostream & os)
+    {
+        boost::io::ios_all_saver ias(os);
+        os << "General Routing Encapsulation:\n"
+           << "  checksum present              : " << p->checksumPresent() ? "true" : "false" << "\n"
+           << "  version                       : " << p->version() << "\n"
+           << "  protocol type                 : 0x" << std::hex << std::setw(4) << std::setfill('0')
+                                                     << p->protocolType() << "\n";
+        if (p->checksumPresent())
+            os << "  checksum                     : 0x" << std::hex << std::setw(4)
+                                                        << std::setfill('0') << p->checksum() << "\n"; 
+    }
+    \endcode
+
+
+    \section howto_newpacket_advanced Going further
+
+    \subsection howto_newpacket_advanced_valid Checking the GRE packet for validity
+
+    We have implemented the \c GREPacket completely by now. There is however still room for
+    improvement. Reading the RFC, there are some restrictions which a packet needs to obey to be
+    considered valid. If the packet is not valid it cannot be parsed and should be dropped. There
+    are two conditions which lead to this: If one of the \a reserved0 fields first 5 bits is set or
+    if the version is not 0. We will add a \a valid() check to the parser and utilize this check in
+    the packet type.
+
+    So first lets update the parser. We will need to change the fields a little bit so we have
+    access to the first 5 bits of \a reserved0. We therefore replace the first three field
+    statements with
+
+    \code
+    SENF_PARSER_BITFIELD_RO      ( checksumPresent,  1, bool                      );
+    SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned                  );
+    SENF_PARSER_SKIP_BITS        (                   7                            );
+    SENF_PARSER_PRIVATE_BITFIELD ( version_,         3, unsigned                  );
+    \endcode
+
+    We have added an additional private bitfield \a reserved0_5bits_() and we made the \a version_()
+    field private since we do not want the user to change the value. We could have used a read-only
+    field in this special case (since the valid value is 0) but generally in a case like this since
+    the field will be initialized by the parser (see next section on how). the field should be
+    private with an additional public read-only accessor.
+
+    We will now add two additional simple members to the parser
+
+    \code
+    typedef version__t version_t;
+    version_t::value_type version() const { return version_(); }
+
+    bool valid() const { return version() == 0 && reserved0_5bits_() == 0; }
+    \endcode
+
+    I think, both are quite straight forward: \a version() will allow the user to read out the value
+    of the version field. However, since it does \e not return a parser but a numeric value, the
+    access is read-only. The \a valid() member will just check the restrictions as defined in the RFC.
+
+    Now to the packet type. We want to refrain from parsing the payload if the packet is
+    invalid. This is important: If the packet is not valid, we have no idea, whether the payload is
+    what we surmise it to be (if any of the \a reserved0_5bits_() are set, the packet is from an
+    older GRE RFC and the header is quite a bit longer so the payload will be incorrect).
+
+    So we need to change the logic which is used by the packet library to find the type of the next
+    packet. We have two ways to do this: We keep using the default \c nextPacketType()
+    implementation as provided by the senf::PacketTypeMixin and have our \a nextPacketKey()
+    implementation return a key value which is guaranteed never to be registered in the registry.
+
+    The more flexible possibility is implementing \c nextPacketType() ourselves. In this case, the
+    first method would suffice, but we will choose to go the second route to show how to write the
+    \c nextPacketType() member. We therefore remove the \c using declaration of \c nextPacketType()
+    and also remove the \a nextPacketKey() implementation. Instead we add the following to the
+    packet type
+
+    \code
+    // disabled: using Min::nextPacketType;
+
+    factory_t nextPacketType(packet p) { return p->valid() ? lookup(p->protocolType()) : no_factory(); }
+    \endcode
+    
+    As we see, this is still quite simple. \c factory_t is provided by senf::PacketTypeBase. For our
+    purpose it is an opaque type which somehow enables the packet library to create a new packet of
+    a specified packet type. The \c factory_t has a special value, \c no_factory() which stands for
+    the absence of any concrete factory. In a boolean context this (and only this) \c factory_t
+    value tests \c false.
+
+    The \c lookup() member is provided by the senf::PacketTypeMixin. It looks up the key passed as
+    argument in the registry and returns the factory or \c no_factory(), if the key was not found in
+    the registry.
+
+    In this case this is all. We can however return the factory for some specific type easily as in
+    the following example:
+
+    \code
+    factory_t nextPacketType(packet p) { 
+        if (p->valid()) {
+            if (p->protocolType() == 0x6558)  return senf::EthernetPacket::factory();
+            else                              return lookup(p->protocolType());
+        }
+        else                                  return no_factory();
+    }
+    \endcode
+
+    Of course, this example is academic since senf::EthernetPacket is correctly registered in the
+    senf::EtherTypes registry but you get the picture.
+
+
+    \subsection howto_newpacket_advanced_init Non-trivial packet initialization
+
+    When we create a new GRE packet using the packet library, the library will initialize the packet
+    with all 0 bytes. It just happens, that this is correct for our GRE packet. Lets just for the
+    sake of experiment assume, the GRE packet would have to set \a version() to 1 not 0. In this
+    case, the default initialization would not suffice. It is however very simple to explicitly
+    initialize the packet. The initialization happens within the parser. We just add
+
+    \code
+    SENF_PARSER_INIT() { version_() << 1u; }
+    \endcode
+
+    to \c GREPacketParser. Here we see, why we have defined \a version_() as a private and not a
+    read-only field.
+
+
+    \section howto_newpacket_final The ultimate GRE packet implementation completed
+
+    So here we now have \c GREPacket finally complete in all it's glory. First the header file \c
+    GREPacket.hh:
+
+    \code
+    #ifndef HH_GREPacket_
+    #define HH_GREPacket_
+
+    #include <senf/Packets.hh>
+    
+    struct GREPacketParser_OptFields : public senf::PacketParser
+    {
+    #   include SENF_FIXED_PARSER()
+
+        SENF_PARSER_FIELD           ( checksum,        senf::UInt16Parser            );
+        SENF_PARSER_SKIP            (                   2                            );
+
+        SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
+    };
+
+    struct GREPacketParser : public senf::PacketParser
+    {
+    #   include SENF_PARSER()
+
+        SENF_PARSER_BITFIELD_RO      ( checksumPresent,  1, bool                      );
+        SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned                  );
+        SENF_PARSER_SKIP_BITS        (                   7                            );
+        SENF_PARSER_PRIVATE_BITFIELD ( version_,         3, unsigned                  );
+
+        SENF_PARSER_FIELD            ( protocolType,    senf::UInt16Parser            );
+
+        SENF_PARSER_PRIVATE_VARIANT  ( optionalFields_, checksumPresent,
+                                                          (senf::VoidPacketParser)
+                                                          (GREPacketParser_OptFields) );
+
+        typedef version__t version_t;
+        version_t::value_type version() const { return version_(); }
+
+        bool valid() const { return version() == 0 && reserved0_5bits_() == 0; }
+
+        typedef GREPacketParser_OptFields::checksum_t checksum_t;
+        checksum_t checksum() const
+            { return optionalFields_().get<1>().checksum(); }
+
+        void enableChecksum()  const { optionalFields_().init<1>(); }
+        void disableChecksum() const { optionalFields_().init<0>(); }
+    
+        SENF_PARSER_FINALIZE(GREPacketParser);
+
+        checksum_t::value_type calculateChecksum() const;
+    };
+
+    struct GREPacketType
+        : public senf::PacketTypeBase,
+          public senf::PacketTypeMixin<GREPacketType, EtherTypes>
+    {
+        typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
+        typedef senf::ConcretePacket<GREPacketType> packet;
+        typedef senf::GREPacketParser parser;
+    
+        using mixin::nextPacketRange;
+        using mixin::init;
+        using mixin::initSize;
+
+        factory_t nextPacketType(packet p) 
+            { return p->valid() ? lookup(p->protocolType()) : no_factory(); }
+    
+        static void finalize(packet p) {
+            p->protocolType() << key(p.next(senf::nothrow));
+            if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
+        }
+    
+        static void dump(packet p, std::ostream & os);
+    };
+
+    typedef GREPacketType::packet GREPacket;
+    
+    #endif
+    \endcode
+
+    And the implementation file \c GREPacket.cc:
+
+    \code
+    #include "GREPacket.hh"
+    #include <senf/Utils/IpChecksum.hh>
+    #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
+    #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
+
+    SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
+    SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
+
+    GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const
+    {
+        if (!checksumEnabled()) 
+            return 0;
+
+        validate(6);
+        senf::IpChecksum cs;
+        cs.feed( i(), i()+4 );
+        // Skip even number of 0 bytes (the 2 bytes checksum field)
+        // cs.feed(0); cs.feed(0);
+        cs.feed( i()+6, data().end() );
+
+        return cs.sum()
+    }
+
+    void GREPacketType::dump(packet p, std::ostream & os)
+    {
+        boost::io::ios_all_saver ias(os);
+        os << "General Routing Encapsulation:\n"
+           << "  checksum present              : " << p->checksumPresent() ? "true" : "false" << "\n"
+           << "  version                       : " << p->version() << "\n"
+           << "  protocol type                 : 0x" << std::hex << std::setw(4) << std::setfill('0')
+                                                     << p->protocolType() << "\n";
+        if (p->checksumPresent())
+            os << "  checksum                     : 0x" << std::hex << std::setw(4)
+                                                        << std::setfill('0') << p->checksum() << "\n"; 
+    }
+    \endcode
+
+
+    \section howto_newpacket_using Using the newly created GRE packet type
+
+    The GRE packet is now fully integrated into the packet library framework. For example, we can
+    read GRE packets from a raw INet socket and forward decapsulated Ethernet frames to a packet
+    socket.
+
+    \code
+    #include <iostream>
+    #include <senf/Packets.hh>
+    #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
+    #include <senf/Socket/Protocols/INet/RawINetProtocol.hh>
+    #include <senf/Socket/Protocols/Raw/PacketSocketHandle.hh>
+    #include "GREPacket.hh"
+
+    int main(int, char const **)
+    {
+        senf::RawV6ClientSocketHandle isock (47u); // 47 = Read GRE packets
+        senf::PacketSocketHandle osock;
+
+        while (true) {
+            try {
+                GREPacket gre (GREPacket::create(senf::noinit));
+                isock.read(gre.data(),0u);
+                if (gre->checksumPresent() && gre->checksum() != gre->calculateChecksum())
+                    throw InvalidPacketChainException();
+                osock.write(gre.next<EthernetPacket>().data())
+            }
+            catch (senf::TruncatedPacketException & ex) {
+                std::cerr << "Malformed packet dropped\n";
+            }
+            catch (senf::InvalidPacketChainException & ex) {
+                std::cerr << "Invalid GRE packet dropped\n";
+            }
+        }
+    }
+    \endcode
+
+    Or we can do the opposite: Read ethernet packets from a \c tap device and send them out GRE
+    encapsulated.
+
+    \code
+    #include <iostream>
+    #include <senf/Packets.hh>
+    #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
+    #include <senf/Socket/Protocols/INet/RawINetProtocol.hh>
+    #include <senf/Socket/Protocols/Raw/TunTapSocketHandle.hh>
+    #include "GREPacket.hh"
+
+    int main(int argc, char const ** argv)
+    {
+        if (argc != 2) {
+            std::cerr << "Usage: " << argv[0] << " <tunnel endpoint>\n";
+            return 1;
+        }
+
+        senf::TapSocketHandle tap ("tap0");
+        senf::ConnectedRawV6ClientSocketHandle osock (47u, senf::INet6SocketAddress(argv[1]));
+    
+        while (true) {
+            senf::EthernetPacket eth (senf::EthernetPacket::create(senf::noinit));
+            isock.read(eth.data(),0u);
+            GREPacket gre (senf::GREPacket::createBefore(eth));
+            gre.finalize();
+            osock.write(gre.data());
+        }
+    }
+    \endcode
+
+    
+    \section howto_newpacket_further Further reading
+
+    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):
+
+    <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:
+
+    <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, these lists are not complete as there are other protocol
+    specific reusable parsers (without claiming to be exhaustive: senf::INet4AddressParser,
+    senf::INet6AddressParser, senf::MACAddressParser)</td></tr>
+
+    </table>
+
  */
 
 \f
 // indent-tabs-mode: nil
 // ispell-local-dictionary: "american"
 // compile-command: "scons -u doc"
-// mode: flyspell
 // mode: auto-fill
 // End: