From: Charles-Henri Bruyand Date: Wed, 27 Mar 2019 17:17:01 +0000 (+0100) Subject: all: DNSName avoid copying labels while converting to string X-Git-Tag: auth-4.2.0-rc3~19^2~21^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a640c4a6344454d5ac740e427201f54b97c1a2ef;p=pdns all: DNSName avoid copying labels while converting to string (cherry picked from commit 19164b93abc64a56140114c0416be6fa585dfab9) --- diff --git a/pdns/dnsname.cc b/pdns/dnsname.cc index 58f2d3a54..2eb1d9a12 100644 --- a/pdns/dnsname.cc +++ b/pdns/dnsname.cc @@ -170,8 +170,16 @@ std::string DNSName::toString(const std::string& separator, const bool trailing) std::string ret; ret.reserve(d_storage.size()); - for(const auto& s : getRawLabels()) { - ret+= escapeLabel(s) + separator; + + { + // iterate over the raw labels + const char* p = d_storage.c_str(); + const char* end = p + d_storage.size(); + + while (p < end && *p) { + ret += escapeLabel(p + 1, static_cast(*p)) + separator; + p += *p + 1; + } } if (!trailing) { ret.resize(ret.size() - separator.size()); @@ -341,9 +349,9 @@ bool DNSName::slowCanonCompare(const DNSName& rhs) const return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare()); } -vector DNSName::getRawLabels() const +vector DNSName::getRawLabels() const { - vector ret; + vector ret; ret.reserve(countLabels()); // 3www4ds9a2nl0 for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1) { @@ -400,8 +408,13 @@ bool DNSName::isHostname() const unsigned int DNSName::countLabels() const { unsigned int count=0; - for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1) + const unsigned char* p = reinterpret_cast(d_storage.c_str()); + const unsigned char* end = reinterpret_cast(p + d_storage.size()); + + while (p < end && *p) { ++count; + p += *p + 1; + } return count; } @@ -419,9 +432,17 @@ size_t hash_value(DNSName const& d) string DNSName::escapeLabel(const std::string& label) { - string ret; - ret.reserve(label.size()); // saves 15% on bulk .COM load - for(uint8_t p : label) { + return escapeLabel(label.c_str(), label.size()); +} + +string DNSName::escapeLabel(const char* orig, size_t len) +{ + std::string ret; + size_t pos = 0; + + ret.reserve(len); + while (pos < len) { + auto p = static_cast(orig[pos]); if(p=='.') ret+="\\."; else if(p=='\\') @@ -431,6 +452,7 @@ string DNSName::escapeLabel(const std::string& label) else { ret+="\\" + (boost::format("%03d") % (unsigned int)p).str(); } + ++pos; } return ret; } diff --git a/pdns/dnsname.hh b/pdns/dnsname.hh index e5f6b11db..ea540ce47 100644 --- a/pdns/dnsname.hh +++ b/pdns/dnsname.hh @@ -151,6 +151,7 @@ private: void packetParser(const char* p, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset); static std::string escapeLabel(const std::string& orig); + static std::string escapeLabel(const char* orig, size_t len); static std::string unescapeLabel(const std::string& orig); };