Browse Source

[trac1112] Finish the basic function of HINFO rrdata support.

Ocean Wang 13 years ago
parent
commit
3fc53ba91b

+ 133 - 5
src/lib/dns/rdata/generic/hinfo_13.cc

@@ -20,7 +20,6 @@
 
 #include <exceptions/exceptions.h>
 
-#include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -33,34 +32,163 @@ using namespace isc::util;
 // BEGIN_ISC_NAMESPACE
 // BEGIN_RDATA_NAMESPACE
 
-HINFO::HINFO(const string& type_str) {
+
+HINFO::HINFO(const string& hinfo_str) {
+    string::const_iterator input_iterator = hinfo_str.begin();
+    cpu_ = getNextCharacterString(hinfo_str, input_iterator);
+
+    skipLeftSpaces(hinfo_str, input_iterator);
+
+    os_ = getNextCharacterString(hinfo_str, input_iterator);
 }
 
 HINFO::HINFO(InputBuffer& buffer, size_t rdata_len) {
+    cpu_ = getNextCharacterString(buffer, rdata_len);
+    os_ = getNextCharacterString(buffer, rdata_len);
 }
 
-HINFO::HINFO(const HINFO& source) {
+HINFO::HINFO(const HINFO& source):
+    Rdata(), cpu_(source.cpu_), os_(source.os_)
+{
 }
 
 std::string
 HINFO::toText() const {
+    string result;
+    result += "\"";
+    result += cpu_;
+    result += "\" \"";
+    result += os_;
+    result += "\"";
+    return result;
 }
 
 void
 HINFO::toWire(OutputBuffer& buffer) const {
+    buffer.writeUint8(cpu_.size());
+    buffer.writeData(cpu_.c_str(), cpu_.size());
+
+    buffer.writeUint8(os_.size());
+    buffer.writeData(os_.c_str(), os_.size());
 }
 
 void
 HINFO::toWire(AbstractMessageRenderer& renderer) const {
+    renderer.writeUint8(cpu_.size());
+    renderer.writeData(cpu_.c_str(), cpu_.size());
+
+    renderer.writeUint8(os_.size());
+    renderer.writeData(os_.c_str(), os_.size());
 }
 
 int
 HINFO::compare(const Rdata& other) const {
-    // The compare method normally begins with this dynamic cast.
     const HINFO& other_hinfo = dynamic_cast<const HINFO&>(other);
-    // ...
+
+    if (cpu_ < other_hinfo.cpu_) {
+        return (-1);
+    } else if (cpu_ > other_hinfo.cpu_) {
+        return (1);
+    }
+
+    if (os_ < other_hinfo.os_) {
+        return (-1);
+    } else if (os_ > other_hinfo.os_) {
+        return (1);
+    }
+
+    return (0);
+}
+
+const std::string&
+HINFO::getCPU() const {
+    return cpu_;
+}
+
+const std::string&
+HINFO::getOS() const {
+    return os_;
+}
+
+void
+HINFO::skipLeftSpaces(const std::string& input_str,
+                      std::string::const_iterator& input_iterator)
+{
+    if (input_iterator >= input_str.end()) {
+        isc_throw(InvalidRdataText,
+                  "Invalid HINFO text format, field is missing.");
+    }
+
+    if (!isspace(*input_iterator)) {
+        isc_throw(InvalidRdataText,
+            "Invalid HINFO text format, fields are not separated by space.");
+    }
+    // Skip white spaces
+    while (input_iterator < input_str.end() && isspace(*input_iterator)) {
+        ++input_iterator;
+    }
 }
 
+std::string
+HINFO::getNextCharacterString(const std::string& input_str,
+                              std::string::const_iterator& input_iterator)
+{
+    string result;
+
+    // If the input string only contains white-spaces, it is an invalid
+    // <character-string>
+    if (input_iterator >= input_str.end()) {
+        isc_throw(InvalidRdataText, "Invalid HINFO text format, \
+                  <character-string> field is missing.");
+    }
+
+    // Whether the <character-string> is separated with double quotes (")
+    bool quotes_separated = (*input_iterator == '"');
+
+    if (quotes_separated) {
+        ++input_iterator;
+    }
+
+    while(input_iterator < input_str.end()){
+        if (quotes_separated) {
+            // If the <character-string> is seperated with quotes symbol and
+            // another quotes symbol is encountered, it is the end of the
+            // <character-string>
+            if (*input_iterator == '"') {
+                ++input_iterator;
+                break;
+            }
+        } else if (*input_iterator == ' ') {
+            // If the <character-string> is not seperated with quotes symbol,
+            // it is seperated with <space> char
+            break;
+        }
+
+        result.push_back(*input_iterator);
+
+        ++input_iterator;
+    }
+
+    if (result.size() > MAX_CHARSTRING_LEN) {
+        isc_throw(CharStringTooLong, "HINFO <character-string> is too long");
+    }
+
+    return (result);
+}
+
+std::string
+HINFO::getNextCharacterString(InputBuffer& buffer, size_t len) {
+    uint8_t str_len = buffer.readUint8();
+
+    size_t pos = buffer.getPosition();
+    if (len - pos < str_len) {
+        isc_throw(InvalidRdataLength, "Invalid HINFO string length");
+    }
+
+    uint8_t buf[MAX_CHARSTRING_LEN];
+    buffer.readData(buf, str_len);
+    return (string(buf, buf + str_len));
+}
 
 // END_RDATA_NAMESPACE
 // END_ISC_NAMESPACE

+ 29 - 2
src/lib/dns/rdata/generic/hinfo_13.h

@@ -19,6 +19,7 @@
 
 #include <dns/name.h>
 #include <dns/rdata.h>
+#include <util/buffer.h>
 
 // BEGIN_ISC_NAMESPACE
 
@@ -32,11 +33,37 @@ public:
     // BEGIN_COMMON_MEMBERS
     // END_COMMON_MEMBERS
 
+    // HINFO specific methods
+    const std::string& getCPU() const;
+    const std::string& getOS() const;
+
+private:
+    /// Skip the left whitespaces of the input string
+    ///
+    /// \param input_str The input string
+    /// \param input_iterator From which the skipping started
+    void skipLeftSpaces(const std::string& input_str,
+                        std::string::const_iterator& input_iterator);
+
+    /// Get a <character-string> from a string
     ///
-    /// Specialized methods
+    /// \param input_str The input string
+    /// \param input_iterator The iterator from which to start extracting,
+    ///        the iterator will be updated to new position after the function
+    ///        is returned
+    /// \return A std::string that contains the extracted <character-string>
+    std::string getNextCharacterString(const std::string& input_str,
+                                       std::string::const_iterator& input_iterator);
+
+    /// Get a <character-string> from a input buffer
     ///
+    /// \param buffer The input buffer
+    /// \param len The input buffer total length
+    /// \return A std::string that contains the extracted <character-string>
+    std::string getNextCharacterString(util::InputBuffer& buffer, size_t len);
 
-private:
+    std::string cpu_;
+    std::string os_;
 };
 
 

+ 52 - 0
src/lib/dns/tests/rdata_hinfo_unittest.cc

@@ -36,9 +36,61 @@ namespace {
 class Rdata_HINFO_Test : public RdataTest {
 };
 
+static uint8_t hinfo_rdata[] = {0x07,0x50,0x65,0x6e,0x74,0x69,0x75,0x6d,0x05,
+    0x4c,0x69,0x6e,0x75,0x78};
 static const char *hinfo_str = "\"Pentium\" \"Linux\"";
 
+static const char *hinfo_str_small1 = "\"Lentium\" \"Linux\"";
+static const char *hinfo_str_small2 = "\"Pentium\" \"Kinux\"";
+static const char *hinfo_str_large1 = "\"Qentium\" \"Linux\"";
+static const char *hinfo_str_large2 = "\"Pentium\" \"UNIX\"";
+
 TEST_F(Rdata_HINFO_Test, createFromText) {
     HINFO hinfo(hinfo_str);
+    EXPECT_EQ(string("Pentium"), hinfo.getCPU());
+    EXPECT_EQ(string("Linux"), hinfo.getOS());
+}
+
+TEST_F(Rdata_HINFO_Test, createFromWire) {
+    InputBuffer input_buffer(hinfo_rdata, sizeof(hinfo_rdata));
+    HINFO hinfo(input_buffer, sizeof(hinfo_rdata));
+    EXPECT_EQ(string("Pentium"), hinfo.getCPU());
+    EXPECT_EQ(string("Linux"), hinfo.getOS());
+}
+
+TEST_F(Rdata_HINFO_Test, toText) {
+    HINFO hinfo(hinfo_str);
+    EXPECT_EQ(hinfo_str, hinfo.toText());
+}
+
+TEST_F(Rdata_HINFO_Test, toWire) {
+    HINFO hinfo(hinfo_str);
+    hinfo.toWire(obuffer);
+
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
+                        obuffer.getLength(), hinfo_rdata, sizeof(hinfo_rdata));
 }
+
+TEST_F(Rdata_HINFO_Test, toWireRenderer) {
+    HINFO hinfo(hinfo_str);
+
+    hinfo.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
+                        obuffer.getLength(), hinfo_rdata, sizeof(hinfo_rdata));
+}
+
+TEST_F(Rdata_HINFO_Test, compare) {
+    HINFO hinfo(hinfo_str);
+    HINFO hinfo_small1(hinfo_str_small1);
+    HINFO hinfo_small2(hinfo_str_small2);
+    HINFO hinfo_large1(hinfo_str_large1);
+    HINFO hinfo_large2(hinfo_str_large2);
+
+    EXPECT_EQ(0, hinfo.compare(HINFO(hinfo_str)));
+    EXPECT_EQ(1, hinfo.compare(HINFO(hinfo_str_small1)));
+    EXPECT_EQ(1, hinfo.compare(HINFO(hinfo_str_small2)));
+    EXPECT_EQ(-1, hinfo.compare(HINFO(hinfo_str_large1)));
+    EXPECT_EQ(-1, hinfo.compare(HINFO(hinfo_str_large2)));
+}
+
 }