80221Bundle: implemented standard compliant parser for MIHF_Id
tho [Thu, 15 Jan 2009 16:19:03 +0000 (16:19 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1062 270642c3-0616-0410-b53a-bc976706d245

Packets/80221Bundle/MIHPacket.cc
Packets/80221Bundle/MIHPacket.hh
Packets/80221Bundle/MIHPacket.test.cc
Packets/80221Bundle/TLVPacket.cc
Packets/80221Bundle/TLVPacket.ct
Packets/80221Bundle/TLVPacket.hh

index 97407c2..6c167f8 100644 (file)
 
 // Custom includes
 #include "../../Packets/Packets.hh"
+#include "../../Utils/hexdump.hh"
 #include <boost/io/ios_state.hpp>
 
 #define prefix_
 
 
+prefix_ std::string senf::MIHFId_TLVParser::asString()
+    const
+{
+    return std::string( i(1+length_bytes()), i(1+length_bytes()+length()) );
+}
+
+prefix_ void senf::MIHFId_TLVParser::setString(std::string const &id)
+{
+    size_type str_size (id.size());
+    // the maximum length of a MIHF_ID is 253 octets (see F.3.11 in 802.21)
+    if (str_size > 253) 
+        throw std::length_error("maximum length of a MIHF_ID is 253 octets");
+    safe_data_iterator si = resizeValue( str_size);   
+    std::copy( id.begin(), id.end(), si);
+}
+
+
+prefix_ senf::MACAddress senf::MIHFId_TLVParser::asMACAddress()
+    const
+{
+    return MACAddress::from_data( 
+            getNAIDecodedIterator( i(1+length_bytes()), i(1+length_bytes()+12) ));
+}
+
+prefix_ void senf::MIHFId_TLVParser::setMACAddress(senf::MACAddress const &mac)
+{
+    safe_data_iterator si = resizeValue(12);
+    std::copy( mac.begin(), mac.end(), getNAIEncodedOutputIterator(si));
+}
+
+
+prefix_ senf::INet4Address senf::MIHFId_TLVParser::asINet4Address()
+    const
+{
+    return INet4Address::from_data( 
+            getNAIDecodedIterator( i(1+length_bytes()), i(1+length_bytes()+8) ));
+}
+
+prefix_ void senf::MIHFId_TLVParser::setINet4Address(senf::INet4Address const &addr)
+{
+    safe_data_iterator si = resizeValue(8);
+    std::copy( addr.begin(), addr.end(), getNAIEncodedOutputIterator(si));
+}
+
+prefix_ senf::INet6Address senf::MIHFId_TLVParser::asINet6Address()
+    const
+{
+    return INet6Address::from_data( 
+            getNAIDecodedIterator( i(1+length_bytes()), i(1+length_bytes()+32) ));
+}
+
+prefix_ void senf::MIHFId_TLVParser::setINet6Address(senf::INet6Address const &addr)
+{
+    safe_data_iterator si = resizeValue(32);
+    std::copy( addr.begin(), addr.end(), getNAIEncodedOutputIterator(si));
+}
+
+
 prefix_ void senf::MIHPacketType::dump(packet p, std::ostream &os)
 {
     boost::io::ios_all_saver ias(os);
@@ -49,14 +108,24 @@ prefix_ void senf::MIHPacketType::dump(packet p, std::ostream &os)
        << "      Opcode:        " << unsigned( p->opcode()) << "\n"
        << "      AID:           " << unsigned( p->aid()) << "\n"      
        << "    Transaction ID:  " << unsigned( p->transactionId()) << "\n"
-       << "    payload length:  " << unsigned( p->payloadLength()) << "\n";
+       << "    payload length:  " << unsigned( p->payloadLength()) << "\n"
+       << "  source MIHF_Id TLV:\n"
+       << "    length:          " << unsigned (p->src_mihfId().length()) << "\n"
+       << "    value:\n";
+    std::string src_mihfId (p->src_mihfId().asString());
+    hexdump(src_mihfId.begin(), src_mihfId.end(), os);
+    os << "  destination MIHF_Id TLV:\n"
+       << "    length:          " << unsigned (p->dst_mihfId().length()) << "\n"
+       << "    value:\n";
+    std::string dst_mihfId (p->dst_mihfId().asString());
+    hexdump(dst_mihfId.begin(), dst_mihfId.end(), os);
 }
 
 
 prefix_ void senf::MIHPacketType::finalize(packet p)
 {
-    p->source_length() << senf::bytes( p->source_mihf_id());
-    p->destination_length() << senf::bytes( p->destination_mihf_id());
+    p->src_mihfId().shrinkLength();
+    p->dst_mihfId().shrinkLength();
     p->payloadLength_() << p.size() - 8;
 }
 
index a67f0a6..7128135 100644 (file)
 
 // Custom includes
 #include "../../Packets/Packets.hh"
+#include "../../Socket/Protocols/Raw/MACAddress.hh"
+#include "../../Socket/Protocols/INet/INet4Address.hh"
+#include "../../Socket/Protocols/INet/INet6Address.hh"
 #include "TLVPacket.hh"
+#include <boost/function_output_iterator.hpp>
+#include <boost/iterator/filter_iterator.hpp>
+
 
 //#include "MIHPacket.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
 
-    struct MIHF_IdParser : public PacketParserBase
+    // the maximum length of a MIHF_ID is 253 octets (see F.3.11 in 802.21)
+    // we could set maxLengthValue in INIT, but for the most MIHF_IDs the default
+    // maximum length of 127 should be enough.
+    // The user must call mihPacket->src_mihfId().maxLengthValue( 127) before 
+    // setting longer MIHF_IDs
+    class MIHFId_TLVParser : public BaseTLVPacketParser
     {
     #   include SENF_PARSER()        
+        SENF_PARSER_INHERIT  ( BaseTLVPacketParser );
+        SENF_PARSER_SKIP     ( length(), 0         );
+        SENF_PARSER_FINALIZE ( MIHFId_TLVParser    );
                 
-        SENF_PARSER_FINALIZE ( MIHF_IdParser );
+        std::string asString() const;
+        void setString(std::string const &id);
+        
+        senf::MACAddress asMACAddress() const;
+        void setMACAddress(senf::MACAddress const &mac);
+
+        senf::INet4Address asINet4Address() const;
+        void setINet4Address(senf::INet4Address const &addr);
+        
+        senf::INet6Address asINet6Address() const;
+        void setINet6Address(senf::INet6Address const &addr);
+
+    private:
+        template <class OutputIterator>
+        struct binaryNAIEncoder {
+            binaryNAIEncoder(OutputIterator &i) : i_(i) {}
+            void operator()(const boost::uint8_t &v) const {
+                *i_++ = '\\'; 
+                *i_++ = v;
+            }
+            OutputIterator &i_;
+        };
+        template <class OutputIterator>
+        static boost::function_output_iterator<binaryNAIEncoder<OutputIterator> > getNAIEncodedOutputIterator(OutputIterator i) {
+            return boost::make_function_output_iterator(binaryNAIEncoder<OutputIterator>(i));
+        }
+        
+        struct binaryNAIDecoder {
+            binaryNAIDecoder() : readNextByte_(true) {}
+            bool operator()(const boost::uint8_t &v) { 
+                readNextByte_ = readNextByte_ ? false : true;
+                return readNextByte_;
+            }
+            bool readNextByte_;
+        };
+        template <class Iterator>
+        static boost::filter_iterator<binaryNAIDecoder, Iterator> getNAIDecodedIterator(Iterator begin, Iterator end) {
+            return boost::make_filter_iterator<binaryNAIDecoder>(begin, end);
+        }
     };
 
     struct MIHPacketParser : public PacketParserBase
@@ -64,21 +116,16 @@ namespace senf {
         SENF_PARSER_FIELD_RO  ( payloadLength, UInt16Parser );
         
         // Source MIHF Id
-        SENF_PARSER_PRIVATE_FIELD ( source_type,    UInt8Parser            );
-        SENF_PARSER_PRIVATE_FIELD ( source_length,  DynamicTLVLengthParser );
-        SENF_PARSER_FIELD         ( source_mihf_id, MIHF_IdParser          );
-
+        SENF_PARSER_FIELD ( src_mihfId, MIHFId_TLVParser );
         // Destination MIHF Id
-        SENF_PARSER_PRIVATE_FIELD ( destination_type,    UInt8Parser            );
-        SENF_PARSER_PRIVATE_FIELD ( destination_length,  DynamicTLVLengthParser );
-        SENF_PARSER_FIELD         ( destination_mihf_id, MIHF_IdParser          );
+        SENF_PARSER_FIELD ( dst_mihfId, MIHFId_TLVParser );
         
         SENF_PARSER_FINALIZE ( MIHPacketParser );
         
         SENF_PARSER_INIT() {
             version_() = 1;
-            source_type() = 1;
-            destination_type() = 2;
+            src_mihfId().type() = 1;
+            dst_mihfId().type() = 2;
         }
         
         friend class MIHPacketType;
index e0c9583..d4f4df0 100644 (file)
 #include <boost/test/test_tools.hpp>
 
 #include "MIHPacket.hh"
-#include "senf/Utils/hexdump.hh"
+
 
 using namespace senf;
 
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-BOOST_AUTO_UNIT_TEST(MIHPacket_create)
+BOOST_AUTO_UNIT_TEST(MIHPacket_create_string)
+{
+    MIHPacket mihPacket (MIHPacket::create());
+    // set some fields
+    mihPacket->fragmentNr() = 42;
+    mihPacket->transactionId() = 21;
+    mihPacket->src_mihfId().setString( "senf@berlios.de");
+    mihPacket->dst_mihfId().setString( "test");
+    mihPacket.finalizeThis();
+    
+    unsigned char data[] = { 
+            // MIH header
+            0x10, 0x54, 0x00, 0x00, 0x00, 0x15, 0x00, 0x17,
+            // source MIHF_ID TLV:
+            0x01, 0x0f, // type, length
+            0x73, 0x65, 0x6e, 0x66, 0x40, 0x62, 0x65, 0x72, 0x6c, 
+            0x69, 0x6f, 0x73, 0x2e, 0x64, 0x65,  // value
+            // destination MIHF_ID TLV:
+            0x02, 0x04, 0x74, 0x65, 0x73, 0x74
+    };
+    BOOST_CHECK(equal( mihPacket.data().begin(), mihPacket.data().end(), data ));
+    BOOST_CHECK_EQUAL( mihPacket->src_mihfId().asString(), "senf@berlios.de");
+    BOOST_CHECK_EQUAL( mihPacket->dst_mihfId().asString(), "test");
+    
+    // now expand a MIHF_ID
+    mihPacket->dst_mihfId().maxLengthValue(253);
+    mihPacket->dst_mihfId().setString( std::string(200, 'x'));
+    mihPacket.finalizeThis();
+    
+    BOOST_CHECK_EQUAL( mihPacket.size(), 8 + 17 + 203);
+    BOOST_CHECK_EQUAL( mihPacket->payloadLength(), 17 + 203);
+    BOOST_CHECK_EQUAL( mihPacket->dst_mihfId().length(), 200);
+    BOOST_CHECK_EQUAL( senf::bytes(mihPacket->dst_mihfId()), 203);
+}
+
+
+BOOST_AUTO_UNIT_TEST(MIHPacket_create_mac)
 {
     MIHPacket mihPacket (MIHPacket::create());
     // set some fields
     mihPacket->fragmentNr() = 42;
     mihPacket->transactionId() = 21;
+    mihPacket->src_mihfId().setMACAddress( MACAddress::from_string("01:02:03:04:05:06"));
+    mihPacket->dst_mihfId().setMACAddress( MACAddress::from_string("07:08:09:0a:0b:0c"));
     mihPacket.finalizeThis();
     
-//    mihPacket.dump(std::cout);
-//    senf::hexdump(mihPacket.data().begin(), mihPacket.data().end(), std::cout);
+    unsigned char data[] = { 
+            // MIH header
+            0x10, 0x54, 0x00, 0x00, 0x00, 0x15, 0x00, 0x1c,
+            // source MIHF_ID TLV:
+            0x01, 0x0c, // type, length
+            0x5c, 0x01, 0x5c, 0x02, 0x5c, 0x03, 0x5c, 0x04, 0x5c, 0x05, 0x5c, 0x06, // value (nai-encoded)
+            // destination MIHF_ID TLV:
+            0x02, 0x0c,  // type, length
+            0x5c, 0x07, 0x5c, 0x08, 0x5c, 0x09, 0x5c, 0x0a, 0x5c, 0x0b, 0x5c, 0x0c  // value (nai-encoded)
+    };
+    BOOST_CHECK(equal( mihPacket.data().begin(), mihPacket.data().end(), data ));
+    BOOST_CHECK_EQUAL( 
+            mihPacket->src_mihfId().asMACAddress(), 
+            MACAddress::from_string("01:02:03:04:05:06"));
+    BOOST_CHECK_EQUAL( 
+            mihPacket->dst_mihfId().asMACAddress(), 
+            MACAddress::from_string("07:08:09:0a:0b:0c"));
+}
+
+
+BOOST_AUTO_UNIT_TEST(MIHPacket_create_inet4)
+{
+    MIHPacket mihPacket (MIHPacket::create());
+    // set some fields
+    mihPacket->fragmentNr() = 42;
+    mihPacket->transactionId() = 21;
+    mihPacket->src_mihfId().setINet4Address( INet4Address::from_string("128.129.130.131"));
+    mihPacket->dst_mihfId().setINet4Address( INet4Address::from_string("132.133.134.135"));
+    mihPacket.finalizeThis();
+    
+    unsigned char data[] = { 
+            // MIH header
+            0x10, 0x54, 0x00, 0x00, 0x00, 0x15, 0x00, 0x14,
+            // source MIHF_ID TLV:
+            0x01, 0x08, // type, length
+            0x5c, 0x80, 0x5c, 0x81, 0x5c, 0x82, 0x5c, 0x83, // value (nai-encoded)
+            // destination MIHF_ID TLV:
+            0x02, 0x08, // type, length
+            0x5c, 0x84, 0x5c, 0x85, 0x5c, 0x86, 0x5c, 0x87  // value (nai-encoded)
+    };
+    BOOST_CHECK(equal( mihPacket.data().begin(), mihPacket.data().end(), data ));
+    BOOST_CHECK_EQUAL( 
+            mihPacket->src_mihfId().asINet4Address(), 
+            INet4Address::from_string("128.129.130.131"));
+    BOOST_CHECK_EQUAL( 
+            mihPacket->dst_mihfId().asINet4Address(), 
+            INet4Address::from_string("132.133.134.135"));
+}
+
+
+BOOST_AUTO_UNIT_TEST(MIHPacket_create_inet6)
+{
+    MIHPacket mihPacket (MIHPacket::create());
+    // set some fields
+    mihPacket->fragmentNr() = 42;
+    mihPacket->transactionId() = 21;
+    mihPacket->src_mihfId().setINet6Address( INet6Address::from_string("::ffff:1.2.3.4"));
+    mihPacket->dst_mihfId().setINet6Address( INet6Address::from_string("::ffff:5.6.7.8"));
+    mihPacket.finalizeThis();
     
     unsigned char data[] = { 
-            0x10, 0x54, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04,
-            0x01, 0x00,
-            0x02, 0x00
+            // MIH header
+            0x10, 0x54, 0x00, 0x00, 0x00, 0x15, 0x00, 0x44,
+            // source MIHF_ID TLV:
+            0x01, 0x20, // type, length
+            // value (nai-encoded):
+            0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+            0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+            0x5c, 0x00, 0x5c, 0x00, 0x5c, 0xff, 0x5c, 0xff,
+            0x5c, 0x01, 0x5c, 0x02, 0x5c, 0x03, 0x5c, 0x04,
+            // destination MIHF_ID TLV:
+            0x02, 0x20, // type, length
+            // value (nai-encoded):
+            0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+            0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+            0x5c, 0x00, 0x5c, 0x00, 0x5c, 0xff, 0x5c, 0xff,
+            0x5c, 0x05, 0x5c, 0x06, 0x5c, 0x07, 0x5c, 0x08
     };
-    BOOST_CHECK( equal( mihPacket.data().begin(), mihPacket.data().end(), data ));
+    BOOST_CHECK(equal( mihPacket.data().begin(), mihPacket.data().end(), data ));
+    BOOST_CHECK_EQUAL( 
+            mihPacket->src_mihfId().asINet6Address(), 
+            INet6Address::from_string("::ffff:1.2.3.4"));
+    BOOST_CHECK_EQUAL( 
+            mihPacket->dst_mihfId().asINet6Address(), 
+            INet6Address::from_string("::ffff:5.6.7.8") );
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 3bf2039..12d9bfd 100644 (file)
 
 // Custom includes
 #include <iomanip>
-#include <senf/Utils/hexdump.hh>
+#include "../../Utils/hexdump.hh"
 
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
+prefix_ senf::safe_data_iterator senf::BaseTLVPacketParser::resizeValue(
+        DynamicTLVLengthParser::value_type size) 
+{
+    DynamicTLVLengthParser::value_type current_length ( length());
+    length( size);
+
+    safe_data_iterator si (data(), boost::next(i(), 1 + length_bytes() ));
+    if (current_length > size)
+        data().erase( si, boost::next(si, current_length-size));
+    else
+        data().insert( si, size-current_length, 0);
+    return si;
+}
+
+
 prefix_ senf::DynamicTLVLengthParser::value_type senf::DynamicTLVLengthParser::value() const 
 {
     switch (bytes() ) {
@@ -148,15 +163,6 @@ prefix_ void senf::DynamicTLVLengthParser:: maxValue(DynamicTLVLengthParser::val
 }
 
 
-prefix_ senf::PacketInterpreterBase::range senf::GenericTLVPacketParser::value() 
-    const
-{
-    senf::PacketData::iterator begin (boost::next(data().begin(), 1 + length_bytes() ));
-    return PacketInterpreterBase::range(
-            begin, boost::next( begin, length()) );
-}
-
-
 prefix_ void senf::DynamicTLVLengthParser::resize(size_type size)
 {
     value_type v = value();
@@ -178,6 +184,15 @@ prefix_ void senf::DynamicTLVLengthParser::resize(size_type size)
 }
 
 
+prefix_ senf::PacketInterpreterBase::range senf::GenericTLVPacketParser::value() 
+    const
+{
+    senf::PacketData::iterator begin (boost::next(data().begin(), 1 + length_bytes() ));
+    return PacketInterpreterBase::range(
+            begin, boost::next( begin, length()) );
+}
+
+
 prefix_ void senf::GenericTLVPacketType::dump(packet p, std::ostream & os)
 {
     boost::io::ios_all_saver ias(os);
index 5800158..efae0f6 100644 (file)
 template <class ForwardReadableRange>
 prefix_ void senf::GenericTLVPacketParser::value(ForwardReadableRange const &range)
 {
-    DynamicTLVLengthParser::value_type range_size ( boost::size(range));
-    DynamicTLVLengthParser::value_type current_length ( length());
-    length( range_size);
-
-    safe_data_iterator si (data(), boost::next(i(), 1 + length_bytes() ));
-    if (current_length > range_size)
-        data().erase( si, boost::next(si, current_length-range_size));
-    else
-        data().insert( si, range_size-current_length, 0);
-    
+    safe_data_iterator si = resizeValue( boost::size(range) );   
     std::copy( boost::begin(range), boost::end(range), si);
 }
 
index 057f06f..c337aec 100644 (file)
@@ -88,14 +88,16 @@ namespace senf {
     protected:
         size_type length_bytes() const { return length_().bytes(); };
         void length(DynamicTLVLengthParser::value_type &v) { length_() = v; };
+        senf::safe_data_iterator resizeValue(DynamicTLVLengthParser::value_type size);
     };
 
         
     struct GenericTLVPacketParser : public BaseTLVPacketParser
     {
 #       include SENF_PARSER()        
-        SENF_PARSER_INHERIT( BaseTLVPacketParser )
-        SENF_PARSER_FINALIZE( GenericTLVPacketParser );
+        SENF_PARSER_INHERIT  ( BaseTLVPacketParser    );
+        SENF_PARSER_SKIP     ( length(), 0            );
+        SENF_PARSER_FINALIZE ( GenericTLVPacketParser );
         
         SENF_PARSER_INIT() {
             maxLengthValue( DynamicTLVLengthParser::max_value);