BIND 10 master, updated. 3b0ccfb2f23961e4cbddb9d0873bab0f4c1d4c3d [master] update ChangeLog entry for #1153
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Aug 24 02:29:44 UTC 2011
The branch, master has been updated
via 3b0ccfb2f23961e4cbddb9d0873bab0f4c1d4c3d (commit)
via 0a39659638fc68f60b95b102968d7d0ad75443ea (commit)
via 2684301690d59a41cd20d131491e0714d156fa7c (commit)
via af6328603521584ff62b25a6f86a923bba5a4f5e (commit)
via 28988a78d3b80c7f1080fce696acf176b74a29fe (commit)
via 353c08576b5c7fae46be834cb815df744ec2ba96 (commit)
via ec8fed8c805b513ea15ad76eb380c639dba88548 (commit)
via ce3be84b9f772fda5f08947fec92764119989019 (commit)
via 20871297d2aaae57acb79e987ff80a9020d608d1 (commit)
via 9bbf7837ed869bfa42849f433367b0471bf7bc58 (commit)
via e0215095818d30e80b59e99689f2cf0dfbbae841 (commit)
via 10cfb9ccd5b2eb489b14804e0ea9a73c80e697e6 (commit)
via acb5dff4449286422f23a7d5867b3bd792c888e5 (commit)
via 69eb1a250699f481427c2d12abf14314fee9e6eb (commit)
via a36be891057f7a2505db032768264c79f37f05e7 (commit)
via 23b1e8bb169e058dfb11b826b1b59d606d64ce20 (commit)
via c759e90e162192eda89c5046fa446891aac259c7 (commit)
via 21850ab947dbdf98b1d89afc36d8bcfc6001592e (commit)
from 5baa7aa73ad8d8d5250990a9e330b9b746659452 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 3b0ccfb2f23961e4cbddb9d0873bab0f4c1d4c3d
Author: chenzhengzhang <jerry.zzpku at gmail.com>
Date: Wed Aug 24 10:29:25 2011 +0800
[master] update ChangeLog entry for #1153
commit 0a39659638fc68f60b95b102968d7d0ad75443ea
Author: chenzhengzhang <jerry.zzpku at gmail.com>
Date: Wed Aug 24 10:27:40 2011 +0800
[master] merge trac1153: zonemgr exits on empty zones
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 5 +
src/bin/zonemgr/tests/zonemgr_test.py | 65 ++++++---
src/bin/zonemgr/zonemgr.py.in | 45 ++----
src/lib/dns/Makefile.am | 4 +
src/lib/dns/rdata/generic/detail/txt_like.h | 172 ++++++++++++++++++++
.../dns/rdata/generic/{cname_5.cc => spf_99.cc} | 65 +++++----
src/lib/dns/rdata/generic/{txt_16.h => spf_99.h} | 13 +-
src/lib/dns/rdata/generic/txt_16.cc | 121 +++-----------
src/lib/dns/rdata/generic/txt_16.h | 11 +-
9 files changed, 322 insertions(+), 179 deletions(-)
create mode 100644 src/lib/dns/rdata/generic/detail/txt_like.h
copy src/lib/dns/rdata/generic/{cname_5.cc => spf_99.cc} (53%)
copy src/lib/dns/rdata/generic/{txt_16.h => spf_99.h} (85%)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index f85fa0b..c7e6d62 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+284. [bug] jerry
+ b10-zonemgr: zonemgr will not terminate on empty zones, it will
+ log a warning and try to do zone transfer for them.
+ (Trac #1153, git 0a39659638fc68f60b95b102968d7d0ad75443ea)
+
283. [bug] zhanglikun
Make stats and boss processes wait for answer messages from each
other in block mode to avoid orphan answer messages, add an internal
diff --git a/src/bin/zonemgr/tests/zonemgr_test.py b/src/bin/zonemgr/tests/zonemgr_test.py
index 496ce6b..80e41b3 100644
--- a/src/bin/zonemgr/tests/zonemgr_test.py
+++ b/src/bin/zonemgr/tests/zonemgr_test.py
@@ -152,6 +152,16 @@ class TestZonemgrRefresh(unittest.TestCase):
self.assertTrue((time1 + 3600 * (1 - self.zone_refresh._refresh_jitter)) <= zone_timeout)
self.assertTrue(zone_timeout <= time2 + 3600)
+ # No soa rdata
+ self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"] = None
+ time3 = time.time()
+ self.zone_refresh._set_zone_retry_timer(ZONE_NAME_CLASS1_IN)
+ zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
+ time4 = time.time()
+ self.assertTrue((time3 + self.zone_refresh._lowerbound_retry * (1 - self.zone_refresh._refresh_jitter))
+ <= zone_timeout)
+ self.assertTrue(zone_timeout <= time4 + self.zone_refresh._lowerbound_retry)
+
def test_zone_not_exist(self):
self.assertFalse(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS1_IN))
self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS1_CH))
@@ -304,8 +314,8 @@ class TestZonemgrRefresh(unittest.TestCase):
def get_zone_soa2(zone_name, db_file):
return None
sqlite3_ds.get_zone_soa = get_zone_soa2
- self.assertRaises(ZonemgrException, self.zone_refresh.zonemgr_add_zone, \
- ZONE_NAME_CLASS1_IN)
+ self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS2_IN)
+ self.assertTrue(self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_IN]["zone_soa_rdata"] is None)
sqlite3_ds.get_zone_soa = old_get_zone_soa
def test_zone_handle_notify(self):
@@ -362,6 +372,15 @@ class TestZonemgrRefresh(unittest.TestCase):
self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_CH)
self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN)
+ old_get_zone_soa = sqlite3_ds.get_zone_soa
+ def get_zone_soa(zone_name, db_file):
+ return None
+ sqlite3_ds.get_zone_soa = get_zone_soa
+ self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
+ self.assertEqual(self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"],
+ ZONE_EXPIRED)
+ sqlite3_ds.get_zone_soa = old_get_zone_soa
+
def test_find_need_do_refresh_zone(self):
time1 = time.time()
self.zone_refresh._zonemgr_refresh_info = {
@@ -440,6 +459,8 @@ class TestZonemgrRefresh(unittest.TestCase):
"class": "IN" } ]
}
self.zone_refresh.update_config_data(config_data)
+ self.assertTrue(("example.net.", "IN") in
+ self.zone_refresh._zonemgr_refresh_info)
# update all values
config_data = {
@@ -479,14 +500,16 @@ class TestZonemgrRefresh(unittest.TestCase):
"secondary_zones": [ { "name": "doesnotexist",
"class": "IN" } ]
}
- self.assertRaises(ZonemgrException,
- self.zone_refresh.update_config_data,
- config_data)
- self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
- self.assertEqual(30, self.zone_refresh._lowerbound_retry)
- self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
- self.assertEqual(0.25, self.zone_refresh._refresh_jitter)
- self.assertEqual(0.35, self.zone_refresh._reload_jitter)
+ self.zone_refresh.update_config_data(config_data)
+ name_class = ("doesnotexist.", "IN")
+ self.assertTrue(self.zone_refresh._zonemgr_refresh_info[name_class]["zone_soa_rdata"]
+ is None)
+ # The other configs should be updated successfully
+ self.assertEqual(61, self.zone_refresh._lowerbound_refresh)
+ self.assertEqual(31, self.zone_refresh._lowerbound_retry)
+ self.assertEqual(19801, self.zone_refresh._max_transfer_timeout)
+ self.assertEqual(0.21, self.zone_refresh._refresh_jitter)
+ self.assertEqual(0.71, self.zone_refresh._reload_jitter)
# Make sure we accept 0 as a value
config_data = {
@@ -526,10 +549,11 @@ class TestZonemgrRefresh(unittest.TestCase):
self.zone_refresh._zonemgr_refresh_info)
# This one does not exist
config.set_zone_list_from_name_classes(["example.net", "CH"])
- self.assertRaises(ZonemgrException,
- self.zone_refresh.update_config_data, config)
- # So it should not affect the old ones
- self.assertTrue(("example.net.", "IN") in
+ self.zone_refresh.update_config_data(config)
+ self.assertFalse(("example.net.", "CH") in
+ self.zone_refresh._zonemgr_refresh_info)
+ # Simply skip loading soa for the zone, the other configs should be updated successful
+ self.assertFalse(("example.net.", "IN") in
self.zone_refresh._zonemgr_refresh_info)
# Make sure it works even when we "accidentally" forget the final dot
config.set_zone_list_from_name_classes([("example.net", "IN")])
@@ -596,15 +620,18 @@ class TestZonemgr(unittest.TestCase):
config_data3 = {"refresh_jitter" : 0.7}
self.zonemgr.config_handler(config_data3)
self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
- # The zone doesn't exist in database, it should be rejected
+ # The zone doesn't exist in database, simply skip loading soa for it and log an warning
self.zonemgr._zone_refresh = ZonemgrRefresh(None, "initdb.file", None,
config_data1)
config_data1["secondary_zones"] = [{"name": "nonexistent.example",
"class": "IN"}]
- self.assertNotEqual(self.zonemgr.config_handler(config_data1),
- {"result": [0]})
- # As it is rejected, the old value should be kept
- self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
+ self.assertEqual(self.zonemgr.config_handler(config_data1),
+ {"result": [0]})
+ # other configs should be updated successfully
+ name_class = ("nonexistent.example.", "IN")
+ self.assertTrue(self.zonemgr._zone_refresh._zonemgr_refresh_info[name_class]["zone_soa_rdata"]
+ is None)
+ self.assertEqual(0.1, self.zonemgr._config_data.get("refresh_jitter"))
def test_get_db_file(self):
self.assertEqual("initdb.file", self.zonemgr.get_db_file())
diff --git a/src/bin/zonemgr/zonemgr.py.in b/src/bin/zonemgr/zonemgr.py.in
index 87a0092..d4de6a8 100755
--- a/src/bin/zonemgr/zonemgr.py.in
+++ b/src/bin/zonemgr/zonemgr.py.in
@@ -142,7 +142,10 @@ class ZonemgrRefresh:
"""Set zone next refresh time after zone refresh fail.
now + retry - retry_jitter <= next_refresh_time <= now + retry
"""
- zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[RETRY_OFFSET])
+ if (self._get_zone_soa_rdata(zone_name_class) is not None):
+ zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[RETRY_OFFSET])
+ else:
+ zone_retry_time = 0.0
zone_retry_time = max(self._lowerbound_retry, zone_retry_time)
self._set_zone_timer(zone_name_class, zone_retry_time, self._refresh_jitter * zone_retry_time)
@@ -174,7 +177,8 @@ class ZonemgrRefresh:
raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
"belong to zonemgr" % zone_name_class)
# Is zone expired?
- if (self._zone_is_expired(zone_name_class)):
+ if ((self._get_zone_soa_rdata(zone_name_class) is None) or
+ self._zone_is_expired(zone_name_class)):
self._set_zone_state(zone_name_class, ZONE_EXPIRED)
else:
self._set_zone_state(zone_name_class, ZONE_OK)
@@ -200,17 +204,19 @@ class ZonemgrRefresh:
logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_LOAD_ZONE, zone_name_class[0], zone_name_class[1])
zone_info = {}
zone_soa = sqlite3_ds.get_zone_soa(str(zone_name_class[0]), self._db_file)
- if not zone_soa:
- logger.error(ZONEMGR_NO_SOA, zone_name_class[0], zone_name_class[1])
- raise ZonemgrException("[b10-zonemgr] zone (%s, %s) doesn't have soa." % zone_name_class)
- zone_info["zone_soa_rdata"] = zone_soa[7]
+ if zone_soa is None:
+ logger.warn(ZONEMGR_NO_SOA, zone_name_class[0], zone_name_class[1])
+ zone_info["zone_soa_rdata"] = None
+ zone_reload_time = 0.0
+ else:
+ zone_info["zone_soa_rdata"] = zone_soa[7]
+ zone_reload_time = float(zone_soa[7].split(" ")[RETRY_OFFSET])
zone_info["zone_state"] = ZONE_OK
zone_info["last_refresh_time"] = self._get_current_time()
self._zonemgr_refresh_info[zone_name_class] = zone_info
# Imposes some random jitters to avoid many zones need to do refresh at the same time.
- zone_reload_jitter = float(zone_soa[7].split(" ")[RETRY_OFFSET])
- zone_reload_jitter = max(self._lowerbound_retry, zone_reload_jitter)
- self._set_zone_timer(zone_name_class, zone_reload_jitter, self._reload_jitter * zone_reload_jitter)
+ zone_reload_time = max(self._lowerbound_retry, zone_reload_time)
+ self._set_zone_timer(zone_name_class, zone_reload_time, self._reload_jitter * zone_reload_time)
def _zone_is_expired(self, zone_name_class):
"""Judge whether a zone is expired or not."""
@@ -420,12 +426,6 @@ class ZonemgrRefresh:
def update_config_data(self, new_config):
""" update ZonemgrRefresh config """
- # TODO: we probably want to store all this info in a nice
- # class, so that we don't have to backup and restore every
- # single value.
- # TODO2: We also don't use get_default_value yet
- backup = self._zonemgr_refresh_info.copy()
-
# Get a new value, but only if it is defined (commonly used below)
# We don't use "value or default", because if value would be
# 0, we would take default
@@ -435,26 +435,21 @@ class ZonemgrRefresh:
else:
return default
- # store the values so we can restore them if there is a problem
- lowerbound_refresh_backup = self._lowerbound_refresh
self._lowerbound_refresh = val_or_default(
new_config.get('lowerbound_refresh'), self._lowerbound_refresh)
- lowerbound_retry_backup = self._lowerbound_retry
self._lowerbound_retry = val_or_default(
new_config.get('lowerbound_retry'), self._lowerbound_retry)
- max_transfer_timeout_backup = self._max_transfer_timeout
self._max_transfer_timeout = val_or_default(
new_config.get('max_transfer_timeout'), self._max_transfer_timeout)
- refresh_jitter_backup = self._refresh_jitter
self._refresh_jitter = val_or_default(
new_config.get('refresh_jitter'), self._refresh_jitter)
- reload_jitter_backup = self._reload_jitter
self._reload_jitter = val_or_default(
new_config.get('reload_jitter'), self._reload_jitter)
+
try:
required = {}
secondary_zones = new_config.get('secondary_zones')
@@ -469,6 +464,7 @@ class ZonemgrRefresh:
required[name_class] = True
# Add it only if it isn't there already
if not name_class in self._zonemgr_refresh_info:
+ # If we are not able to find it in database, log an warning
self.zonemgr_add_zone(name_class)
# Drop the zones that are no longer there
# Do it in two phases, python doesn't like deleting while iterating
@@ -478,14 +474,7 @@ class ZonemgrRefresh:
to_drop.append(old_zone)
for drop in to_drop:
del self._zonemgr_refresh_info[drop]
- # If we are not able to find it in database, restore the original
except:
- self._zonemgr_refresh_info = backup
- self._lowerbound_refresh = lowerbound_refresh_backup
- self._lowerbound_retry = lowerbound_retry_backup
- self._max_transfer_timeout = max_transfer_timeout_backup
- self._refresh_jitter = refresh_jitter_backup
- self._reload_jitter = reload_jitter_backup
raise
class Zonemgr:
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 3cd532f..3a23e23 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST += rdata/generic/cname_5.cc
EXTRA_DIST += rdata/generic/cname_5.h
EXTRA_DIST += rdata/generic/detail/nsec_bitmap.cc
EXTRA_DIST += rdata/generic/detail/nsec_bitmap.h
+EXTRA_DIST += rdata/generic/detail/txt_like.h
EXTRA_DIST += rdata/generic/dname_39.cc
EXTRA_DIST += rdata/generic/dname_39.h
EXTRA_DIST += rdata/generic/dnskey_48.cc
@@ -51,6 +52,8 @@ EXTRA_DIST += rdata/generic/rrsig_46.cc
EXTRA_DIST += rdata/generic/rrsig_46.h
EXTRA_DIST += rdata/generic/soa_6.cc
EXTRA_DIST += rdata/generic/soa_6.h
+EXTRA_DIST += rdata/generic/spf_99.cc
+EXTRA_DIST += rdata/generic/spf_99.h
EXTRA_DIST += rdata/generic/txt_16.cc
EXTRA_DIST += rdata/generic/txt_16.h
EXTRA_DIST += rdata/generic/minfo_14.cc
@@ -100,6 +103,7 @@ libdns___la_SOURCES += tsigkey.h tsigkey.cc
libdns___la_SOURCES += tsigrecord.h tsigrecord.cc
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc
+libdns___la_SOURCES += rdata/generic/detail/txt_like.h
libdns___la_CPPFLAGS = $(AM_CPPFLAGS)
# Most applications of libdns++ will only implicitly rely on libcryptolink,
diff --git a/src/lib/dns/rdata/generic/detail/txt_like.h b/src/lib/dns/rdata/generic/detail/txt_like.h
new file mode 100644
index 0000000..392a8ce
--- /dev/null
+++ b/src/lib/dns/rdata/generic/detail/txt_like.h
@@ -0,0 +1,172 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __TXT_LIKE_H
+#define __TXT_LIKE_H 1
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+using namespace std;
+using namespace isc::util;
+
+template<class Type, uint16_t typeCode>class TXTLikeImpl {
+public:
+ TXTLikeImpl(InputBuffer& buffer, size_t rdata_len) {
+ if (rdata_len > MAX_RDLENGTH) {
+ isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
+ }
+
+ if (rdata_len == 0) { // note that this couldn't happen in the loop.
+ isc_throw(DNSMessageFORMERR, "Error in parsing " <<
+ RRType(typeCode) << " RDATA: 0-length character string");
+ }
+
+ do {
+ const uint8_t len = buffer.readUint8();
+ if (rdata_len < len + 1) {
+ isc_throw(DNSMessageFORMERR, "Error in parsing " <<
+ RRType(typeCode) <<
+ " RDATA: character string length is too large: " <<
+ static_cast<int>(len));
+ }
+ vector<uint8_t> data(len + 1);
+ data[0] = len;
+ buffer.readData(&data[0] + 1, len);
+ string_list_.push_back(data);
+
+ rdata_len -= (len + 1);
+ } while (rdata_len > 0);
+ }
+
+ explicit TXTLikeImpl(const std::string& txtstr) {
+ // TBD: this is a simple, incomplete implementation that only supports
+ // a single character-string.
+
+ size_t length = txtstr.size();
+ size_t pos_begin = 0;
+
+ if (length > 1 && txtstr[0] == '"' && txtstr[length - 1] == '"') {
+ pos_begin = 1;
+ length -= 2;
+ }
+
+ if (length > MAX_CHARSTRING_LEN) {
+ isc_throw(CharStringTooLong, RRType(typeCode) <<
+ " RDATA construction from text:"
+ " string length is too long: " << length);
+ }
+
+ // TBD: right now, we don't support escaped characters
+ if (txtstr.find('\\') != string::npos) {
+ isc_throw(InvalidRdataText, RRType(typeCode) <<
+ " RDATA from text:"
+ " escaped character is currently not supported: " <<
+ txtstr);
+ }
+
+ vector<uint8_t> data;
+ data.reserve(length + 1);
+ data.push_back(length);
+ data.insert(data.end(), txtstr.begin() + pos_begin,
+ txtstr.begin() + pos_begin + length);
+ string_list_.push_back(data);
+ }
+
+ TXTLikeImpl(const TXTLikeImpl& other) :
+ string_list_(other.string_list_)
+ {}
+
+ void
+ toWire(OutputBuffer& buffer) const {
+ for (vector<vector<uint8_t> >::const_iterator it =
+ string_list_.begin();
+ it != string_list_.end();
+ ++it)
+ {
+ buffer.writeData(&(*it)[0], (*it).size());
+ }
+ }
+
+ void
+ toWire(AbstractMessageRenderer& renderer) const {
+ for (vector<vector<uint8_t> >::const_iterator it =
+ string_list_.begin();
+ it != string_list_.end();
+ ++it)
+ {
+ renderer.writeData(&(*it)[0], (*it).size());
+ }
+ }
+
+ string
+ toText() const {
+ string s;
+
+ // XXX: this implementation is not entirely correct. for example, it
+ // should escape double-quotes if they appear in the character string.
+ for (vector<vector<uint8_t> >::const_iterator it =
+ string_list_.begin();
+ it != string_list_.end();
+ ++it)
+ {
+ if (!s.empty()) {
+ s.push_back(' ');
+ }
+ s.push_back('"');
+ s.insert(s.end(), (*it).begin() + 1, (*it).end());
+ s.push_back('"');
+ }
+
+ return (s);
+ }
+
+ int
+ compare(const TXTLikeImpl& other) const {
+ // This implementation is not efficient. Revisit this (TBD).
+ OutputBuffer this_buffer(0);
+ toWire(this_buffer);
+ size_t this_len = this_buffer.getLength();
+
+ OutputBuffer other_buffer(0);
+ other.toWire(other_buffer);
+ const size_t other_len = other_buffer.getLength();
+
+ const size_t cmplen = min(this_len, other_len);
+ const int cmp = memcmp(this_buffer.getData(), other_buffer.getData(),
+ cmplen);
+ if (cmp != 0) {
+ return (cmp);
+ } else {
+ return ((this_len == other_len) ? 0 :
+ (this_len < other_len) ? -1 : 1);
+ }
+ }
+
+private:
+ /// Note: this is a prototype version; we may reconsider
+ /// this representation later.
+ std::vector<std::vector<uint8_t> > string_list_;
+};
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
+
+#endif // __TXT_LIKE_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/rdata/generic/spf_99.cc b/src/lib/dns/rdata/generic/spf_99.cc
new file mode 100644
index 0000000..492de98
--- /dev/null
+++ b/src/lib/dns/rdata/generic/spf_99.cc
@@ -0,0 +1,87 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <stdint.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include <util/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+
+using namespace std;
+using namespace isc::util;
+
+// BEGIN_ISC_NAMESPACE
+// BEGIN_RDATA_NAMESPACE
+
+#include <dns/rdata/generic/detail/txt_like.h>
+
+SPF&
+SPF::operator=(const SPF& source) {
+ if (impl_ == source.impl_) {
+ return (*this);
+ }
+
+ SPFImpl* newimpl = new SPFImpl(*source.impl_);
+ delete impl_;
+ impl_ = newimpl;
+
+ return (*this);
+}
+
+SPF::~SPF() {
+ delete impl_;
+}
+
+SPF::SPF(InputBuffer& buffer, size_t rdata_len) :
+ impl_(new SPFImpl(buffer, rdata_len))
+{}
+
+SPF::SPF(const std::string& txtstr) :
+ impl_(new SPFImpl(txtstr))
+{}
+
+SPF::SPF(const SPF& other) :
+ Rdata(), impl_(new SPFImpl(*other.impl_))
+{}
+
+void
+SPF::toWire(OutputBuffer& buffer) const {
+ impl_->toWire(buffer);
+}
+
+void
+SPF::toWire(AbstractMessageRenderer& renderer) const {
+ impl_->toWire(renderer);
+}
+
+string
+SPF::toText() const {
+ return (impl_->toText());
+}
+
+int
+SPF::compare(const Rdata& other) const {
+ const SPF& other_txt = dynamic_cast<const SPF&>(other);
+
+ return (impl_->compare(*other_txt.impl_));
+}
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/spf_99.h b/src/lib/dns/rdata/generic/spf_99.h
new file mode 100644
index 0000000..956adb9
--- /dev/null
+++ b/src/lib/dns/rdata/generic/spf_99.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// BEGIN_HEADER_GUARD
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include <dns/rdata.h>
+
+// BEGIN_ISC_NAMESPACE
+
+// BEGIN_COMMON_DECLARATIONS
+// END_COMMON_DECLARATIONS
+
+// BEGIN_RDATA_NAMESPACE
+
+template<class Type, uint16_t typeCode> class TXTLikeImpl;
+
+class SPF : public Rdata {
+public:
+ // BEGIN_COMMON_MEMBERS
+ // END_COMMON_MEMBERS
+
+ SPF& operator=(const SPF& source);
+ ~SPF();
+
+private:
+ typedef TXTLikeImpl<SPF, 99> SPFImpl;
+ SPFImpl* impl_;
+};
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
+// END_HEADER_GUARD
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/rdata/generic/txt_16.cc b/src/lib/dns/rdata/generic/txt_16.cc
index ac2ba8a..418bc05 100644
--- a/src/lib/dns/rdata/generic/txt_16.cc
+++ b/src/lib/dns/rdata/generic/txt_16.cc
@@ -30,130 +30,57 @@ using namespace isc::util;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
-TXT::TXT(InputBuffer& buffer, size_t rdata_len) {
- if (rdata_len > MAX_RDLENGTH) {
- isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
- }
+#include <dns/rdata/generic/detail/txt_like.h>
- if (rdata_len == 0) { // note that this couldn't happen in the loop.
- isc_throw(DNSMessageFORMERR,
- "Error in parsing TXT RDATA: 0-length character string");
+TXT&
+TXT::operator=(const TXT& source) {
+ if (impl_ == source.impl_) {
+ return (*this);
}
- do {
- const uint8_t len = buffer.readUint8();
- if (rdata_len < len + 1) {
- isc_throw(DNSMessageFORMERR,
- "Error in parsing TXT RDATA: character string length "
- "is too large: " << static_cast<int>(len));
- }
- vector<uint8_t> data(len + 1);
- data[0] = len;
- buffer.readData(&data[0] + 1, len);
- string_list_.push_back(data);
-
- rdata_len -= (len + 1);
- } while (rdata_len > 0);
-}
-
-TXT::TXT(const std::string& txtstr) {
- // TBD: this is a simple, incomplete implementation that only supports
- // a single character-string.
+ TXTImpl* newimpl = new TXTImpl(*source.impl_);
+ delete impl_;
+ impl_ = newimpl;
- size_t length = txtstr.size();
- size_t pos_begin = 0;
-
- if (length > 1 && txtstr[0] == '"' && txtstr[length - 1] == '"') {
- pos_begin = 1;
- length -= 2;
- }
+ return (*this);
+}
- if (length > MAX_CHARSTRING_LEN) {
- isc_throw(CharStringTooLong, "TXT RDATA construction from text: "
- "string length is too long: " << length);
- }
+TXT::~TXT() {
+ delete impl_;
+}
- // TBD: right now, we don't support escaped characters
- if (txtstr.find('\\') != string::npos) {
- isc_throw(InvalidRdataText, "TXT RDATA from text: "
- "escaped character is currently not supported: " << txtstr);
- }
+TXT::TXT(InputBuffer& buffer, size_t rdata_len) :
+ impl_(new TXTImpl(buffer, rdata_len))
+{}
- vector<uint8_t> data;
- data.reserve(length + 1);
- data.push_back(length);
- data.insert(data.end(), txtstr.begin() + pos_begin,
- txtstr.begin() + pos_begin + length);
- string_list_.push_back(data);
-}
+TXT::TXT(const std::string& txtstr) :
+ impl_(new TXTImpl(txtstr))
+{}
TXT::TXT(const TXT& other) :
- Rdata(), string_list_(other.string_list_)
+ Rdata(), impl_(new TXTImpl(*other.impl_))
{}
void
TXT::toWire(OutputBuffer& buffer) const {
- for (vector<vector<uint8_t> >::const_iterator it = string_list_.begin();
- it != string_list_.end();
- ++it)
- {
- buffer.writeData(&(*it)[0], (*it).size());
- }
+ impl_->toWire(buffer);
}
void
TXT::toWire(AbstractMessageRenderer& renderer) const {
- for (vector<vector<uint8_t> >::const_iterator it = string_list_.begin();
- it != string_list_.end();
- ++it)
- {
- renderer.writeData(&(*it)[0], (*it).size());
- }
+ impl_->toWire(renderer);
}
string
TXT::toText() const {
- string s;
-
- // XXX: this implementation is not entirely correct. for example, it
- // should escape double-quotes if they appear in the character string.
- for (vector<vector<uint8_t> >::const_iterator it = string_list_.begin();
- it != string_list_.end();
- ++it)
- {
- if (!s.empty()) {
- s.push_back(' ');
- }
- s.push_back('"');
- s.insert(s.end(), (*it).begin() + 1, (*it).end());
- s.push_back('"');
- }
-
- return (s);
+ return (impl_->toText());
}
int
TXT::compare(const Rdata& other) const {
const TXT& other_txt = dynamic_cast<const TXT&>(other);
- // This implementation is not efficient. Revisit this (TBD).
- OutputBuffer this_buffer(0);
- toWire(this_buffer);
- size_t this_len = this_buffer.getLength();
-
- OutputBuffer other_buffer(0);
- other_txt.toWire(other_buffer);
- const size_t other_len = other_buffer.getLength();
-
- const size_t cmplen = min(this_len, other_len);
- const int cmp = memcmp(this_buffer.getData(), other_buffer.getData(),
- cmplen);
- if (cmp != 0) {
- return (cmp);
- } else {
- return ((this_len == other_len) ? 0 :
- (this_len < other_len) ? -1 : 1);
- }
+ return (impl_->compare(*other_txt.impl_));
}
// END_RDATA_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/txt_16.h b/src/lib/dns/rdata/generic/txt_16.h
index b4c791f..d99d69b 100644
--- a/src/lib/dns/rdata/generic/txt_16.h
+++ b/src/lib/dns/rdata/generic/txt_16.h
@@ -28,14 +28,19 @@
// BEGIN_RDATA_NAMESPACE
+template<class Type, uint16_t typeCode> class TXTLikeImpl;
+
class TXT : public Rdata {
public:
// BEGIN_COMMON_MEMBERS
// END_COMMON_MEMBERS
+
+ TXT& operator=(const TXT& source);
+ ~TXT();
+
private:
- /// Note: this is a prototype version; we may reconsider
- /// this representation later.
- std::vector<std::vector<uint8_t> > string_list_;
+ typedef TXTLikeImpl<TXT, 16> TXTImpl;
+ TXTImpl* impl_;
};
// END_RDATA_NAMESPACE
More information about the bind10-changes
mailing list