Browse Source

bug fixes identified via unittests, some cleanups, added operator<<

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/jinmei-dnsrdata2@774 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
a9dc811752
2 changed files with 59 additions and 33 deletions
  1. 51 24
      src/lib/dns/cpp/rdata.cc
  2. 8 9
      src/lib/dns/cpp/rdata.h

+ 51 - 24
src/lib/dns/cpp/rdata.cc

@@ -19,6 +19,7 @@
 #include <sstream>
 #include <iomanip>
 #include <ios>
+#include <ostream>
 #include <vector>
 
 #include <stdint.h>
@@ -55,6 +56,10 @@ RdataPtr
 createRdata(const RRType& rrtype, const RRClass& rrclass,
             InputBuffer& buffer, size_t len)
 {
+    if (len > MAX_RDLENGTH) {
+        dns_throw(InvalidRdataLength, "RDLENGTH too large");
+    }
+
     size_t old_pos = buffer.getPosition();
 
     RdataPtr rdata =
@@ -103,6 +108,10 @@ struct GenericImpl {
 
 Generic::Generic(InputBuffer& buffer, size_t rdata_len)
 {
+    if (rdata_len > MAX_RDLENGTH) {
+        dns_throw(InvalidRdataLength, "RDLENGTH too large");
+    }
+
     vector<uint8_t> data(rdata_len);
     buffer.readData(&data[0], rdata_len);
     data.resize(rdata_len);
@@ -133,30 +142,35 @@ Generic::Generic(const string& rdata_string)
     if (rdlen < 0 || rdlen > 0xffff) {
         dns_throw(InvalidRdataLength, "RDATA length is out of range");
     }
+    iss >> ws;                  // skip any white spaces
 
+    // Hexadecimal encoding of RDATA: each segment must consist of an even
+    // number of hex digits.
     vector<uint8_t> data;
     while (!iss.eof() && data.size() < rdlen) {
-        string bytes;
-        iss >> bytes;
-        // Hexadecimal encoding of RDATA: each segment must consist of an even
-        // number of hex digits.
-        if ((iss.rdstate() & (ios::badbit | ios::failbit)) != 0 ||
-            (bytes.size() % 2) != 0) {
+        // extract two characters, which should compose a single byte of data.
+        char buf[2];
+        iss.read(buf, sizeof(buf));
+        if ((iss.rdstate() & (ios::badbit | ios::failbit)) != 0) {
             dns_throw(InvalidRdataText,
                       "Invalid hex encoding of generic RDATA");
         }
 
-        for (int pos = 0; pos < bytes.size(); pos += 2) {
-            istringstream iss_hex(bytes.substr(pos, 2));
-
-            unsigned int ch;
-            iss_hex >> hex >> ch;
-            if (iss_hex.rdstate() != ios::eofbit) {
-                dns_throw(InvalidRdataText,
-                          "Invalid hex encoding of generic RDATA");
-            }
-            data.push_back(ch);
+        // convert it to a single byte integer as a hex digit.
+        istringstream iss_byte(string(buf, sizeof(buf)));
+        unsigned int ch;
+        iss_byte >> hex >> ch;
+        if (iss_byte.rdstate() != ios::eofbit) {
+            dns_throw(InvalidRdataText,
+                      "Invalid hex encoding of generic RDATA");
         }
+        data.push_back(ch);
+        iss >> ws;              // skip spaces
+    }
+
+    if (!iss.eof()) {
+        dns_throw(InvalidRdataLength,
+                  "RDLENGTH is too small for generic RDATA");
     }
 
     if (data.size() != rdlen) {
@@ -178,7 +192,7 @@ Generic::operator=(const Generic& source)
         return (*this);
     }
 
-    GenericImpl* newimpl = new GenericImpl(*impl_);
+    GenericImpl* newimpl = new GenericImpl(*source.impl_);
     delete impl_;
     impl_ = newimpl;
 
@@ -223,17 +237,16 @@ Generic::toWire(MessageRenderer& renderer) const
     renderer.writeData(&impl_->data_[0], impl_->data_.size());
 }
 
-int
-Generic::compare(const Rdata& other) const
+namespace {
+inline int
+compare_internal(const GenericImpl& lhs, const GenericImpl& rhs)
 {
-    const Generic& other_rdata = dynamic_cast<const Generic&>(other);
-
-    size_t this_len = impl_->data_.size();
-    size_t other_len = other_rdata.impl_->data_.size();
+    size_t this_len = lhs.data_.size();
+    size_t other_len = rhs.data_.size();
     size_t len = (this_len < other_len) ? this_len : other_len;
     int cmp;
 
-    if ((cmp = memcmp(&impl_->data_[0], &other_rdata.impl_->data_[0], len))
+    if ((cmp = memcmp(&lhs.data_[0], &rhs.data_[0], len))
         != 0) {
         return (cmp);
     } else {
@@ -241,7 +254,21 @@ Generic::compare(const Rdata& other) const
                 (this_len < other_len) ? -1 : 1);
     }
 }
+}
+
+int
+Generic::compare(const Rdata& other) const
+{
+    const Generic& other_rdata = dynamic_cast<const Generic&>(other);
+
+    return (compare_internal(*impl_, *other_rdata.impl_));
+}
 
+std::ostream&
+operator<<(std::ostream& os, const Generic& rdata)
+{
+    return (os << rdata.toText());
+}
 } // end of namespace generic
 
 } // end of namespace rdata

+ 8 - 9
src/lib/dns/cpp/rdata.h

@@ -66,6 +66,10 @@ public:
 class Rdata;
 typedef boost::shared_ptr<Rdata> RdataPtr;
 
+/// \brief Possible maximum length of RDATA, which is the maximum unsigned
+/// 16 bit value.
+const size_t MAX_RDLENGTH = 65535;
+
 /// Abstract RDATA class
 class Rdata {
 protected:
@@ -106,14 +110,6 @@ public:
     /// be more polymorphic, but might involve significant overhead, especially
     /// for a large size of RDATA.
     virtual int compare(const Rdata& other) const = 0;
-
-    // not yet:
-    // methods specific derived classes: throw an exception by default
-    //virtual Address& getAddress() = 0;
-    //virtual Name& getName() = 0;
-
-    // polymorphic copy constructor (XXX should revisit it)
-    //virtual Rdata* copy() const = 0;
 };
 
 namespace generic {
@@ -123,7 +119,7 @@ class Generic : public Rdata {
 public:
     explicit Generic(const std::string& rdata_string);
     explicit Generic(InputBuffer& buffer, size_t rdata_len);
-    explicit Generic(const Generic& source);
+    Generic(const Generic& source);
     Generic& operator=(const Generic& source);
     virtual std::string toText() const;
     virtual void toWire(OutputBuffer& buffer) const;
@@ -137,6 +133,9 @@ public:
 private:
     GenericImpl* impl_;
 };
+
+std::ostream&
+operator<<(std::ostream& os, const Generic& rdata);
 } // end of namespace "generic"
 
 ///