BIND 10 trac1186, updated. ce56b4e948ccf00ac04736fa36eb4b666031426a [1186] Added suboptions support in Option class, tests implemented.

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Sep 6 17:16:56 UTC 2011


The branch, trac1186 has been updated
       via  ce56b4e948ccf00ac04736fa36eb4b666031426a (commit)
      from  06fd78fda15e2e877cf8d15c058ee6fd2015dd78 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ce56b4e948ccf00ac04736fa36eb4b666031426a
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Tue Sep 6 19:15:58 2011 +0200

    [1186] Added suboptions support in Option class, tests implemented.

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dhcp/option.cc                 |   59 +++++++++----
 src/lib/dhcp/option.h                  |   18 +++-
 src/lib/dhcp/option6_ia.cc             |    6 +-
 src/lib/dhcp/option6_ia.h              |    2 +-
 src/lib/dhcp/option6_iaaddr.cc         |    5 +-
 src/lib/dhcp/option6_iaaddr.h          |    2 +-
 src/lib/dhcp/tests/libdhcp_unittest.cc |   16 ++--
 src/lib/dhcp/tests/option_unittest.cc  |  148 ++++++++++++++++++++++++++++++--
 8 files changed, 217 insertions(+), 39 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc
index fedc557..4cfaad8 100644
--- a/src/lib/dhcp/option.cc
+++ b/src/lib/dhcp/option.cc
@@ -27,7 +27,7 @@ using namespace std;
 using namespace isc::dhcp;
 
 Option::Option(Universe u, unsigned short type)
-    :universe_(u), type_(type) {
+    :universe_(u), type_(type), data_len_(0) {
 
 
 }
@@ -82,14 +82,20 @@ Option::pack6(boost::shared_array<char> buf,
         isc_throw(OutOfRange, "Failed to pack v6 option=" <<
                   type_ << ",len=" << len() << ": too small buffer.");
     }
+
+    int length = len() - getHeaderLen();
+
     char * ptr = &buf[offset];
     *(uint16_t*)ptr = htons(type_);
     ptr += 2;
-    *(uint16_t*)ptr = htons(data_len_);
+    *(uint16_t*)ptr = htons(length);
     ptr += 2;
-    memcpy(ptr, &data_[offset_], data_len_);
+    if (data_len_)
+        memcpy(ptr, &data_[offset_], data_len_);
 
-    return offset + len();
+    offset += 4 + data_len_; // end of this option
+
+    return LibDHCP::packOptions6(buf, buf_len, offset, optionLst_);
 }
 
 unsigned int
@@ -126,8 +132,9 @@ Option::unpack6(boost::shared_array<char> buf,
 
     if (buf_len < offset+parse_len) {
         isc_throw(OutOfRange, "Failed to unpack DHCPv6 option len="
-                  << parse_len << " offset=" << offset << " from buffer (length="
-                  << buf_len << "): too small buffer.");
+                  << parse_len << " offset=" << offset
+                  << " from buffer (length=" << buf_len
+                  << "): too small buffer.");
     }
 
     data_ = buf;
@@ -139,16 +146,15 @@ Option::unpack6(boost::shared_array<char> buf,
 }
 
 unsigned short Option::len() {
-    switch (universe_) {
-    case V4:
-        return data_len_ + 2; // DHCPv4 option header length: 2 bytes
-    case V6:
-        return data_len_ + 4; // DHCPv6 option header length: 4 bytes
-    default:
-        isc_throw(BadValue, "Unknown universe defined for Option " << type_);
+    int length = getHeaderLen() + data_len_;
+
+    for (Option::Option6Lst::iterator it = optionLst_.begin();
+         it != optionLst_.end();
+         ++it) {
+        length += (*it).second->len();
     }
 
-    return 0; // should not happen
+    return (length);
 }
 
 bool Option::valid() {
@@ -165,19 +171,25 @@ bool Option::valid() {
 
 void
 isc::dhcp::Option::addOption(boost::shared_ptr<isc::dhcp::Option> opt) {
-    optionLst_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
+    optionLst_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(),
+                                                            opt));
 
 }
 
-std::string Option::toText() {
+std::string Option::toText(int indent /* =0 */ ) {
     std::stringstream tmp;
-    tmp << type_ << "(len=" << data_len_ << "):";
+
+    for (int i=0; i<indent; i++)
+        tmp << " ";
+
+    tmp << "type=" << type_ << ", len=" << data_len_ << ":";
 
     for (unsigned int i=0; i<data_len_; i++) {
         if (i) {
             tmp << ":";
         }
-        tmp << setfill('0') << setw(2) << hex << (unsigned short)(unsigned char)data_[offset_+i];
+        tmp << setfill('0') << setw(2) << hex
+            << (unsigned short)(unsigned char)data_[offset_+i];
     }
     return tmp.str();
 }
@@ -196,6 +208,17 @@ Option::getData() {
     }
 }
 
+unsigned short
+Option::getHeaderLen() {
+    switch (universe_) {
+    case V4:
+        return 2; // header length for v4
+    case V6:
+        return 4; // header length for v6
+    }
+    return 0; // should not happen
+}
+
 
 Option::~Option() {
 
diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h
index ceeb03a..14a9fe1 100644
--- a/src/lib/dhcp/option.h
+++ b/src/lib/dhcp/option.h
@@ -80,10 +80,12 @@ public:
     ///
     /// Returns string representation of the option.
     ///
+    /// @param indent number of spaces before printing text
+    ///
     /// @return string with text representation.
     ///
     virtual std::string
-    toText();
+    toText(int indent = 0);
 
     ///
     /// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
@@ -101,11 +103,21 @@ public:
     virtual unsigned short
     len();
 
-    // returns if option is valid (e.g. option may be truncated)
+    /// @brief Returns length of header (2 for v4, 4 for v6)
+    ///
+    /// @return length of option header
+    ///
+    virtual unsigned short
+    getHeaderLen();
+
+    /// returns if option is valid (e.g. option may be truncated)
     virtual bool
     valid();
 
-    // returns pointer to actual data
+    /// Returns pointer to actual data.
+    ///
+    /// @return pointer to actual data (or NULL if there is no data)
+    ///
     virtual char*
     getData();
 
diff --git a/src/lib/dhcp/option6_ia.cc b/src/lib/dhcp/option6_ia.cc
index e18b623..6396935 100644
--- a/src/lib/dhcp/option6_ia.cc
+++ b/src/lib/dhcp/option6_ia.cc
@@ -89,8 +89,12 @@ Option6IA::unpack(boost::shared_array<char> buf,
     return (offset);
 }
 
-std::string Option6IA::toText() {
+std::string Option6IA::toText(int indent /* = 0*/) {
     stringstream tmp;
+
+    for (int i=0; i<indent; i++)
+        tmp << " ";
+
     switch (type_) {
     case D6O_IA_NA:
         tmp << "IA_NA";
diff --git a/src/lib/dhcp/option6_ia.h b/src/lib/dhcp/option6_ia.h
index 20667e1..a067e61 100644
--- a/src/lib/dhcp/option6_ia.h
+++ b/src/lib/dhcp/option6_ia.h
@@ -51,7 +51,7 @@ public:
            unsigned int offset, 
            unsigned int parse_len);
 
-    virtual std::string toText();
+    virtual std::string toText(int indent = 0);
 
     void setT1(unsigned int t1) { t1_=t1; }
     void setT2(unsigned int t2) { t2_=t2; }
diff --git a/src/lib/dhcp/option6_iaaddr.cc b/src/lib/dhcp/option6_iaaddr.cc
index 34e3885..456e441 100644
--- a/src/lib/dhcp/option6_iaaddr.cc
+++ b/src/lib/dhcp/option6_iaaddr.cc
@@ -99,8 +99,11 @@ Option6IAAddr::unpack(boost::shared_array<char> buf,
     return offset;
 }
 
-std::string Option6IAAddr::toText() {
+std::string Option6IAAddr::toText(int indent /* =0 */) {
     stringstream tmp;
+    for (int i=0; i<indent; i++)
+        tmp << " ";
+
     tmp << "addr: " << addr_.toText() << ", preferred-lft=" << preferred_ 
         << ", valid-lft=" << valid_ << endl;
 
diff --git a/src/lib/dhcp/option6_iaaddr.h b/src/lib/dhcp/option6_iaaddr.h
index 89412ab..6f49a40 100644
--- a/src/lib/dhcp/option6_iaaddr.h
+++ b/src/lib/dhcp/option6_iaaddr.h
@@ -55,7 +55,7 @@ public:
            unsigned int offset, 
            unsigned int parse_len);
 
-    virtual std::string toText();
+    virtual std::string toText(int indent = 0);
 
     void setAddress(isc::asiolink::IOAddress addr) { addr_ = addr; }
     void setPreferred(unsigned int pref) { preferred_=pref; }
diff --git a/src/lib/dhcp/tests/libdhcp_unittest.cc b/src/lib/dhcp/tests/libdhcp_unittest.cc
index 20a1848..f9c98c0 100644
--- a/src/lib/dhcp/tests/libdhcp_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp_unittest.cc
@@ -87,8 +87,8 @@ TEST_F(LibDhcpTest, unpackOptions6) {
         1,  1, 0, 1, 114 // opt5 (5 bytes)
     };
     // Option is used as a simple option implementation
-    // More advanced classes are used in tests dedicated for
-    // specific options.
+    // More advanced uses are validated in tests dedicated for
+    // specific derived classes.
 
     isc::dhcp::Option::Option6Lst options; // list of options
 
@@ -109,36 +109,36 @@ TEST_F(LibDhcpTest, unpackOptions6) {
     ASSERT_NE(x, options.end()); // option 1 should exist
     EXPECT_EQ(12, x->second->getType());  // this should be option 12
     ASSERT_EQ(9, x->second->len()); // it should be of length 9
-    EXPECT_EQ(0, memcmp(x->second->getData(), packed+4, 5)); // data len = 5
+    EXPECT_EQ(0, memcmp(x->second->getData(), packed+4, 5)); // data len=5
 
     x = options.find(13);
     ASSERT_NE(x, options.end()); // option 13 should exist
     EXPECT_EQ(13, x->second->getType());  // this should be option 13
     ASSERT_EQ(7, x->second->len()); // it should be of length 7
-    EXPECT_EQ(0, memcmp(x->second->getData(), packed+13, 3)); // data length = 3
+    EXPECT_EQ(0, memcmp(x->second->getData(), packed+13, 3)); // data len=3
 
     x = options.find(14);
     ASSERT_NE(x, options.end()); // option 3 should exist
     EXPECT_EQ(14, x->second->getType());  // this should be option 14
     ASSERT_EQ(6, x->second->len()); // it should be of length 6
-    EXPECT_EQ(0, memcmp(x->second->getData(), packed+20, 2)); // data length = 2
+    EXPECT_EQ(0, memcmp(x->second->getData(), packed+20, 2)); // data len=2
 
     x = options.find(256);
     ASSERT_NE(x, options.end()); // option 256 should exist
     EXPECT_EQ(256, x->second->getType());  // this should be option 256
     ASSERT_EQ(8, x->second->len()); // it should be of length 7
-    EXPECT_EQ(0, memcmp(x->second->getData(), packed+26, 4)); // data length = 4
+    EXPECT_EQ(0, memcmp(x->second->getData(), packed+26, 4)); // data len=4
 
     x = options.find(257);
     ASSERT_NE(x, options.end()); // option 257 should exist
     EXPECT_EQ(257, x->second->getType());  // this should be option 257
     ASSERT_EQ(5, x->second->len()); // it should be of length 5
-    EXPECT_EQ(0, memcmp(x->second->getData(), packed+34, 1)); // data length = 2
+    EXPECT_EQ(0, memcmp(x->second->getData(), packed+34, 1)); // data len=1
 
     x = options.find(0);
     EXPECT_EQ(x, options.end()); // option 0 not found
 
-    x = options.find(1); // 1 is htons(256). Worth checking
+    x = options.find(1); // 1 is htons(256) on little endians. Worth checking
     EXPECT_EQ(x, options.end()); // option 1 not found
 
     x = options.find(2);
diff --git a/src/lib/dhcp/tests/option_unittest.cc b/src/lib/dhcp/tests/option_unittest.cc
index cb9034c..b900d86 100644
--- a/src/lib/dhcp/tests/option_unittest.cc
+++ b/src/lib/dhcp/tests/option_unittest.cc
@@ -18,6 +18,7 @@
 
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
+#include <boost/shared_ptr.hpp>
 
 #include "dhcp/dhcp6.h"
 #include "dhcp/option.h"
@@ -33,7 +34,63 @@ public:
     }
 };
 
-TEST_F(OptionTest, basic) {
+// v4 is not really implemented yet. A simple test will do for now
+TEST_F(OptionTest, basic4) {
+
+    Option* opt = new Option(Option::V4, 17);
+
+    EXPECT_EQ(17, opt->getType());
+    EXPECT_EQ(NULL, opt->getData());
+    EXPECT_EQ(2, opt->len()); // just v4 header
+
+    delete opt;
+}
+
+// tests simple constructor
+TEST_F(OptionTest, basic6) {
+
+    Option* opt = new Option(Option::V6, 1);
+
+    EXPECT_EQ(1, opt->getType());
+    EXPECT_EQ(NULL, opt->getData());
+    EXPECT_EQ(4, opt->len()); // just v6 header
+
+    delete opt;
+}
+
+// tests contructor used in pkt reception
+// option contains actual data
+TEST_F(OptionTest, data1) {
+    boost::shared_array<char> buf(new char[32]);
+    for (int i=0; i<32; i++)
+        buf[i] = 100+i;
+    Option* opt = new Option(Option::V6, 333, //type
+                             buf,
+                             3, // offset
+                             7); // 7 bytes of data
+    EXPECT_EQ(333, opt->getType());
+    ASSERT_EQ(&buf[3], opt->getData());
+    ASSERT_EQ(11, opt->len());
+    EXPECT_EQ(0, memcmp(&buf[3], opt->getData(), 7) );
+
+    int offset = opt->pack(buf, 32, 20);
+    EXPECT_EQ(31, offset);
+
+    EXPECT_EQ(buf[20], 333/256); // type
+    EXPECT_EQ(buf[21], 333%256);
+
+    EXPECT_EQ(buf[22], 0); // len
+    EXPECT_EQ(buf[23], 7);
+
+    // payload
+    EXPECT_EQ(0, memcmp(&buf[3], &buf[24], 7) );
+
+    delete opt;
+}
+
+// another text that tests the same thing, just
+// with different input parameters
+TEST_F(OptionTest, data2) {
 
     boost::shared_array<char> simple_buf(new char[128]);
     for (int i=0; i<128; i++)
@@ -70,12 +127,91 @@ TEST_F(OptionTest, basic) {
     // if option content is correct
     EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[14],4));
 
-    for (int i=0; i<20; i++) {
-        std::cout << i << ":" << (unsigned short) (unsigned char)simple_buf[i] << " ";
-    }
-    std::cout << std::endl;
-
     delete opt;
 }
 
+// check that an option can contain 2 suboptions:
+// opt1
+//  +----opt2
+//  |
+//  +----opt3
+//
+TEST_F(OptionTest, suboptions1) {
+    boost::shared_array<char> buf(new char[128]);
+    for (int i=0; i<128; i++)
+        buf[i] = 100+i;
+    Option* opt1 = new Option(Option::V6, 65535, //type
+                              buf,
+                              0, // offset
+                              3); // 3 bytes of data
+    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
+    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
+                                              buf,
+                                              3, // offset
+                                              5)); // 5 bytes of data
+    opt1->addOption(opt2);
+    opt1->addOption(opt3);
+    // opt2 len = 4 (just header)
+    // opt3 len = 9 4(header)+5(data)
+    // opt1 len = 7 + suboptions() = 7 + 4 + 9 = 20
+
+    EXPECT_EQ(4, opt2->len());
+    EXPECT_EQ(9, opt3->len());
+    EXPECT_EQ(20, opt1->len());
+
+    char expected[] = {
+        0xff, 0xff, 0, 16, 100, 101, 102,
+        0, 7, 0, 5, 103, 104, 105, 106, 107,
+        0, 13, 0, 0 // no data at all
+    };
+
+    int offset = opt1->pack(buf, 128, 20);
+    EXPECT_EQ(40, offset);
+
+    // payload
+    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+
+    delete opt1;
+}
+
+// check that an option can contain 2 suboptions:
+// opt1
+//  +----opt2
+//        |
+//        +----opt3
+//
+TEST_F(OptionTest, suboptions2) {
+    boost::shared_array<char> buf(new char[128]);
+    for (int i=0; i<128; i++)
+        buf[i] = 100+i;
+    Option* opt1 = new Option(Option::V6, 65535, //type
+                              buf,
+                              0, // offset
+                              3); // 3 bytes of data
+    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
+    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
+                                              buf,
+                                              3, // offset
+                                              5)); // 5 bytes of data
+    opt1->addOption(opt2);
+    opt2->addOption(opt3);
+    // opt3 len = 9 4(header)+5(data)
+    // opt2 len = 4 (just header) + len(opt3)
+    // opt1 len = 7 + len(opt2)
+
+    char expected[] = {
+        0xff, 0xff, 0, 16, 100, 101, 102,
+        0, 13, 0, 9,
+        0, 7, 0, 5, 103, 104, 105, 106, 107,
+    };
+
+    int offset = opt1->pack(buf, 128, 20);
+    EXPECT_EQ(40, offset);
+
+    // payload
+    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+
+    delete opt1;
+}
+
 }




More information about the bind10-changes mailing list