Add additional IpTypes for Ip-in-IP etc.
g0dil [Tue, 20 Feb 2007 08:59:31 +0000 (08:59 +0000)]
Implemented IPv6 fragment extension
Add output streaming (operator<<) for ParseInt parsers

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

Packets/IpV4Packet.cc
Packets/IpV6Extensions.cc [new file with mode: 0644]
Packets/IpV6Extensions.ct [new file with mode: 0644]
Packets/IpV6Extensions.hh [new file with mode: 0644]
Packets/IpV6Extensions.test.cc [new file with mode: 0644]
Packets/IpV6Packet.cc
Packets/IpV6Packet.hh
Packets/IpV6Packet.test.cc
Packets/ParseInt.hh
Packets/UDPPacket.cc
Packets/UDPPacket.hh

index fd04025..46b925c 100644 (file)
 
 namespace {
     senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::IpV4Packet> 
-        registerIpV4Packet(0x0800);
+        registerIpV4Packet (0x0800);
+
+    senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV4Packet>
+        regsiterIpV4Packet2 (4); // IP-in-IP encapsulation
 }
 
 prefix_ void senf::IpV4Packet::v_nextInterpreter()
diff --git a/Packets/IpV6Extensions.cc b/Packets/IpV6Extensions.cc
new file mode 100644 (file)
index 0000000..30f4dd4
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief IpV6Extensions non-inline non-template implementation */
+
+#include "IpV6Extensions.hh"
+//#include "IpV6Extensions.ih"
+
+// Custom includes
+
+//#include "IpV6Extensions.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+    senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV6Extension_Fragment>
+        registerIpV6Extension_Fragment (44);
+}
+
+prefix_ void senf::IpV6Extension_Fragment::v_nextInterpreter()
+    const
+{
+    registerInterpreter(nextHeader(),begin()+bytes(),end());
+}
+
+prefix_ void senf::IpV6Extension_Fragment::v_finalize()
+{}
+
+prefix_ void senf::IpV6Extension_Fragment::v_dump(std::ostream & os)
+    const
+{
+    os << "Internet protocol Version 6 fragment extension:\n"
+       << "  next header    : " << unsigned(nextHeader()) << "\n"
+       << "  fragment offset: " << std::hex << unsigned(fragmentOffset()) << "\n"
+       << "  more fragments : " << (moreFragments()?"yes":"no") << "\n"
+       << "  id             : " << std::hex << unsigned(id()) << "\n";
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "IpV6Extensions.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// ispell-local-dictionary: "american"
+// End:
diff --git a/Packets/IpV6Extensions.ct b/Packets/IpV6Extensions.ct
new file mode 100644 (file)
index 0000000..1f0873e
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief IpV6Extensions non-inline template implementation  */
+
+//#include "IpV6Extensions.ih"
+
+// Custom includes
+
+#define prefix_
+///////////////////////////////ct.p////////////////////////////////////////
+
+template <class Arg>
+prefix_ senf::IpV6Extension_Fragment::IpV6Extension_Fragment(Arg const & arg)
+    : Packet(arg)
+{}
+
+///////////////////////////////ct.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// ispell-local-dictionary: "american"
+// End:
diff --git a/Packets/IpV6Extensions.hh b/Packets/IpV6Extensions.hh
new file mode 100644 (file)
index 0000000..cc6581a
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief IpV6Extensions public header */
+
+#ifndef HH_IpV6Extensions_
+#define HH_IpV6Extensions_ 1
+
+// Custom includes
+#include "IpV6Packet.hh"
+
+//#include "IpV6Extensions.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+    // See RFC2460
+    template <class Iterator=nil, class IPacket=nil>
+    struct Parse_IpV6Extension_Fragment
+       : public ParserBase<Iterator,IPacket>
+    {
+        template <class I, class P=nil>
+        struct rebind { typedef Parse_IpV6Extension_Fragment<I,P> parser; };
+        typedef Iterator byte_iterator;
+
+        Parse_IpV6Extension_Fragment() {}
+        Parse_IpV6Extension_Fragment(Iterator const & i) : ParserBase<Iterator,IPacket>(i) {}
+
+        static unsigned bytes() { return 8; }
+        
+        ///////////////////////////////////////////////////////////////////////////
+
+       typedef Parse_UInt8     <         Iterator > Parse_8bit;
+       typedef Parse_UIntField <  0, 13, Iterator > Parse_Offset;
+       typedef Parse_UIntField < 13, 15, Iterator > Parse_Reserved;
+       typedef Parse_Flag      < 15,     Iterator > Parse_More;
+       typedef Parse_UInt32    <         Iterator > Parse_32bit;
+
+       Parse_8bit      nextHeader()      const { return Parse_8bit      (this->i()      ); }
+       Parse_8bit      reserved1()       const { return Parse_8bit      (this->i() +  1 ); }
+       Parse_Offset    fragmentOffset()  const { return Parse_Offset    (this->i() +  2 ); }
+       Parse_Reserved  reserved2()       const { return Parse_Reserved  (this->i() +  2 ); }
+       Parse_More      moreFragments()   const { return Parse_More      (this->i() +  2 ); }
+       Parse_32bit     id()              const { return Parse_32bit     (this->i() +  4 ); }
+    };
+
+    class IpV6Extension_Fragment
+       : public Packet,
+         public Parse_IpV6Extension_Fragment<Packet::iterator, IpV6Extension_Fragment>,
+         public PacketRegistryMixin<IpTypes, IpV6Extension_Fragment>
+    {
+       using PacketRegistryMixin<IpTypes,IpV6Extension_Fragment>::registerInterpreter;
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef ptr_t<IpV6Extension_Fragment>::ptr ptr;
+
+        ///////////////////////////////////////////////////////////////////////////
+
+    private:
+        template <class Arg>
+        IpV6Extension_Fragment(Arg const & arg);
+
+        virtual void v_nextInterpreter() const;
+        virtual void v_finalize();
+        virtual void v_dump(std::ostream & os) const;
+
+        friend class Packet;
+    };
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "IpV6Extensions.cci"
+#include "IpV6Extensions.ct"
+//#include "IpV6Extensions.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// ispell-local-dictionary: "american"
+// End:
diff --git a/Packets/IpV6Extensions.test.cc b/Packets/IpV6Extensions.test.cc
new file mode 100644 (file)
index 0000000..1d56ee2
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief IpV6Extensions.test unit tests */
+
+//#include "IpV6Extensions.test.hh"
+//#include "IpV6Extensions.test.ih"
+
+// Custom includes
+#include "IpV6Extensions.hh"
+#include "IpV6Packet.hh"
+#include "UDPPacket.hh"
+#include "DataPacket.hh"
+#include "Socket/INetAddressing.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+using namespace senf;
+
+BOOST_AUTO_UNIT_TEST(ipv6Extension_Fragment_parser)
+{
+    unsigned char data[] = { 59, 0, 0x10, 0x20,
+                            0x01, 0x02, 0x03, 0x04 };
+
+    typedef unsigned char * iterator;
+    Parse_IpV6Extension_Fragment<iterator> p (data);
+
+    BOOST_CHECK_EQUAL( unsigned(p.nextHeader()), 59u );
+    BOOST_CHECK_EQUAL( unsigned(p.fragmentOffset()), 0x1020u >> 3 );
+    BOOST_CHECK ( ! p.moreFragments() );
+    BOOST_CHECK_EQUAL( unsigned(p.id()), 0x01020304u );
+}
+
+BOOST_AUTO_UNIT_TEST(ipv6Extension_Fragment_packet)
+{
+    // Just for the fun of it, we test a nice chain: A fragment of a fragmented UDP packet
+    
+    unsigned char data[] = { 
+       // IP header
+       0x60, 0x00, 0x00, 0x00,         // IP Version, class, flow label
+       0, 20,                          // payload length
+       44,                             // next header (IPv6 Fragment)
+       32,                             // hop limit
+       0x20, 0x01, 0, 0, 0, 0, 0, 0,   // source ip = 2001::1
+          0, 0, 0, 0, 0, 0, 0, 0x01,
+       0x20, 0x01, 0, 0, 0, 0, 0, 0,   // destination ip = 2001::2
+          0, 0, 0, 0, 0, 0, 0, 0x02,
+       // IPv6 Fragment header
+       17,                             // next header (UDP)
+       0,                              // reserved
+       0x05, 0x00,                     // fragment offset, last fragment
+       0x01, 0x02, 0x03, 0x04,         // id
+       // UDP header
+       0x10, 0x00,                     // source port
+       0x20, 0x00,                     // destination port
+       0, 12,                          // length
+       0x00, 0x00,                     // CRC (no, I won't calculate this one ...)
+       // Payload data
+       0x11, 0x12, 0x13, 0x14
+    };
+
+    IpV6Packet::ptr p (Packet::create<IpV6Packet>(data, data + sizeof(data)));
+    
+    BOOST_CHECK_EQUAL( p->version(), 6u );
+    BOOST_CHECK_EQUAL( p->length(), 20u );
+    BOOST_CHECK_EQUAL( p->nextHeader(), 44u );
+    BOOST_CHECK_EQUAL( INet6Address(p->source().range()), "2001::1" );
+    BOOST_CHECK_EQUAL( INet6Address(p->destination().range()), "2001::2" );
+    BOOST_CHECK( p->next()->is<IpV6Extension_Fragment>() );
+    
+    IpV6Extension_Fragment::ptr f (p->next()->as<IpV6Extension_Fragment>());
+    
+    BOOST_CHECK_EQUAL( f->nextHeader(), 17u );
+    BOOST_CHECK_EQUAL( f->fragmentOffset(), 160u );
+    BOOST_CHECK_EQUAL( f->id(), 0x01020304u );
+    BOOST_CHECK( f->next()->is<UDPPacket>() );
+
+    UDPPacket::ptr u (f->next()->as<UDPPacket>());
+    
+    BOOST_CHECK_EQUAL( u->source(), 0x1000u );
+    BOOST_CHECK_EQUAL( u->destination(), 0x2000u );
+    BOOST_CHECK_EQUAL( u->length(), 12u );
+    BOOST_CHECK( u->next()->is<DataPacket>() );
+    
+    Packet::iterator i (u->next()->begin());
+    BOOST_CHECK_EQUAL( Parse_UInt32<Packet::iterator>(i).value(), 0x11121314u );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// ispell-local-dictionary: "american"
+// End:
index b511d02..ba2f389 100644 (file)
 
 namespace {
     senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::IpV6Packet>
-        registerIpV6Packet(0x86dd);
+        registerIpV6Packet (0x86dd);
+
+    senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::IpV6Packet>
+        registerIpV6Packet2 (41); // IP6-in-IP(6) encapsulation
+
+    senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::DataPacket>
+        registerNoNextHeader (59);
 }
 
 prefix_ void senf::IpV6Packet::v_nextInterpreter()
index 99d2476..693d260 100644 (file)
@@ -36,6 +36,7 @@
 
 namespace senf {
 
+    // See RFC2460
     template <class Iterator=nil, class IpV6Packet=nil>
     struct Parse_IpV6 : public ParserBase<Iterator,IpV6Packet>
     {
index 70008a4..41fdcb2 100644 (file)
@@ -46,7 +46,7 @@ BOOST_AUTO_UNIT_TEST(ipV6Packet_parser)
                             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f };
 
     typedef unsigned char * iterator;
-    Parse_IpV6<iterator> p(data);
+    Parse_IpV6<iterator> p (data);
 
     BOOST_CHECK_EQUAL( unsigned(p.version()),       0x06u      );
     BOOST_CHECK_EQUAL( unsigned(p.trafficClass()),  0x01u      );
@@ -60,6 +60,34 @@ BOOST_AUTO_UNIT_TEST(ipV6Packet_parser)
                       "2021:2223:2425:2627:2829:2a2b:2c2d:2e2f" );
 }
 
+BOOST_AUTO_UNIT_TEST(ipV6Packet_packet)
+{
+    unsigned char data[] = { 0x60, 0x12, 0x20, 0x30,
+                            0x01, 0x02, 0x03, 0x04,
+                            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+                            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                            0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+                            0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f };
+
+    IpV6Packet::ptr p (Packet::create<IpV6Packet>(data, data+sizeof(data)));
+
+    
+    BOOST_CHECK_EQUAL( unsigned(p->version()),       0x06u      );
+    BOOST_CHECK_EQUAL( unsigned(p->trafficClass()),  0x01u      );
+    BOOST_CHECK_EQUAL( unsigned(p->flowLabel()),     0x22030u   );
+    BOOST_CHECK_EQUAL( unsigned(p->length()),        0x0102u    );
+    BOOST_CHECK_EQUAL( unsigned(p->nextHeader()),    0x03u      );
+    BOOST_CHECK_EQUAL( unsigned(p->hopLimit()),      0x04u      );
+    BOOST_CHECK_EQUAL( INet6Address(p->source().range()).address() , 
+                      "1011:1213:1415:1617:1819:1a1b:1c1d:1e1f" );
+    BOOST_CHECK_EQUAL( INet6Address(p->destination().range()).address() , 
+                      "2021:2223:2425:2627:2829:2a2b:2c2d:2e2f" );
+
+    BOOST_CHECK( p->next() );
+    BOOST_CHECK( p->next()->is<DataPacket>() );
+    BOOST_CHECK_EQUAL( p->next()->size(), 0u );
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
index ba13aaf..3f35b93 100644 (file)
@@ -24,6 +24,7 @@
 #define HH_ParseInt_ 1
 
 // Custom includes
+#include <iostream>
 #include "ParserBase.hh"
 #include <boost/cstdint.hpp>
 #include <boost/static_assert.hpp>
@@ -58,6 +59,9 @@ namespace senf {
         void value(value_type v) { this->i()[0] = v; }
         Parse_Int8 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_Int8<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_UInt8
@@ -81,6 +85,9 @@ namespace senf {
         void value(value_type v) { this->i()[0] = v; }
         Parse_UInt8 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_UInt8<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_Int16
@@ -104,6 +111,9 @@ namespace senf {
         void value(value_type v) { impl::write_uint16(this->i(),v); }
         Parse_Int16 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_Int16<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_UInt16
@@ -127,6 +137,9 @@ namespace senf {
         void value(value_type v) { impl::write_uint16(this->i(),v); }
         Parse_UInt16 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_UInt16<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_Int24
@@ -151,6 +164,9 @@ namespace senf {
         void value(value_type v) { impl::write_uint24(this->i(),v); }
         Parse_Int24 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_Int24<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_UInt24
@@ -174,6 +190,9 @@ namespace senf {
         void value(value_type v) { impl::write_uint24(this->i(),v); }
         Parse_UInt24 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_UInt24<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_Int32
@@ -197,6 +216,9 @@ namespace senf {
         void value(value_type v) { impl::write_uint32(this->i(),v); }
         Parse_Int32 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_Int32<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_UInt32
@@ -220,6 +242,9 @@ namespace senf {
         void value(value_type v) { impl::write_uint32(this->i(),v); }
         Parse_UInt32 const & operator= (value_type other) { value(other); return *this; }
     };
+    template <class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_UInt32<Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <unsigned start, unsigned end, class Iterator=nil, class IPacket=nil>
     struct Parse_IntField
@@ -251,6 +276,9 @@ namespace senf {
         BOOST_STATIC_ASSERT( start<end );
         BOOST_STATIC_ASSERT( end-start<=32 );
     };
+    template <unsigned start, unsigned end, class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_IntField<start,end,Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <unsigned start, unsigned end, class Iterator=nil, class IPacket=nil>
     struct Parse_UIntField
@@ -278,6 +306,9 @@ namespace senf {
         BOOST_STATIC_ASSERT( start<end );
         BOOST_STATIC_ASSERT( end-start<=32 );
     };
+    template <unsigned start, unsigned end, class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_UIntField<start,end,Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
     template <unsigned bit, class Iterator=nil, class IPacket=nil>
     struct Parse_Flag
@@ -304,6 +335,9 @@ namespace senf {
         }
         Parse_Flag const & operator= (value_type other) { value(other); return *this; }
     };
+    template <unsigned bit, class Iterator, class IPacket>
+    std::ostream & operator<<(std::ostream & os, Parse_Flag<bit,Iterator,IPacket> const & i)
+    { os << i.value(); return os; }
 
 }
 
index c9c2a22..e3ef329 100644 (file)
@@ -34,7 +34,7 @@
 
 namespace {
     senf::PacketRegistry<senf::IpTypes>::RegistrationProxy<senf::UDPPacket> 
-        registerUDPPacket(17);
+        registerUDPPacket (17);
 }
 
 prefix_ void senf::UDPPacket::v_nextInterpreter()
index e94f9c4..078a424 100644 (file)
@@ -34,6 +34,7 @@
 
 namespace senf {
     
+    // See RFC768
     template <class Iterator=nil, class IPacket=nil>
     struct Parse_UDP : public ParserBase<Iterator,IPacket>
     {