Packets: Allow packet parsers to access the packet chain
g0dil [Mon, 8 Oct 2007 13:23:45 +0000 (13:23 +0000)]
Packets/DefaultBundle: Implement IpV6Packet, IpV6Extensions and UDPPacket's finalize()

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

13 files changed:
Packets/DefaultBundle/IpV4Packet.cc
Packets/DefaultBundle/IpV6Extensions.hh
Packets/DefaultBundle/IpV6Packet.cc
Packets/DefaultBundle/IpV6Packet.hh
Packets/DefaultBundle/UDPPacket.cc
Packets/DefaultBundle/UDPPacket.hh
Packets/DefaultBundle/UDPPacket.test.cc
Packets/Packet.hh
Packets/PacketInterpreter.hh
Packets/PacketParser.cci
Packets/PacketParser.cti
Packets/PacketParser.hh
Packets/PacketType.hh

index 8c55752..ec35159 100644 (file)
@@ -52,6 +52,7 @@ namespace {
 prefix_ boost::uint16_t senf::Parse_IpV4::calcChecksum()
     const
 {
+    validate(bytes(*this));
     IpChecksum summer;
     summer.feed( i(),                   i()+checksum_offset );
     // Not needed since the number of 0-bytes is even
index a0bd5b0..37e74c7 100644 (file)
@@ -101,6 +101,9 @@ namespace senf {
             { return p->nextHeader(); }
         
         static void dump(packet p, std::ostream & os);
+
+        static void finalize(packet p)
+            { p->nextHeader() << key(p.next()); }
     };
 
     /** \brief IpV6 fragment extension packet typedef */
index 2cf67b2..e96eaec 100644 (file)
@@ -25,6 +25,7 @@
 //#include "IpV6Packet.ih"
 
 // Custom includes
+#include <iomanip>
 #include <boost/io/ios_state.hpp>
 #include "EthernetPacket.hh"
 #include "../../Socket/Protocols/INet/INetAddressing.hh"
@@ -48,14 +49,22 @@ prefix_ void senf::IpV6PacketType::dump(packet p, std::ostream & os)
 {
     boost::io::ios_all_saver ias(os);
     os << "Internet protocol Version 6:\n"
-       << "  version       : " << unsigned(p->version()) << "\n"
-       << "  traffic class : " << std::hex << unsigned(p->trafficClass()) << "\n"
-       << "  flow label    : " << std::hex << unsigned(p->flowLabel()) << "\n"
-       << "  length        : " << std::dec << unsigned(p->length()) << "\n"
-       << "  next header   : " << unsigned(p->nextHeader()) << "\n"
-       << "  hop limit     : " << unsigned(p->hopLimit()) << "\n"
-       << "  source        : " << p->source() << "\n"
-       << "  destination   : " << p->destination() << "\n";
+       << "  version        : " << unsigned(p->version()) << "\n"
+       << "  traffic class  : 0x" 
+         << std::hex << std::setw(2) << std::setfill('0') << unsigned(p->trafficClass()) << "\n"
+       << "  flow label     : 0x" 
+         << std::hex << std::setw(5) << std::setfill('0') << unsigned(p->flowLabel()) << "\n"
+       << "  payload length : " << std::dec << unsigned(p->length()) << "\n"
+       << "  next header    : " << unsigned(p->nextHeader()) << "\n"
+       << "  hop limit      : " << unsigned(p->hopLimit()) << "\n"
+       << "  source         : " << p->source() << "\n"
+       << "  destination    : " << p->destination() << "\n";
+}
+
+prefix_ void senf::IpV6PacketType::finalize(packet p)
+{
+    p->length() << (p.size() - Parse_IpV6::fixed_bytes);
+    p->nextHeader() << key(p.next());
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index f64652d..94a8799 100644 (file)
@@ -131,6 +131,8 @@ namespace senf {
             { return p->nextHeader(); }
         
         static void dump(packet p, std::ostream & os);
+
+        static void finalize(packet p);
     };
 
     /** \brief IpV6 packet typedef */
index 5cf1f43..7ae0079 100644 (file)
 #include "IpV4Packet.hh"
 
 // Custom includes
+#include <iomanip>
+#include <boost/io/ios_state.hpp>
 #include "../../Packets/Packets.hh"
+#include "../../Utils/IpChecksum.hh"
+#include "IpV4Packet.hh"
+#include "IpV6Packet.hh"
 
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
@@ -38,13 +43,73 @@ namespace {
         registerUDPPacket (17);
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_UDP
+
+prefix_ boost::uint16_t senf::Parse_UDP::calcChecksum()
+    const
+{
+    IpChecksum summer;
+    summer.feed( i(), i()+checksum_offset );
+    summer.feed( i()+checksum_offset+2, data().end() );
+    
+    // Now on to the awkward part: the IP pseudo header
+    IpV4Packet ipv4 (packet().prev<IpV4Packet>(nothrow));
+    if (ipv4) {
+        // Pseudo header defined in RFC768
+        summer.feed( ipv4->source().i(), 
+                     ipv4->source().i() + Parse_IpV4::source_t::fixed_bytes );
+        ///\fixme What about a hop-by-hop routing option? Which destination is used in IpV4 ?
+        summer.feed( ipv4->destination().i(), 
+                     ipv4->destination().i() + Parse_IpV4::destination_t::fixed_bytes );
+        summer.feed( 0u );
+        ///\fixme May there be another header between the IpV4 header and UDP? if so, we
+        /// need to hack the correct protocol number here ...
+        summer.feed( 17u );
+        summer.feed( i() + length_offset, i() + length_offset + 2 );
+    } 
+    else {
+        // Pseudo header defined in RFC2460
+        IpV6Packet ipv6 (packet().prev<IpV6Packet>(nothrow));
+        if (ipv6) {
+            summer.feed( ipv6->source().i(), 
+                         ipv6->source().i() + Parse_IpV6::source_t::fixed_bytes );
+            ///\todo Implement routing header support
+            // The destination used here must be the *final* destination ...
+            summer.feed( ipv6->destination().i(), 
+                         ipv6->destination().i() + Parse_IpV6::destination_t::fixed_bytes );
+            /// This is a simplification. The value is really 32bit to support UDP Jumbograms
+            /// (RFC2147). However, skipping an even number of 0 bytes does not change the checksum
+            summer.feed( i() + length_offset, i() + length_offset + 2 );
+            // RFC2460 specifies, that this must always be 17, not the value used in the ipv6
+            // header
+            summer.feed( 0u );
+            summer.feed( 17u );
+        }
+    }
+    
+    boost::uint16_t rv (summer.sum());
+    return rv ? rv : 0xffffu;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::UDPPacketType
+
 prefix_ void senf::UDPPacketType::dump(packet p, std::ostream & os)
 {
+    boost::io::ios_all_saver ias(os);
     os << "UDP:\n"
        << "  source port   : " << p->source() << "\n"
        << "  dest port     : " << p->destination() << "\n"
        << "  length        : " << p->length() << "\n"
-       << "  crc           : " << std::hex << p->crc() << std::dec << "\n";
+       << "  checksum      : " 
+         << std::hex << std::setw(4) << std::setfill('0') << p->checksum() << "\n";
+}
+
+prefix_ void senf::UDPPacketType::finalize(packet p)
+{
+    p->length() << p.size();
+    p->checksum() << p->calcChecksum();
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index e42bbc4..1e566a1 100644 (file)
@@ -53,16 +53,21 @@ namespace senf {
             ((Field)( source,      Parse_16bit ))
             ((Field)( destination, Parse_16bit ))
             ((Field)( length,      Parse_16bit ))
-            ((Field)( crc,         Parse_16bit )) );
+            ((Field)( checksum,    Parse_16bit )) );
 
 #       else
 
         Parse_16bit source();
         Parse_16bit destination();
         Parse_16bit length();
-        Parse_16bit crc();
+        Parse_16bit checksum();
 
 #       endif
+
+        boost::uint16_t calcChecksum() const;
+        bool validateChecksum() const {
+            return checksum() == 0u || checksum() == calcChecksum();
+        }
     };
 
     /** \brief UDP packet
@@ -88,6 +93,8 @@ namespace senf {
         using mixin::init;
 
         static void dump(packet p, std::ostream & os);
+
+        static void finalize(packet p);
     };
 
     /** \brief UDP packet typedef */
index 347d5ac..d9d84c3 100644 (file)
@@ -27,6 +27,7 @@
 
 // Custom includes
 #include "UDPPacket.hh"
+#include "IpV4Packet.hh"
 
 #include <boost/test/auto_unit_test.hpp>
 #include <boost/test/test_tools.hpp>
@@ -46,10 +47,37 @@ BOOST_AUTO_UNIT_TEST(udpPacket_packet)
     BOOST_CHECK_EQUAL( p->source(),            0x0102       );
     BOOST_CHECK_EQUAL( p->destination(),       0x0304       );
     BOOST_CHECK_EQUAL( p->length(),            0x0506       );
-    BOOST_CHECK_EQUAL( p->crc(),               0x0708       );
-
+    BOOST_CHECK_EQUAL( p->checksum(),          0x0708       );
 }
 
+BOOST_AUTO_UNIT_TEST(udpPacket_create)
+{
+    unsigned char data[] = { 0x45, 0x00, 0x00, 0x26, 0x00, 0x00, 0x40, 0x00,
+                             0x40, 0x11, 0x3c, 0xc5, 0x7f, 0x00, 0x00, 0x01,
+                             0x7f, 0x00, 0x00, 0x01, 0x5b, 0xa0, 0x30, 0x39,
+                             0x00, 0x12, 0xfa, 0x6e, 0x54, 0x45, 0x53, 0x54,
+                             0x2d, 0x57, 0x52, 0x49, 0x54, 0x45 };
+
+    senf::IpV4Packet ip (senf::IpV4Packet::create());
+    ip->source() = senf::INet4Address::Loopback;
+    ip->destination() = senf::INet4Address::Loopback;
+    ip->df() = true;
+    ip->ttl() = 64;
+    
+    senf::UDPPacket udp (senf::UDPPacket::createAfter(ip));
+    udp->source() = 23456;
+    udp->destination() = 12345;
+    
+    senf::DataPacket::createAfter(udp,std::string("TEST-WRITE"));
+
+    // validates, since the checksum is 0 and thus ignored !
+    BOOST_CHECK( udp->validateChecksum() );
+
+    ip.finalize();
+    BOOST_CHECK_EQUAL_COLLECTIONS( data, data+sizeof(data),
+                                   ip.data().begin(), ip.data().end() );
+    BOOST_CHECK( udp->validateChecksum() );
+}
 
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 206b8c8..59f7d56 100644 (file)
@@ -384,6 +384,7 @@ namespace senf {
         
         template <class PacketType>
         friend class ConcretePacket;
+        friend class PacketParserBase;
     };
 
     /** \brief Protocol specific packet handle
index 927d0ff..fe1b27a 100644 (file)
@@ -212,6 +212,7 @@ namespace senf {
         friend class intrusive_refcount_t<PacketInterpreterBase>;
         template <class PacketType> friend class PacketInterpreter;
         friend class detail::packet::test::TestDriver;
+        friend class PacketParserBase;
     };
 
     /** \brief Internal: Concrete packet interpreter
index 173e54e..ca79628 100644 (file)
@@ -53,6 +53,19 @@ prefix_ void senf::PacketParserBase::init()
     const
 {}
 
+prefix_ void senf::PacketParserBase::defaultInit()
+    const
+{}
+
+prefix_ senf::Packet senf::PacketParserBase::packet()
+    const
+{
+    // OUCH ... I hate this but for some awkward packet types, access to the packet
+    // from the parser is really needed (e.g. UDP when building the pseudo-header
+    // for calculating the checksum).
+    return Packet(PacketInterpreterBase::ptr(static_cast<PacketInterpreterBase*>(&data())));
+}
+
 ////////////////////////////////////////
 // protected members
 
@@ -68,11 +81,13 @@ prefix_ senf::PacketParserBase::PacketParserBase(data_iterator i, state_type s,
 }
 
 prefix_ bool senf::PacketParserBase::check(size_type size)
+    const
 {
     return size <= size_type(std::distance(i(),end()));
 }
 
 prefix_ void senf::PacketParserBase::validate(size_type size)
+    const
 {
     if (! check(size))
         throw TruncatedPacketException();
@@ -82,6 +97,7 @@ prefix_ void senf::PacketParserBase::validate(size_type size)
 // private members
 
 prefix_ senf::PacketParserBase::data_iterator senf::PacketParserBase::end()
+    const
 {
     return data_->end();
 }
index 28b71c2..5d27c62 100644 (file)
@@ -46,10 +46,6 @@ prefix_ Parser senf::PacketParserBase::parse(size_type n)
     return Parser(boost::next(i(),n),state());
 }
 
-prefix_ void senf::PacketParserBase::defaultInit()
-    const
-{}
-
 ///////////////////////////////////////////////////////////////////////////
 // namespace members
 
index c6a38e8..76b8252 100644 (file)
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
+
+    class Packet;
     
     /** \brief Parser Base class
 
@@ -292,10 +294,10 @@ namespace senf {
                                                  container does not hold at least \a size bytes
                                                  beginning at \a i. */
 
-        bool check(size_type size);     ///< Check size of data container
+        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);  ///< Validate size of data container
+        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
                                              beginning at i(). */
@@ -314,8 +316,13 @@ namespace senf {
                                              implementation. Re-implement this member in your own
                                              parsers if needed. */
 
+        Packet packet() const;          ///< Get packet this parser is parsing from
+                                        /**< \important This member should only be used from packet
+                                             parsers when access to previous or following packets is
+                                             needed e.g. for calculating checksums etc. */
+
     private:
-        data_iterator end();
+        data_iterator end() const;
 
         data_iterator i_;
         PacketData * data_;
index 53c17c1..88768f2 100644 (file)
@@ -334,8 +334,8 @@ namespace senf {
                                              type is not found in the registry, the returned
                                              optional value will be empty. */
 
-        ///@{
         ///\name PacketType interface implementation
+        ///@{
 
         static PacketInterpreterBase::optional_range nextPacketRange (Packet p);
         static PacketInterpreterBase::factory_t      nextPacketType  (Packet p);