Browse Source

[2384] Implement the units in TTLs

Michal 'vorner' Vaner 12 years ago
parent
commit
dc34527fc3
1 changed files with 73 additions and 8 deletions
  1. 73 8
      src/lib/dns/rrttl.cc

+ 73 - 8
src/lib/dns/rrttl.cc

@@ -21,22 +21,87 @@
 #include <dns/messagerenderer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rrttl.h>
 #include <dns/rrttl.h>
 
 
+#include <boost/lexical_cast.hpp>
+#include <algorithm>
+#include <cctype>
+
 using namespace std;
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::util;
 using namespace isc::util;
 
 
+namespace {
+
+// We wrap the C isalpha, because it seems to be overloaded with something.
+// Then the find_if doesn't work.
+bool
+myIsalpha(char c) {
+    return (isalpha(c));
+}
+
+// The conversion of units to their size
+struct Unit {
+    char unit;
+    uint32_t multiply;
+};
+
+Unit units[] = {
+    { 'S', 1 },
+    { 'M', 60 },
+    { 'H', 60 * 60 },
+    { 'D', 24 * 60 * 60 },
+    { 'W', 7 * 24 * 60 * 60 }
+};
+
+}
+
 namespace isc {
 namespace isc {
 namespace dns {
 namespace dns {
 
 
 RRTTL::RRTTL(const std::string& ttlstr) {
 RRTTL::RRTTL(const std::string& ttlstr) {
-    // Some systems (at least gcc-4.4) flow negative values over into
-    // unsigned integer, where older systems failed to parse. We want
-    // that failure here, so we extract into int64 and check the value
-    int64_t val;
-
-    istringstream iss(ttlstr);
-    iss >> dec >> val;
-    if (iss.rdstate() == ios::eofbit && val >= 0 && val <= 0xffffffff) {
+    int64_t val = 0;
+
+    const string::const_iterator end = ttlstr.end();
+    string::const_iterator pos = ttlstr.begin();
+
+    try {
+        while (pos != end) {
+            // Find the first unit, if there's any.
+            const string::const_iterator unit = find_if(pos, end,
+                                                        myIsalpha);
+            // Default multiplication if no unit.
+            uint32_t multiply = 1;
+            if (unit != end) {
+                // Find the unit and get the size.
+                bool found = false;
+                for (size_t i = 0; i < sizeof units / sizeof *units; ++i) {
+                    if (toupper(*unit) == units[i].unit) {
+                        found = true;
+                        multiply = units[i].multiply;
+                        break;
+                    }
+                }
+                if (!found) {
+                    isc_throw(InvalidRRTTL, "Unknown unit used: " << *unit);
+                }
+            }
+            // Now extract the number, defaut to 1 if there's no digit
+            const int64_t value = (unit == pos) ? 1 :
+                                  boost::lexical_cast<int64_t>(string(pos,
+                                                                      unit));
+            // Add what we found
+            val += multiply * value;
+            // Move to after the unit (if any). But make sure not to increment
+            // past end, which is, strictly speaking, illegal.
+            pos = unit;
+            if (pos != end) {
+                ++pos;
+            }
+        };
+    } catch (const boost::bad_lexical_cast&) {
+        isc_throw(InvalidRRTTL, "invalid TTL");
+    }
+
+    if (val >= 0 && val <= 0xffffffff) {
         ttlval_ = static_cast<uint32_t>(val);
         ttlval_ = static_cast<uint32_t>(val);
     } else {
     } else {
         isc_throw(InvalidRRTTL, "invalid TTL");
         isc_throw(InvalidRRTTL, "invalid TTL");