Howtos/NewPacket: Reformat 'Further reading' list
g0dil [Mon, 28 Jan 2008 13:38:42 +0000 (13:38 +0000)]
doclib: Fix some senf.css / doxygen.css interactions
Packets: Implement ConcreatePacket::parser
Packets: Make the PacketTypeMixin work with (simple) dynamically sized parsers

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

HowTos/NewPacket/Mainpage.dox
Packets/Packet.cti
Packets/Packet.hh
Packets/Packet.test.cc
Packets/PacketType.ct
Packets/PacketType.hh
doclib/senf.css

index 1395147..a932cb8 100644 (file)
         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>
 
  */
 
index 5f67ccb..6331b1c 100644 (file)
@@ -248,13 +248,21 @@ senf::ConcretePacket<PacketType>::clone()
 // 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>
index 33f6317..996e2c1 100644 (file)
@@ -569,6 +569,13 @@ namespace senf {
                                              / 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:
index fe949cb..90d383b 100644 (file)
@@ -49,9 +49,15 @@ namespace {
         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;
 
@@ -63,6 +69,10 @@ namespace {
         SENF_PARSER_FIELD( length,   senf::Int32Parser  );
         SENF_PARSER_FIELD( reserved, senf::UInt16Parser );
 
+        SENF_PARSER_INIT() {
+            reserved() << 0xA0A0u;
+        }
+
         SENF_PARSER_FINALIZE(BarPacketParser);
     };
 
@@ -77,11 +87,6 @@ namespace {
         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"
@@ -117,6 +122,10 @@ BOOST_AUTO_UNIT_TEST(packet)
     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>() );
index d3cc085..5443c1d 100644 (file)
@@ -43,9 +43,16 @@ senf::PacketTypeMixin<Self,void>::nextPacketRange(Packet p)
     ///\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));
 }
index e9d0d30..c23db1e 100644 (file)
@@ -216,11 +216,16 @@ namespace senf {
 
     /** \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 
@@ -232,36 +237,9 @@ namespace senf {
             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)
             {
@@ -286,11 +264,18 @@ namespace senf {
             {
                 // 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 
@@ -304,16 +289,20 @@ namespace senf {
             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>
index be87f66..1e4697d 100644 (file)
@@ -5,6 +5,11 @@ body {
         font-size: 10pt;
 }
 
+/* Argh .. doxygen.css has font-size:90% for td ... */
+td {
+        font-size: 100%;
+}
+
 #head {
         height: 62px;
         border-top: 5px solid #DECD40;
@@ -290,12 +295,15 @@ table.senf th {
         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 {
@@ -315,7 +323,6 @@ table.listing {
         padding: 0;
         border-spacing: 0;
         border: none;
-        font-size: 120%; /* ????????  Why is THIS needed ?? */
 }
 
 table.listing td {