Packets: Add PacketParserBase::i(size_type) utility
g0dil [Fri, 25 Jan 2008 11:10:58 +0000 (11:10 +0000)]
Packets: Renamed PacketParserMixin::registry_key_t to key_t
Packets: Add PacketParserMixin::lookup helper

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@638 270642c3-0616-0410-b53a-bc976706d245

15 files changed:
HowTos/NewPacket/Mainpage.dox
Packets/DefaultBundle/EthernetPacket.cc
Packets/DefaultBundle/EthernetPacket.hh
Packets/DefaultBundle/IPv4Packet.hh
Packets/DefaultBundle/IPv6Extensions.hh
Packets/DefaultBundle/IPv6Packet.hh
Packets/DefaultBundle/LlcSnapPacket.cc
Packets/MPEGDVBBundle/SNDUPacket.cc
Packets/MPEGDVBBundle/SNDUPacket.hh
Packets/Packet.test.cc
Packets/PacketParser.cci
Packets/PacketParser.hh
Packets/PacketType.cti
Packets/PacketType.hh
senf.dict

index ef7a92d..1395147 100644 (file)
@@ -74,6 +74,8 @@
     \subsection howto_newpacket_parser_skeleton The PacketParser skeleton
 
     \code
+    #include <senf/Packets.hh>
+
     struct GREPacketParser : public senf::PacketParser
     {
     #   include SENF_PARSER()
     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 );
+        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() );
+        cs.feed( i(6), data().end() );
 
         return cs.sum()
     }
     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
 
     \code
     #include <senf/Packets.hh>
-    #include <senf/Utils/IpChecksum.hh>
     
     struct GREPacketParser_OptFields : public senf::PacketParser
     {
 
         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)
     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>
     \c .cc file):
 
     \code
+    #include <senf/Packets/DefaultBundle/EthernetPacket.hh>
+
     SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
     \endcode
 
     GRE has been assigned the value 47:
 
     \code
+    #include <senf/Packets/DefaultBundle/IPv4Packet.hh>
+
     SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
     \endcode
 
     {
         if (p->checksumPresent())
             p->checksum() << p->calculateChecksum();
-        p->protocolType() << key(p->next(senf::nothrow));
+        p->protocolType() << key(p.next(senf::nothrow));
     }
     \endcode
     
     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) {
+            if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
+            p->protocolType() << key(p.next(senf::nothrow));
+        }
+    
+        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 GRE_PACKET_HH
+    #define GRE_PACKET_HH
+
+    #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) {
+            if (p->checksumPresent()) p->checksum() << p->calculateChecksum();
+            p->protocolType() << key(p.next(senf::nothrow));
+        }
+    
+        static void dump(packet p, std::ostream & os);
+    };
+
+    typedef GREPacketType::packet GREPacket;
     
-    \fixme Document the needed \c \#include files
-    \fixme Provide an advanced section with additional info: How to ensure, that the first 5 bits in
-        reserver0 are not set. How to enforce version == 0 (that is, make version() read-only and
-        return no_factory for the next packet type if any of the conditions is violated)
+    #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 (1) {
+            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 (1) {
+            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 'Show all members' 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.
+
+    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)
+
  */
 
 \f
index 9926efc..328db04 100644 (file)
@@ -60,24 +60,18 @@ prefix_ void senf::EthernetPacketType::dump(packet p, std::ostream & os)
 
 prefix_ senf::PacketInterpreterBase::factory_t senf::EthernetPacketType::nextPacketType(packet p)
 {
-    if (p->type_length() >= 1536) {
-        PkReg_Entry const * e;
-        e = PacketRegistry<senf::EtherTypes>::lookup( p->type_length(), nothrow );
-        return e ? e->factory() : no_factory();
-    }
-    if (p->type_length() <= 1500)
-        return LlcSnapPacket::factory();
-    return no_factory();
+    if      (p->type_length() >= 1536) return lookup(p->type_length());
+    else if (p->type_length() <= 1500) return LlcSnapPacket::factory();
+    else                               return no_factory();
 }
 
 prefix_ void senf::EthernetPacketType::finalize(packet p)
 {
-    optional_registry_key_t k = key(p.next(nothrow));
+    optional_key_t k (key(p.next(nothrow)));
     if (k)
         p->type_length() << k;
-    else
-        if (p.next().is<LlcSnapPacket>())
-            p->type_length() << p.next().data().size();
+    else if (p.next().is<LlcSnapPacket>())
+        p->type_length() << p.next().data().size();
     // Do NOT reset type_length if the type is not known ... doing this will destroy read packets
 }
 
index 6991f9d..ad9c1f9 100644 (file)
@@ -177,7 +177,7 @@ namespace senf {
 
         /** \todo Add LLC/SNAP support -> only use the registry
             for type() values >=1536, otherwise expect an LLC header */
-        static registry_key_t nextPacketKey(packet p) 
+        static key_t nextPacketKey(packet p) 
             { return p->type(); }
 
         static void dump(packet p, std::ostream & os);
index 1a27b27..3da21e0 100644 (file)
@@ -174,7 +174,7 @@ namespace senf {
         using mixin::initSize;
         using mixin::init;
 
-        static registry_key_t nextPacketKey(packet p) 
+        static key_t nextPacketKey(packet p) 
             { return p->protocol(); }
 
         static void dump(packet p, std::ostream & os);
index 7f1bcbc..54b18e1 100644 (file)
@@ -87,7 +87,7 @@ namespace senf {
         using mixin::initSize;
         using mixin::init;
 
-        static registry_key_t nextPacketKey(packet p) 
+        static key_t nextPacketKey(packet p) 
             { return p->nextHeader(); }
         
         static void dump(packet p, std::ostream & os);
index 05ce061..935bcea 100644 (file)
@@ -114,7 +114,7 @@ namespace senf {
         using mixin::initSize;
         using mixin::init;
 
-        static registry_key_t nextPacketKey(packet p) 
+        static key_t nextPacketKey(packet p) 
             { return p->nextHeader(); }
         
         static void dump(packet p, std::ostream & os);
index 99461bb..d6ced6a 100644 (file)
@@ -61,14 +61,14 @@ prefix_ senf::PacketInterpreterBase::factory_t senf::LlcSnapPacketType::nextPack
 
 prefix_ void senf::LlcSnapPacketType::finalize(packet p)
 {
-    optional_registry_key_t k = key(p.next(nothrow));
+    optional_key_t k (key(p.next(nothrow)));
     if (k)
         p->type_length() << k;
+    else if (p.next().is<EthernetPacket>())
+        p->type_length() << p.next().data().size();
     else
-        if (p.next().is<EthernetPacket>())
-            p->type_length() << p.next().data().size();
-        else
-            p->type_length() << 0;
+        ///\fixme Is this correct ??
+        p->type_length() << 0;
 }
 
 
index b969752..58dfda8 100644 (file)
@@ -50,7 +50,7 @@ prefix_ boost::uint32_t senf::SNDUPacketParser::calcCrc()
             ule_crc32() ).checksum();
 }
 
-//prefix_ senf::SNDUPacketType::registry_key_t senf::SNDUPacketType::nextPacketKey(packet p)
+//prefix_ senf::SNDUPacketType::key_t senf::SNDUPacketType::nextPacketKey(packet p)
 //{
 //    return p->type(); 
 //}
index 2ac0c9f..34e83b8 100644 (file)
@@ -103,7 +103,7 @@ namespace senf {
 //        using mixin::nextPacketType;
 //        using mixin::init;
         
-//        static registry_key_t nextPacketKey(packet p);
+//        static key_t nextPacketKey(packet p);
         
         static void init(packet p);
 
index e79f172..fe949cb 100644 (file)
@@ -93,7 +93,7 @@ namespace {
             else
                 p->type() = -1;
         }
-        static registry_key_t nextPacketKey(packet p) {
+        static key_t nextPacketKey(packet p) {
             return p->type();
         }
     };
index 9266ce8..8449145 100644 (file)
@@ -39,6 +39,13 @@ prefix_ senf::PacketParserBase::data_iterator senf::PacketParserBase::i()
     return i_;
 }
 
+prefix_ data_iterator senf::PacketParserBase::i(size_type offset)
+    const
+{
+    validate(offset);
+    return boost::next(i_, offset);
+}
+
 prefix_ senf::PacketParserBase::state_type senf::PacketParserBase::state()
     const
 {
index a00da0d..5248296 100644 (file)
@@ -264,10 +264,23 @@ namespace senf {
                                              here. The size of the interpreted is given by
                                              <tt>senf::bytes(</tt><em>parser
                                              instance</em><tt>)</tt>. */
+
+        data_iterator i(size_type offset) const; ///< Return iterator \a offset bytes from the start
+                                        /**< The return value is the same as i() + \a
+                                             offset. However, the parser checks, that the iterator is
+                                             still within range of the raw data
+                                             container. Otherwise a TruncatedPacketException is
+                                             thrown. 
+                                             
+                                             \throws TruncatedPacketException if the raw data
+                                                 container does not hold at least \a offset bytes
+                                                 starting at i(). */
+
         state_type state() const;       ///< Return state of this parser
                                         /**< The value returned should be interpreted as an opaque
                                              value provided just to be forwarded to other
                                              parsers. */
+
         PacketData & data() const;      ///< Access the packets raw data container
                                         /**< This member will return the raw data container holding
                                              the data which is parsed by \c this parser. */
@@ -282,6 +295,7 @@ namespace senf {
                                         /**< This is the constructor used by most parsers. The
                                              parameters are just forwarded from the derived classes
                                              constructor parameters. */
+
         PacketParserBase(data_iterator i, state_type s, size_type size); 
                                         ///< Size checking constructor
                                         /**< In addition to the standard constructor, this
@@ -303,6 +317,7 @@ namespace senf {
         bool check(size_type size) const; ///< Check size of data container
                                         /**< \returns \c true, if the data container holds at least
                                              \a size beginning at i(), \c false otherwise. */
+
         void validate(size_type size) const; ///< Validate size of data container
                                         /**< \throws TruncatedPacketException if the raw data
                                              container does not hold at least \a size bytes
@@ -312,6 +327,7 @@ namespace senf {
                                         /**< Creates a new instance of \a Parser to parse data
                                              beginning at \a i. Automatically passes \a state() to
                                              the new parser. */
+
         template <class Parser> Parser parse(size_type n) const; ///< Create sub-parser
                                         /**< Creates a new instance of \a Parser to parse data
                                          * beginning at i()<tt> + </tt>\a n. Automatically passes \a
index 843e83a..34f15dc 100644 (file)
@@ -58,9 +58,7 @@ senf::PacketTypeMixin<Self,Registry>::nextPacketType(Packet p)
 {
     if (p.data().size() < Self::initSize())
         return Self::no_factory();
-    PkReg_Entry const * e (PacketRegistry<Registry>::lookup( 
-                               Self::nextPacketKey(p.as< ConcretePacket<Self> >()), nothrow));
-    return e ? e->factory() : PacketTypeBase::no_factory();
+    return lookup( Self::nextPacketKey(p.as< ConcretePacket<Self> >()) );
 }
 
 template <class Self, class Registry>
@@ -76,10 +74,17 @@ prefix_ void senf::PacketTypeMixin<Self,Registry>::init(Packet p)
 }
 
 template <class Self, class Registry>
-prefix_ typename senf::PacketTypeMixin<Self,Registry>::optional_registry_key_t
+prefix_ typename senf::PacketTypeMixin<Self,Registry>::optional_key_t
 senf::PacketTypeMixin<Self,Registry>::key(Packet p)
 {
-    return p ? PacketRegistry<Registry>::key(p, nothrow) : optional_registry_key_t();
+    return p ? PacketRegistry<Registry>::key(p, nothrow) : optional_key_t();
+}
+
+template <class Self, class Registry>
+prefix_ senf::PacketTypeBase::factory_t senf::PacketTypeMixin<Self,Registry>::lookup(key_t key)
+{
+    PkReg_Entry const * entry (PacketRegistry<Registry>::lookup( key, senf::nothrow ));
+    return entry ? entry->factory() : PacketTypeBase::no_factory();
 }
 
 ///////////////////////////////////////////////////////////////////////////
index e23ef09..e9d0d30 100644 (file)
@@ -263,7 +263,7 @@ namespace senf {
                 // member.
             }
 
-            static registry_key_t nextPacketKey(packet p)
+            static key_t nextPacketKey(packet p)
             {
                 // Return the key in the registry under which the next packet
                 // header is to be found. This member must be given if a Registry argument is
@@ -306,7 +306,7 @@ namespace senf {
             using mixin::initSize;
             using mixin::init;         
 
-            static registry_key_t nextPacketKey(packet p)
+            static key_t nextPacketKey(packet p)
             { return p->typeField(); }
         };
         \endcode
@@ -320,10 +320,10 @@ namespace senf {
     class PacketTypeMixin
     {
     public:
-        typedef typename Registry::key_t registry_key_t;
-        typedef boost::optional<registry_key_t> optional_registry_key_t;
+        typedef typename Registry::key_t key_t;
+        typedef boost::optional<key_t> optional_key_t;
 
-        static optional_registry_key_t key (Packet p); ///< Find key of packet from registry
+        static optional_key_t key (Packet p); ///< Find key of packet from registry
                                         /**< key() will query the registry to find the key of the
                                              given packet. Whereas \c nextPacketKey() as implemented
                                              by the mixin user will provide the registry key of the
@@ -336,6 +336,11 @@ namespace senf {
                                              type is not found in the registry, the returned
                                              optional value will be empty. */
 
+        static PacketTypeBase::factory_t lookup (key_t key); ///< Lookup the key in the registry
+                                        /**< lookup() will query the registry and find the factory
+                                             for the given key. If the key cannot be found,
+                                             no_factory() will be returned. */
+
         ///\name PacketType interface implementation
         ///@{
 
index 8a155b1..ec75335 100644 (file)
--- a/senf.dict
+++ b/senf.dict
@@ -12,11 +12,16 @@ ActiveSource
 addr
 AddressingPolicy
 AddressingPolicyBase
+AddressParser
 addtogroup
 aListCollection
 alloc
+API
+API's
 arg
+argc
 args
+argv
 async
 Augustin
 autoThrottling
@@ -36,6 +41,7 @@ cc
 cd
 cerr
 cfi
+checksumEnabled
 checksumPresent
 CIDR
 ClientSocketHandle
@@ -46,6 +52,7 @@ ConcretePacket
 conf
 CONFIG
 ConnectedCommunicationPolicy
+ConnectedRawV
 ConnectedUDPv
 const
 createAfter
@@ -55,6 +62,7 @@ DataPacket
 dd
 de
 DebugModules
+decapsulated
 DefaultArea
 DefaultBundle
 defaultInit
@@ -71,6 +79,7 @@ dt
 ElementParser
 enableChecksum
 endcode
+endif
 enum
 eof
 EPIPE
@@ -114,10 +123,11 @@ ForwardingRoute
 fraunhofer
 FroblizerArea
 GlobalScope
-GRE
+gre
 GREPacket
 GREPacketParser
 GREPacketType
+GREPackeType
 GREParser
 hangup
 HangupException
@@ -128,13 +138,16 @@ hostname
 hostnames
 howto
 HowTo
+hpp
 href
 htm
 html
 http
 iana
+ias
 IdleEvent
 ietf
+ifndef
 ih
 impl
 INet
@@ -146,17 +159,23 @@ inline
 InputConnector
 inputSocket
 Institut
-Int
+int
 IntervalTimer
 IntField
 InvalidPacketChainException
+io
 IOEvent
 IOEventInfo
+ios
+iostream
 ip
+IpChecksum
 IpTypes
 IpV
 ipv
+IPv
 IPX
+isock
 iterator
 join
 key
@@ -171,6 +190,7 @@ localhost
 loopback
 mac
 MACAddress
+MACAddressParser
 mainpage
 mixin
 MPEGDVBBundle
@@ -204,6 +224,7 @@ OptFields
 optionalFields
 org
 os
+osock
 ostream
 OtherPacket
 OtherPacketType
@@ -266,6 +287,8 @@ rateFilter
 ratefilter
 RateStuffer
 ratestuffer
+RawINetProtocol
+RawV
 refcount
 registerEvent
 registerPacket
@@ -287,12 +310,15 @@ senf
 ServerSocketHandle
 setBegin
 setEnd
+setfill
 setFromPosition
+setw
 SimplePacketType
 SimpleVectorSizer
 SiteScope
 SizeParser
 skipline
+SocketAddress
 SocketHandle
 SocketProtocol
 SomeEvent
@@ -316,6 +342,7 @@ struct
 structors
 SyntaxException
 SystemException
+TapSocketHandle
 td
 templated
 ThresholdQueueing
@@ -325,6 +352,7 @@ tr
 TruncatedPacketException
 tt
 ttl
+TunTapSocketHandle
 TypeA
 TypeB
 typeField
@@ -341,6 +369,7 @@ unthrottle
 unthrottled
 unthrottles
 unthrottling
+Utils
 VectorN
 Ver
 vlanId