]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
this commit uglifies DNSName escaped representation parsing for tremendous speedup... 3455/head
authorbert hubert <bert.hubert@netherlabs.nl>
Thu, 25 Feb 2016 12:03:29 +0000 (13:03 +0100)
committerbert hubert <bert.hubert@netherlabs.nl>
Thu, 25 Feb 2016 12:03:29 +0000 (13:03 +0100)
Part of the uglification is that we now special case unescaped names, which are the vast majority of cases.
Simultaneously, this moves us back to DNSName boost::container::string on non-Apple platforms, which delivered another 15% speedup on general operations
Finally, an additional unit test is added.

pdns/dnslabeltext.rl
pdns/dnsname.cc
pdns/dnsname.hh
pdns/test-dnsname_cc.cc

index 21abd67448681887d92ca40c36bcbca56bc03956..fb3c3d210f278ecf7d2f06e50bbe421dd1b071bc 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <string>
+#include "dnsname.hh"
 #include "namespaces.hh"
 
 namespace {
@@ -81,79 +82,92 @@ vector<string> segmentDNSText(const string& input )
         return ret;
 };
 
-deque<string> segmentDNSName(const string& input )
+
+DNSName::string_t segmentDNSNameRaw(const char* realinput)
 {
-  // cerr<<"segmentDNSName("<<input<<")"<<endl; 
 %%{
-        machine dnsname;
+        machine dnsnameraw;
         write data;
         alphtype unsigned char;
 }%%
-       (void)dnsname_error;  // silence warnings
-       (void)dnsname_en_main;
+       (void)dnsnameraw_error;  // silence warnings
+       (void)dnsnameraw_en_main;
 
-        deque<string> ret;
+        DNSName::string_t ret;
 
-        string realinput;
-        if(input.empty() || input == ".") return ret;
+        if(!*realinput || *realinput == '.') {
+          ret.append(1, (char)0);
+          return ret;
+        }
 
-        if(input[input.size()-1]!='.') realinput=input+".";  // FIXME400 YOLO
-        else realinput=input;
+        unsigned int inputlen=strlen(realinput);
+        ret.reserve(inputlen+1);
 
-        const char *p = realinput.c_str(), *pe = realinput.c_str() + realinput.length();
+        const char *p = realinput, *pe = realinput + inputlen;
         const char* eof = pe;
         int cs;
         char val = 0;
-
-        string label;
-       label.reserve(10);
+        char labellen=0;
+        unsigned int lenpos=0;
         %%{
                 action labelEnd { 
-                        ret.push_back(label);
-                        label.clear();
+                        ret[lenpos]=labellen;
+                        labellen=0;
                 }
                 action labelBegin { 
-                        label.clear();
+                        lenpos=ret.size();
+                        ret.append(1, (char)0);
+                        labellen=0;
                 }
 
                 action reportEscaped {
                   char c = *fpc;
-                  label.append(1, c);
+                  ret.append(1, c);
+                  labellen++;
                 }
                 action reportEscapedNumber {
                   char c = *fpc;
                   val *= 10;
                   val += c-'0';
-                  
                 }
                 action doneEscapedNumber {
-                  label.append(1, val);
+                  ret.append(1, val);
+                  labellen++;
                   val=0;
                 }
                 
                 action reportPlain {
-                  label.append(1, *(fpc));
+                  ret.append(1, *(fpc));
+                  labellen++;
                 }
 
                 escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
                 plain = (extend-'\\'-'.') $ reportPlain;
                 labelElement = escaped | plain;            
 
-                main := ((labelElement+ '.') >labelBegin %labelEnd)+;
+                label = labelElement+ >labelBegin %labelEnd;
+
+                main:=  label ('.' label )* '.'?;
+
+                #main := labelElement((labelElement+ '.') >labelBegin %labelEnd)+;
+
+                #  label = (plain | escaped | escdecb)+ >label_init %label_fin;
+                #  dnsname := '.'? label ('.' label >label_sep)* '.'?;
 
                 # Initialize and execute.
                 write init;
                 write exec;
         }%%
 
-        if ( cs < dnsname_first_final ) {
-                throw runtime_error("Unable to parse DNS name '"+input+"' ('"+realinput+"'): cs="+std::to_string(cs));
+        if ( cs < dnsnameraw_first_final ) {
+                throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs));
         }
-
+        ret.append(1, (char)0);
         return ret;
 };
 
 
+
 #if 0
 int main()
 {
index ddc3998c077cafc5d8e91380e03e49fed13374f9..94f7c542abf97c285d89305d9b5a3e6ccbc5ec41 100644 (file)
@@ -17,19 +17,46 @@ std::ostream & operator<<(std::ostream &os, const DNSName& d)
   return os <<d.toString();
 }
 
-
 DNSName::DNSName(const char* p)
 {
   if(p[0]==0 || (p[0]=='.' && p[1]==0)) {
     d_storage.assign(1, (char)0);
   } else {
-    d_storage.reserve(strlen(p)+1);
-    auto labels = segmentDNSName(p);
-    for(const auto& e : labels)
-      appendRawLabel(e);
+    if(!strchr(p, '\\')) {
+      unsigned char lenpos=0;
+      unsigned char labellen=0;
+      unsigned int plen=strlen(p);
+      const char* const pbegin=p, *pend=p+plen;
+      d_storage.reserve(plen+1);
+      for(auto iter = pbegin; iter != pend; ) {
+        lenpos = d_storage.size();
+        if(*iter=='.')
+          throw std::runtime_error("Found . in wrong position in DNSName "+string(p));
+        d_storage.append(1, (char)0);
+        labellen=0;
+        auto begiter=iter;
+        for(; iter != pend && *iter!='.'; ++iter) {
+          labellen++;
+        }
+        d_storage.append(begiter,iter);
+        if(iter != pend)
+          ++iter;
+        if(labellen > 63)
+          throw std::range_error("label too long to append");
+
+        if(iter-pbegin > 254) // reserve two bytes, one for length and one for the root label
+          throw std::range_error("name too long to append");
+
+        d_storage[lenpos]=labellen;
+      }
+      d_storage.append(1, (char)0);
+    }
+    else
+      d_storage=segmentDNSNameRaw(p); 
   }
 }
 
+
 DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed)
 {
   if (offset >= len)
index 5c49c525f757e2c0316b0ef494399738c930b8e2..20b7d1c6e5b5d945933b3dbf906cde9267993f2c 100644 (file)
@@ -5,7 +5,11 @@
 #include <deque>
 #include <strings.h>
 #include <stdexcept>
+
+// it crashes on OSX..
+#ifndef __APPLE__
 #include <boost/container/string.hpp>
+#endif
 
 uint32_t burtleCI(const unsigned char* k, uint32_t lengh, uint32_t init);
 
@@ -38,7 +42,7 @@ class DNSName
 public:
   DNSName()  {}          //!< Constructs an *empty* DNSName, NOT the root!
   explicit DNSName(const char* p);      //!< Constructs from a human formatted, escaped presentation
-  explicit DNSName(const std::string& str) : DNSName(str.c_str()) {}   //!< Constructs from a human formatted, escaped presentation
+  explicit DNSName(const std::string& str) : DNSName(str.c_str()) {}; //!< Constructs from a human formatted, escaped presentation
   DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0, unsigned int* consumed=0); //!< Construct from a DNS Packet, taking the first question if offset=12
   
   bool isPartOf(const DNSName& rhs) const;   //!< Are we part of the rhs name?
@@ -95,10 +99,14 @@ public:
 
   inline bool canonCompare(const DNSName& rhs) const;
   bool slowCanonCompare(const DNSName& rhs) const;  
-private:
+
+#ifdef __APPLE__
+  typedef std::string string_t;
+#else
   typedef boost::container::string string_t;
-  // typedef std::string string_t;
+#endif
 
+private:
   string_t d_storage;
 
   void packetParser(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0, unsigned int* consumed=0, int depth=0);
@@ -256,3 +264,5 @@ namespace std {
         size_t operator () (const DNSName& dn) const { return dn.hash(0); }
     };
 }
+
+DNSName::string_t segmentDNSNameRaw(const char* input); // from ragel
index a3cdb3969e233cc4337544c61cbf4acb520dfb82..dc8a6388d563925161854ca596569ea1423b6265 100644 (file)
@@ -176,7 +176,10 @@ BOOST_AUTO_TEST_CASE(test_trim) {
 }
 
 BOOST_AUTO_TEST_CASE(test_toolong) {
+
   BOOST_CHECK_THROW(DNSName w("1234567890123456789012345678901234567890123456789012345678901234567890.com."), std::range_error);
+
+  BOOST_CHECK_THROW(DNSName w("12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.234567890.789012345678901.234567890.234567890.789012345678901.234567890.234567890.com."), std::range_error);
 }
 
 BOOST_AUTO_TEST_CASE(test_dnsstrings) {