BIND 10 master, updated. e533dc83ccb7bf541e53f753c28a52248d7b195b [master] update changelog
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Dec 2 10:14:14 UTC 2011
The branch, master has been updated
via e533dc83ccb7bf541e53f753c28a52248d7b195b (commit)
via 2ae72d76c74f61a67590722c73ebbf631388acbd (commit)
via 0b5da8bd0800bfa3744e23c367cee2c38de7a497 (commit)
via eb6053d466fcea08fa66205d598d316e550863c8 (commit)
via 42d4a37a121ea7df3440268fe15995267fb66b12 (commit)
via 1b186f0a6fc242fa6dff08944ef43b60010d3631 (commit)
via b6568546ccdac044fd30200a54708f9418e7af9d (commit)
via 07b884ef0f72044fa5a5fd661ab068794ff68ca6 (commit)
from 1ecbd2b16b44b6439030fd245f951fe5a538ecc5 (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 e533dc83ccb7bf541e53f753c28a52248d7b195b
Author: Jelte Jansen <jelte at isc.org>
Date: Fri Dec 2 11:14:05 2011 +0100
[master] update changelog
commit 2ae72d76c74f61a67590722c73ebbf631388acbd
Merge: 1ecbd2b16b44b6439030fd245f951fe5a538ecc5 0b5da8bd0800bfa3744e23c367cee2c38de7a497
Author: Jelte Jansen <jelte at isc.org>
Date: Fri Dec 2 11:12:59 2011 +0100
Merge branch 'trac1278'
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 8 +
src/lib/datasrc/database.cc | 12 +-
src/lib/dns/Makefile.am | 1 +
src/lib/dns/python/Makefile.am | 1 +
src/lib/dns/python/pydnspp.cc | 17 ++
src/lib/dns/python/serial_python.cc | 281 ++++++++++++++++++++
.../python/{opcode_python.h => serial_python.h} | 32 ++--
src/lib/dns/python/tests/Makefile.am | 1 +
src/lib/dns/python/tests/serial_python_test.py | 109 ++++++++
src/lib/dns/rdata/generic/soa_6.cc | 4 +-
src/lib/dns/rdata/generic/soa_6.h | 3 +-
src/lib/dns/serial.cc | 76 ++++++
src/lib/dns/serial.h | 155 +++++++++++
src/lib/dns/tests/Makefile.am | 1 +
src/lib/dns/tests/rdata_soa_unittest.cc | 2 +-
src/lib/dns/tests/serial_unittest.cc | 179 +++++++++++++
16 files changed, 856 insertions(+), 26 deletions(-)
create mode 100644 src/lib/dns/python/serial_python.cc
copy src/lib/dns/python/{opcode_python.h => serial_python.h} (66%)
create mode 100644 src/lib/dns/python/tests/serial_python_test.py
create mode 100644 src/lib/dns/serial.cc
create mode 100644 src/lib/dns/serial.h
create mode 100644 src/lib/dns/tests/serial_unittest.cc
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index d7cbf83..eb4746f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+336. [func] jelte
+ libdns++ (and its python wrapper) now includes a class Serial, for
+ SOA SERIAL comparison and addition. Operations on instances of this
+ class follow the specification from RFC 1982.
+ Rdata::SOA::getSerial() now returns values of this type (and not
+ uint32_t).
+ (Trac #1278, git 2ae72d76c74f61a67590722c73ebbf631388acbd)
+
335. [bug]* jelte
The DataSourceClientContainer class that dynamically loads
datasource backend libraries no longer provides just a .so file name
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index 053d4bc..45ce0c2 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -843,7 +843,7 @@ public:
committed_(false), accessor_(accessor), zone_id_(zone_id),
db_name_(accessor->getDBName()), zone_name_(zone_name.toText()),
zone_class_(zone_class), journaling_(journaling),
- diff_phase_(NOT_STARTED),
+ diff_phase_(NOT_STARTED), serial_(0),
finder_(new DatabaseClient::Finder(accessor_, zone_id_, zone_name))
{
logger.debug(DBG_TRACE_DATA, DATASRC_DATABASE_UPDATER_CREATED)
@@ -896,7 +896,7 @@ private:
ADD
};
DiffPhase diff_phase_;
- uint32_t serial_;
+ Serial serial_;
boost::scoped_ptr<DatabaseClient::Finder> finder_;
// This is a set of validation checks commonly used for addRRset() and
@@ -985,8 +985,8 @@ DatabaseUpdater::addRRset(const RRset& rrset) {
columns[Accessor::ADD_RDATA] = it->getCurrent().toText();
if (journaling_) {
journal[Accessor::DIFF_RDATA] = columns[Accessor::ADD_RDATA];
- accessor_->addRecordDiff(zone_id_, serial_, Accessor::DIFF_ADD,
- journal);
+ accessor_->addRecordDiff(zone_id_, serial_.getValue(),
+ Accessor::DIFF_ADD, journal);
}
accessor_->addRecordToZone(columns);
}
@@ -1023,8 +1023,8 @@ DatabaseUpdater::deleteRRset(const RRset& rrset) {
params[Accessor::DEL_RDATA] = it->getCurrent().toText();
if (journaling_) {
journal[Accessor::DIFF_RDATA] = params[Accessor::DEL_RDATA];
- accessor_->addRecordDiff(zone_id_, serial_, Accessor::DIFF_DELETE,
- journal);
+ accessor_->addRecordDiff(zone_id_, serial_.getValue(),
+ Accessor::DIFF_DELETE, journal);
}
accessor_->deleteRecordInZone(params);
}
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 0d2bffd..00faf40 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -102,6 +102,7 @@ libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
libdns___la_SOURCES += rrttl.h rrttl.cc
libdns___la_SOURCES += rrtype.cc
libdns___la_SOURCES += question.h question.cc
+libdns___la_SOURCES += serial.h serial.cc
libdns___la_SOURCES += tsig.h tsig.cc
libdns___la_SOURCES += tsigerror.h tsigerror.cc
libdns___la_SOURCES += tsigkey.h tsigkey.cc
diff --git a/src/lib/dns/python/Makefile.am b/src/lib/dns/python/Makefile.am
index 3b89358..dd14991 100644
--- a/src/lib/dns/python/Makefile.am
+++ b/src/lib/dns/python/Makefile.am
@@ -12,6 +12,7 @@ libpydnspp_la_SOURCES += rrclass_python.cc rrclass_python.h
libpydnspp_la_SOURCES += rrtype_python.cc rrtype_python.h
libpydnspp_la_SOURCES += rrttl_python.cc rrttl_python.h
libpydnspp_la_SOURCES += rdata_python.cc rdata_python.h
+libpydnspp_la_SOURCES += serial_python.cc serial_python.h
libpydnspp_la_SOURCES += messagerenderer_python.cc messagerenderer_python.h
libpydnspp_la_SOURCES += rcode_python.cc rcode_python.h
libpydnspp_la_SOURCES += opcode_python.cc opcode_python.h
diff --git a/src/lib/dns/python/pydnspp.cc b/src/lib/dns/python/pydnspp.cc
index 0a7d8e5..212141c 100644
--- a/src/lib/dns/python/pydnspp.cc
+++ b/src/lib/dns/python/pydnspp.cc
@@ -49,6 +49,7 @@
#include "rrset_python.h"
#include "rrttl_python.h"
#include "rrtype_python.h"
+#include "serial_python.h"
#include "tsigerror_python.h"
#include "tsigkey_python.h"
#include "tsig_python.h"
@@ -492,6 +493,18 @@ initModulePart_RRType(PyObject* mod) {
}
bool
+initModulePart_Serial(PyObject* mod) {
+ if (PyType_Ready(&serial_type) < 0) {
+ return (false);
+ }
+ Py_INCREF(&serial_type);
+ PyModule_AddObject(mod, "Serial",
+ reinterpret_cast<PyObject*>(&serial_type));
+
+ return (true);
+}
+
+bool
initModulePart_TSIGError(PyObject* mod) {
if (PyType_Ready(&tsigerror_type) < 0) {
return (false);
@@ -804,6 +817,10 @@ PyInit_pydnspp(void) {
return (NULL);
}
+ if (!initModulePart_Serial(mod)) {
+ return (NULL);
+ }
+
if (!initModulePart_TSIGKey(mod)) {
return (NULL);
}
diff --git a/src/lib/dns/python/serial_python.cc b/src/lib/dns/python/serial_python.cc
new file mode 100644
index 0000000..e2bd809
--- /dev/null
+++ b/src/lib/dns/python/serial_python.cc
@@ -0,0 +1,281 @@
+// 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.
+
+#include <Python.h>
+
+#include <dns/serial.h>
+#include <util/python/pycppwrapper_util.h>
+
+#include "serial_python.h"
+#include "pydnspp_common.h"
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::python;
+using namespace isc::util;
+using namespace isc::util::python;
+
+namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_Serial : public PyObject {
+public:
+ s_Serial() : cppobj(NULL) {};
+ isc::dns::Serial* cppobj;
+};
+
+typedef CPPPyObjectContainer<s_Serial, Serial> SerialContainer;
+
+PyObject* Serial_str(PyObject* self);
+PyObject* Serial_getValue(s_Serial* self);
+PyObject* Serial_richcmp(s_Serial* self, s_Serial* other, int op);
+PyObject* Serial_add(PyObject *right, PyObject *left);
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef Serial_methods[] = {
+ { "get_value", reinterpret_cast<PyCFunction>(Serial_getValue), METH_NOARGS,
+ "Returns the Serial value as an integer" },
+ { NULL, NULL, 0, NULL }
+};
+
+// For overriding the + operator. We do not define any other operators for
+// this type.
+PyNumberMethods Serial_NumberMethods = {
+ Serial_add, //nb_add;
+ NULL, //nb_subtract;
+ NULL, //nb_multiply;
+ NULL, //nb_remainder;
+ NULL, //nb_divmod;
+ NULL, //nb_power;
+ NULL, //nb_negative;
+ NULL, //nb_positive;
+ NULL, //nb_absolute;
+ NULL, //nb_bool;
+ NULL, //nb_invert;
+ NULL, //nb_lshift;
+ NULL, //nb_rshift;
+ NULL, //nb_and;
+ NULL, //nb_xor;
+ NULL, //nb_or;
+ NULL, //nb_int;
+ NULL, //nb_reserved;
+ NULL, //nb_float;
+
+ NULL, //nb_inplace_add;
+ NULL, //nb_inplace_subtract;
+ NULL, //nb_inplace_multiply;
+ NULL, //nb_inplace_remainder;
+ NULL, //nb_inplace_power;
+ NULL, //nb_inplace_lshift;
+ NULL, //nb_inplace_rshift;
+ NULL, //nb_inplace_and;
+ NULL, //nb_inplace_xor;
+ NULL, //nb_inplace_or;
+
+ NULL, //nb_floor_divide;
+ NULL, //nb_true_divide;
+ NULL, //nb_inplace_floor_divide;
+ NULL, //nb_inplace_true_divide;
+
+ NULL, //nb_index;
+};
+
+int
+Serial_init(s_Serial* self, PyObject* args) {
+ long long i;
+ if (PyArg_ParseTuple(args, "L", &i)) {
+ PyErr_Clear();
+ if (i < 0 || i > 0xffffffff) {
+ PyErr_SetString(PyExc_ValueError, "Serial number out of range");
+ return (-1);
+ }
+ self->cppobj = new Serial(i);
+ return (0);
+ } else {
+ return (-1);
+ }
+}
+
+void
+Serial_destroy(s_Serial* self) {
+ delete self->cppobj;
+ self->cppobj = NULL;
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+Serial_getValue(s_Serial* self) {
+ return (Py_BuildValue("I", self->cppobj->getValue()));
+}
+
+PyObject*
+Serial_str(PyObject* po_self) {
+ const s_Serial* const self = static_cast<s_Serial*>(po_self);
+ return (PyUnicode_FromFormat("%u", self->cppobj->getValue()));
+}
+
+PyObject*
+Serial_richcmp(s_Serial* self, s_Serial* other, int op) {
+ bool c = false;
+
+ // Check for null and if the types match. If different type,
+ // simply return False
+ if (!other || (self->ob_type != other->ob_type)) {
+ Py_RETURN_FALSE;
+ }
+
+ switch (op) {
+ case Py_LT:
+ c = *self->cppobj < *other->cppobj;
+ break;
+ case Py_LE:
+ c = *self->cppobj <= *other->cppobj;
+ break;
+ case Py_EQ:
+ c = *self->cppobj == *other->cppobj;
+ break;
+ case Py_NE:
+ c = *self->cppobj != *other->cppobj;
+ break;
+ case Py_GT:
+ c = *self->cppobj > *other->cppobj;
+ break;
+ case Py_GE:
+ c = *self->cppobj >= *other->cppobj;
+ break;
+ }
+ if (c) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+}
+
+PyObject *
+Serial_add(PyObject *left, PyObject *right) {
+ // Either can be either a serial or a long, as long as one of them is a
+ // serial
+ if (PySerial_Check(left) && PySerial_Check(right)) {
+ return (createSerialObject(PySerial_ToSerial(left) +
+ PySerial_ToSerial(right)));
+ } else if (PySerial_Check(left) && PyLong_Check(right)) {
+ return (createSerialObject(PySerial_ToSerial(left) +
+ PyLong_AsLong(right)));
+ } else if (PyLong_Check(left) && PySerial_Check(right)) {
+ return (createSerialObject(PySerial_ToSerial(right) +
+ PyLong_AsLong(left)));
+ } else {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+}
+
+} // end anonymous namespace
+
+namespace isc {
+namespace dns {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_Serial
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject serial_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "pydnspp.Serial",
+ sizeof(s_Serial), // tp_basicsize
+ 0, // tp_itemsize
+ (destructor)Serial_destroy, // tp_dealloc
+ NULL, // tp_print
+ NULL, // tp_getattr
+ NULL, // tp_setattr
+ NULL, // tp_reserved
+ NULL, // tp_repr
+ &Serial_NumberMethods, // tp_as_number
+ NULL, // tp_as_sequence
+ NULL, // tp_as_mapping
+ NULL, // tp_hash
+ NULL, // tp_call
+ Serial_str, // tp_str
+ NULL, // tp_getattro
+ NULL, // tp_setattro
+ NULL, // tp_as_buffer
+ Py_TPFLAGS_DEFAULT, // tp_flags
+ "The Serial class encapsulates Serials used in DNS SOA records.\n\n"
+ "This is a straightforward class; an Serial object simply maintains a "
+ "32-bit unsigned integer corresponding to the SOA SERIAL value. The "
+ "main purpose of this class is to provide serial number arithmetic, as "
+ "described in RFC 1892. Objects of this type can be compared and added "
+ "to each other, as described in RFC 1892. Apart from str(), get_value(), "
+ "comparison operators, and the + operator, no other operations are "
+ "defined for this type.",
+ NULL, // tp_traverse
+ NULL, // tp_clear
+ (richcmpfunc)Serial_richcmp, // tp_richcompare
+ 0, // tp_weaklistoffset
+ NULL, // tp_iter
+ NULL, // tp_iternext
+ Serial_methods, // tp_methods
+ NULL, // tp_members
+ NULL, // tp_getset
+ NULL, // tp_base
+ NULL, // tp_dict
+ NULL, // tp_descr_get
+ NULL, // tp_descr_set
+ 0, // tp_dictoffset
+ (initproc)Serial_init, // tp_init
+ NULL, // tp_alloc
+ PyType_GenericNew, // tp_new
+ NULL, // tp_free
+ NULL, // tp_is_gc
+ NULL, // tp_bases
+ NULL, // tp_mro
+ NULL, // tp_cache
+ NULL, // tp_subclasses
+ NULL, // tp_weaklist
+ NULL, // tp_del
+ 0 // tp_version_tag
+};
+
+PyObject*
+createSerialObject(const Serial& source) {
+ SerialContainer container(PyObject_New(s_Serial, &serial_type));
+ container.set(new Serial(source));
+ return (container.release());
+}
+
+bool
+PySerial_Check(PyObject* obj) {
+ if (obj == NULL) {
+ isc_throw(PyCPPWrapperException,
+ "obj argument NULL in Serial typecheck");
+ }
+ return (PyObject_TypeCheck(obj, &serial_type));
+}
+
+const Serial&
+PySerial_ToSerial(const PyObject* serial_obj) {
+ if (serial_obj == NULL) {
+ isc_throw(PyCPPWrapperException,
+ "obj argument NULL in Serial PyObject conversion");
+ }
+ const s_Serial* serial = static_cast<const s_Serial*>(serial_obj);
+ return (*serial->cppobj);
+}
+
+} // namespace python
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/python/serial_python.h b/src/lib/dns/python/serial_python.h
new file mode 100644
index 0000000..48b5199
--- /dev/null
+++ b/src/lib/dns/python/serial_python.h
@@ -0,0 +1,64 @@
+// 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 __PYTHON_SERIAL_H
+#define __PYTHON_SERIAL_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace dns {
+class Serial;
+
+namespace python {
+
+extern PyTypeObject serial_type;
+
+/// This is a simple shortcut to create a python Serial object (in the
+/// form of a pointer to PyObject) with minimal exception safety.
+/// On success, it returns a valid pointer to PyObject with a reference
+/// counter of 1; if something goes wrong it throws an exception (it never
+/// returns a NULL pointer).
+/// This function is expected to be called within a try block
+/// followed by necessary setup for python exception.
+PyObject* createSerialObject(const Serial& source);
+
+/// \brief Checks if the given python object is a Serial object
+///
+/// \exception PyCPPWrapperException if obj is NULL
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Serial, false otherwise
+bool PySerial_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Serial object contained within the given
+/// Python object.
+///
+/// \note The given object MUST be of type Serial; this can be checked with
+/// either the right call to ParseTuple("O!"), or with PySerial_Check()
+///
+/// \note This is not a copy; if the Serial is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param Serial_obj The Serial object to convert
+const Serial& PySerial_ToSerial(const PyObject* Serial_obj);
+
+} // namespace python
+} // namespace dns
+} // namespace isc
+#endif // __PYTHON_SERIAL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/dns/python/tests/Makefile.am b/src/lib/dns/python/tests/Makefile.am
index d1273f3..3338727 100644
--- a/src/lib/dns/python/tests/Makefile.am
+++ b/src/lib/dns/python/tests/Makefile.am
@@ -11,6 +11,7 @@ PYTESTS += rrclass_python_test.py
PYTESTS += rrset_python_test.py
PYTESTS += rrttl_python_test.py
PYTESTS += rrtype_python_test.py
+PYTESTS += serial_python_test.py
PYTESTS += tsig_python_test.py
PYTESTS += tsig_rdata_python_test.py
PYTESTS += tsigerror_python_test.py
diff --git a/src/lib/dns/python/tests/serial_python_test.py b/src/lib/dns/python/tests/serial_python_test.py
new file mode 100644
index 0000000..4e87f3d
--- /dev/null
+++ b/src/lib/dns/python/tests/serial_python_test.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2011 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+#
+# Tests for the rrttl part of the pydnspp module
+#
+
+import unittest
+import os
+from pydnspp import *
+
+class SerialTest(unittest.TestCase):
+ def setUp(self):
+ self.one = Serial(1)
+ self.one_2 = Serial(1)
+ self.two = Serial(2)
+ self.date_zero = Serial(1980120100)
+ self.date_one = Serial(1980120101)
+ self.zero = Serial(0)
+ self.highest = Serial(4294967295)
+ self.number_low = Serial(12345)
+ self.number_medium = Serial(2000000000)
+ self.number_high = Serial(4000000000)
+
+ def test_init(self):
+ self.assertRaises(ValueError, Serial, -1)
+ self.assertRaises(ValueError, Serial, 4294967296)
+ self.assertRaises(ValueError, Serial, 4294967297)
+ self.assertRaises(ValueError, Serial, 100000000000)
+
+ def test_get_value(self):
+ self.assertEqual(1, self.one.get_value())
+ self.assertNotEqual(2, self.one_2.get_value())
+ self.assertEqual(2, self.two.get_value())
+ self.assertEqual(1980120100, self.date_zero.get_value())
+ self.assertEqual(1980120101, self.date_one.get_value())
+ self.assertEqual(0, self.zero.get_value())
+ self.assertEqual(4294967295, self.highest.get_value())
+ self.assertEqual(12345, self.number_low.get_value())
+ self.assertEqual(2000000000, self.number_medium.get_value())
+ self.assertEqual(4000000000, self.number_high.get_value())
+
+ def test_str(self):
+ self.assertEqual('1', str(self.one))
+ self.assertNotEqual('2', str(self.one_2))
+ self.assertEqual('2', str(self.two))
+ self.assertEqual('1980120100', str(self.date_zero))
+ self.assertEqual('1980120101', str(self.date_one))
+ self.assertEqual('0', str(self.zero))
+ self.assertEqual('4294967295', str(self.highest))
+ self.assertEqual('12345', str(self.number_low))
+ self.assertEqual('2000000000', str(self.number_medium))
+ self.assertEqual('4000000000', str(self.number_high))
+
+ def test_equals(self):
+ self.assertEqual(self.one, self.one)
+ self.assertEqual(self.one, self.one_2)
+ self.assertNotEqual(self.one, self.two)
+ self.assertNotEqual(self.two, self.one)
+ self.assertEqual(Serial(12345), self.number_low)
+ self.assertNotEqual(Serial(12346), self.number_low)
+
+ def test_compare(self):
+ # These should be true/false even without serial arithmetic
+ self.assertLessEqual(self.one, self.one)
+ self.assertLessEqual(self.one, self.one_2)
+ self.assertLess(self.one, self.two)
+ self.assertLessEqual(self.one, self.two)
+ self.assertGreater(self.two, self.one)
+ self.assertGreaterEqual(self.two, self.two)
+ self.assertLess(self.one, self.number_low)
+ self.assertLess(self.number_low, self.number_medium)
+ self.assertLess(self.number_medium, self.number_high)
+
+ # These should 'wrap'
+ self.assertGreater(self.zero, self.highest)
+ self.assertLess(self.highest, self.one)
+ self.assertLess(self.number_high, self.number_low)
+
+ def test_addition(self):
+ self.assertEqual(self.two, self.one + self.one)
+ self.assertEqual(self.two, self.one + self.one_2)
+ self.assertEqual(self.highest, self.highest + self.zero)
+ self.assertEqual(self.zero, self.highest + self.one)
+ self.assertEqual(self.one, self.highest + self.two)
+ self.assertEqual(self.one, self.highest + self.one + self.one)
+ self.assertEqual(self.one + 100, self.highest + 102)
+ self.assertEqual(100 + self.one, self.highest + 102)
+ self.assertEqual(self.zero + 2147483645, self.highest + 2147483646)
+
+ # using lambda so the error doesn't get thrown on initial evaluation
+ self.assertRaises(TypeError, lambda: self.zero + "bad")
+ self.assertRaises(TypeError, lambda: self.zero + None)
+ self.assertRaises(TypeError, lambda: "bad" + self.zero)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/lib/dns/rdata/generic/soa_6.cc b/src/lib/dns/rdata/generic/soa_6.cc
index 875a957..e473bca 100644
--- a/src/lib/dns/rdata/generic/soa_6.cc
+++ b/src/lib/dns/rdata/generic/soa_6.cc
@@ -106,10 +106,10 @@ SOA::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeData(numdata_, sizeof(numdata_));
}
-uint32_t
+Serial
SOA::getSerial() const {
InputBuffer b(numdata_, sizeof(numdata_));
- return (b.readUint32());
+ return (Serial(b.readUint32()));
}
string
diff --git a/src/lib/dns/rdata/generic/soa_6.h b/src/lib/dns/rdata/generic/soa_6.h
index 4c6b6ec..2c180b2 100644
--- a/src/lib/dns/rdata/generic/soa_6.h
+++ b/src/lib/dns/rdata/generic/soa_6.h
@@ -18,6 +18,7 @@
#include <dns/name.h>
#include <dns/rdata.h>
+#include <dns/serial.h>
// BEGIN_ISC_NAMESPACE
@@ -35,7 +36,7 @@ public:
uint32_t refresh, uint32_t retry, uint32_t expire,
uint32_t minimum);
/// \brief Returns the serial stored in the SOA.
- uint32_t getSerial() const;
+ Serial getSerial() const;
private:
/// Note: this is a prototype version; we may reconsider
/// this representation later.
diff --git a/src/lib/dns/serial.cc b/src/lib/dns/serial.cc
new file mode 100644
index 0000000..7f07444
--- /dev/null
+++ b/src/lib/dns/serial.cc
@@ -0,0 +1,76 @@
+// 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.
+
+#include <dns/serial.h>
+
+namespace isc {
+namespace dns {
+
+bool
+Serial::operator==(const Serial& other) const {
+ return (value_ == other.getValue());
+}
+
+bool
+Serial::operator!=(const Serial& other) const {
+ return (value_ != other.getValue());
+}
+
+bool
+Serial::operator<(const Serial& other) const {
+ uint32_t other_val = other.getValue();
+ bool result = false;
+ if (value_ < other_val) {
+ result = ((other_val - value_) <= MAX_SERIAL_INCREMENT);
+ } else if (other_val < value_) {
+ result = ((value_ - other_val) > MAX_SERIAL_INCREMENT);
+ }
+ return (result);
+}
+
+bool
+Serial::operator<=(const Serial& other) const {
+ return (operator==(other) || operator<(other));
+}
+
+bool
+Serial::operator>(const Serial& other) const {
+ return (!operator==(other) && !operator<(other));
+}
+
+bool
+Serial::operator>=(const Serial& other) const {
+ return (operator==(other) || !operator>(other));
+}
+
+Serial
+Serial::operator+(uint32_t other_val) const {
+ uint64_t new_val = static_cast<uint64_t>(value_) +
+ static_cast<uint64_t>(other_val);
+ return Serial(static_cast<uint32_t>(new_val % MAX_SERIAL_VALUE));
+}
+
+Serial
+Serial::operator+(const Serial& other) const {
+ return (operator+(other.getValue()));
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Serial& serial) {
+ return (os << serial.getValue());
+}
+
+} // end namespace dns
+} // end namespace isc
+
diff --git a/src/lib/dns/serial.h b/src/lib/dns/serial.h
new file mode 100644
index 0000000..620e274
--- /dev/null
+++ b/src/lib/dns/serial.h
@@ -0,0 +1,155 @@
+// 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 __SERIAL_H
+#define __SERIAL_H 1
+
+#include <stdint.h>
+#include <iostream>
+
+namespace isc {
+namespace dns {
+
+/// The maximum difference between two serial numbers. If the (plain uint32_t)
+/// difference between two serials is greater than this number, the smaller one
+/// is considered greater.
+const uint32_t MAX_SERIAL_INCREMENT = 2147483647;
+
+/// Maximum value a serial can have, used in + operator.
+const uint64_t MAX_SERIAL_VALUE = 4294967296;
+
+/// \brief This class defines DNS serial numbers and serial arithmetic.
+///
+/// DNS Serial number are in essence unsigned 32-bits numbers, with one
+/// catch; they should be compared using sequence space arithmetic.
+/// So given that they are 32-bits; as soon as the difference between two
+/// serial numbers is greater than 2147483647 (2^31 - 1), the lower number
+/// (in plain comparison) is considered the higher one.
+///
+/// In order to do this as transparently as possible, these numbers are
+/// stored in the Serial class, which overrides the basic comparison operators.
+///
+/// In this specific context, these operations are called 'serial number
+/// arithmetic', and they are defined in RFC 1982.
+///
+/// \note RFC 1982 defines everything based on the value SERIAL_BITS. Since
+/// the serial number has a fixed length of 32 bits, the values we use are
+/// hard-coded, and not computed based on variable bit lengths.
+class Serial {
+public:
+ /// \brief Constructor with value
+ ///
+ /// \param value The uint32_t value of the serial
+ explicit Serial(uint32_t value) : value_(value) {}
+
+ /// \brief Copy constructor
+ Serial(const Serial& other) : value_(other.getValue()) {}
+
+ /// \brief Direct assignment from other Serial
+ ///
+ /// \param other The Serial to assign the value from
+ void operator=(const Serial& other) { value_ = other.getValue(); }
+
+ /// \brief Direct assignment from value
+ ///
+ /// \param value the uint32_t value to assing
+ void operator=(uint32_t value) { value_ = value; }
+
+ /// \brief Returns the uint32_t representation of this serial value
+ ///
+ /// \return The uint32_t value of this Serial
+ uint32_t getValue() const { return (value_); }
+
+ /// \brief Returns true if the serial values are equal
+ ///
+ /// \return True if the values are equal
+ bool operator==(const Serial& other) const;
+
+ /// \brief Returns true if the serial values are not equal
+ ///
+ /// \return True if the values are not equal
+ bool operator!=(const Serial& other) const;
+
+ /// \brief Returns true if the serial value of this serial is smaller than
+ /// the other, according to serial arithmetic as described in RFC 1982
+ ///
+ /// \param other The Serial to compare to
+ ///
+ /// \return True if this is smaller than the given value
+ bool operator<(const Serial& other) const;
+
+ /// \brief Returns true if the serial value of this serial is equal to or
+ /// smaller than the other, according to serial arithmetic as described
+ /// in RFC 1982
+ ///
+ /// \param other The Serial to compare to
+ ///
+ /// \return True if this is smaller than or equal to the given value
+ bool operator<=(const Serial& other) const;
+
+ /// \brief Returns true if the serial value of this serial is greater than
+ /// the other, according to serial arithmetic as described in RFC 1982
+ ///
+ /// \param other The Serial to compare to
+ ///
+ /// \return True if this is greater than the given value
+ bool operator>(const Serial& other) const;
+
+ /// \brief Returns true if the serial value of this serial is equal to or
+ /// greater than the other, according to serial arithmetic as described in
+ /// RFC 1982
+ ///
+ /// \param other The Serial to compare to
+ ///
+ /// \return True if this is greater than or equal to the given value
+ bool operator>=(const Serial& other) const;
+
+ /// \brief Adds the given value to the serial number. If this would make
+ /// the number greater than 2^32-1, it is 'wrapped'.
+ /// \note According to the specification, an addition greater than
+ /// MAX_SERIAL_INCREMENT is undefined. We do NOT catch this error (so as not
+ /// to raise exceptions), but this behaviour remains undefined.
+ ///
+ /// \param other The Serial to add
+ ///
+ /// \return The result of the addition
+ Serial operator+(const Serial& other) const;
+
+ /// \brief Adds the given value to the serial number. If this would make
+ /// the number greater than 2^32-1, it is 'wrapped'.
+ ///
+ /// \note According to the specification, an addition greater than
+ /// MAX_SERIAL_INCREMENT is undefined. We do NOT catch this error (so as not
+ /// to raise exceptions), but this behaviour remains undefined.
+ ///
+ /// \param other_val The uint32_t value to add
+ ///
+ /// \return The result of the addition
+ Serial operator+(uint32_t other_val) const;
+
+private:
+ uint32_t value_;
+};
+
+/// \brief Helper operator for output streams, writes the value to the stream
+///
+/// \param os The ostream to write to
+/// \param serial The Serial to write
+/// \return the output stream
+std::ostream& operator<<(std::ostream& os, const Serial& serial);
+
+} // end namespace dns
+} // end namespace isc
+
+#endif // __SERIAL_H
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index ceeb3b8..fc6c87c 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -54,6 +54,7 @@ run_unittests_SOURCES += question_unittest.cc
run_unittests_SOURCES += rrparamregistry_unittest.cc
run_unittests_SOURCES += masterload_unittest.cc
run_unittests_SOURCES += message_unittest.cc
+run_unittests_SOURCES += serial_unittest.cc
run_unittests_SOURCES += tsig_unittest.cc
run_unittests_SOURCES += tsigerror_unittest.cc
run_unittests_SOURCES += tsigkey_unittest.cc
diff --git a/src/lib/dns/tests/rdata_soa_unittest.cc b/src/lib/dns/tests/rdata_soa_unittest.cc
index 17498eb..07c24d5 100644
--- a/src/lib/dns/tests/rdata_soa_unittest.cc
+++ b/src/lib/dns/tests/rdata_soa_unittest.cc
@@ -76,7 +76,7 @@ TEST_F(Rdata_SOA_Test, toText) {
}
TEST_F(Rdata_SOA_Test, getSerial) {
- EXPECT_EQ(2010012601, rdata_soa.getSerial());
+ EXPECT_EQ(2010012601, rdata_soa.getSerial().getValue());
}
}
diff --git a/src/lib/dns/tests/serial_unittest.cc b/src/lib/dns/tests/serial_unittest.cc
new file mode 100644
index 0000000..128c92d
--- /dev/null
+++ b/src/lib/dns/tests/serial_unittest.cc
@@ -0,0 +1,179 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include <dns/serial.h>
+
+using namespace isc::dns;
+
+class SerialTest : public ::testing::Test {
+public:
+ SerialTest() : one(1), one_2(1), two(2),
+ date_zero(1980120100), date_one(1980120101),
+ min(0), max(4294967295u),
+ number_low(12345),
+ number_medium(2000000000),
+ number_high(4000000000u)
+ {}
+ Serial one, one_2, two, date_zero, date_one, min, max, number_low, number_medium, number_high;
+};
+
+//
+// Basic tests
+//
+
+TEST_F(SerialTest, get_value) {
+ EXPECT_EQ(1, one.getValue());
+ EXPECT_NE(2, one.getValue());
+ EXPECT_EQ(2, two.getValue());
+ EXPECT_EQ(1980120100, date_zero.getValue());
+ EXPECT_EQ(1980120101, date_one.getValue());
+ EXPECT_EQ(0, min.getValue());
+ EXPECT_EQ(4294967295u, max.getValue());
+ EXPECT_EQ(12345, number_low.getValue());
+ EXPECT_EQ(2000000000, number_medium.getValue());
+ EXPECT_EQ(4000000000u, number_high.getValue());
+}
+
+TEST_F(SerialTest, equals) {
+ EXPECT_EQ(one, one);
+ EXPECT_EQ(one, one);
+ EXPECT_EQ(one, one_2);
+ EXPECT_NE(one, two);
+ EXPECT_NE(two, one);
+ EXPECT_EQ(Serial(12345), number_low);
+ EXPECT_NE(Serial(12346), number_low);
+}
+
+TEST_F(SerialTest, comparison) {
+ // These should be true/false even without serial arithmetic
+ EXPECT_LE(one, one);
+ EXPECT_LE(one, one_2);
+ EXPECT_LT(one, two);
+ EXPECT_LE(one, two);
+ EXPECT_GE(two, two);
+ EXPECT_GT(two, one);
+ EXPECT_LT(one, number_low);
+ EXPECT_LT(number_low, number_medium);
+ EXPECT_LT(number_medium, number_high);
+
+ // now let's try some that 'wrap', as it were
+ EXPECT_GT(min, max);
+ EXPECT_LT(max, min);
+ EXPECT_LT(number_high, number_low);
+}
+
+//
+// RFC 1982 Section 3.1
+//
+TEST_F(SerialTest, addition) {
+ EXPECT_EQ(two, one + one);
+ EXPECT_EQ(two, one + one_2);
+ EXPECT_EQ(max, max + min);
+ EXPECT_EQ(min, max + one);
+ EXPECT_EQ(one, max + two);
+ EXPECT_EQ(one, max + one + one);
+
+ EXPECT_EQ(one + 100, max + 102);
+ EXPECT_EQ(min + 2147483645, max + 2147483646);
+ EXPECT_EQ(min + 2147483646, max + MAX_SERIAL_INCREMENT);
+}
+
+//
+// RFC 1982 Section 3.2 has been checked by the basic tests above
+//
+
+//
+// RFC 1982 Section 4.1
+//
+
+// Helper function for addition_always_larger test, add some numbers
+// and check that the result is always larger than the original
+void do_addition_larger_test(const Serial& number) {
+ EXPECT_GE(number + 0, number);
+ EXPECT_EQ(number + 0, number);
+ EXPECT_GT(number + 1, number);
+ EXPECT_GT(number + 2, number);
+ EXPECT_GT(number + 100, number);
+ EXPECT_GT(number + 1111111, number);
+ EXPECT_GT(number + 2147483646, number);
+ EXPECT_GT(number + MAX_SERIAL_INCREMENT, number);
+ // Try MAX_SERIAL_INCREMENT as a hardcoded number as well
+ EXPECT_GT(number + 2147483647, number);
+}
+
+TEST_F(SerialTest, addition_always_larger) {
+ do_addition_larger_test(one);
+ do_addition_larger_test(two);
+ do_addition_larger_test(date_zero);
+ do_addition_larger_test(date_one);
+ do_addition_larger_test(min);
+ do_addition_larger_test(max);
+ do_addition_larger_test(number_low);
+ do_addition_larger_test(number_medium);
+ do_addition_larger_test(number_high);
+}
+
+//
+// RFC 1982 Section 4.2
+//
+
+// Helper function to do the second addition
+void
+do_two_additions_test_second(const Serial &original,
+ const Serial &number)
+{
+ EXPECT_NE(original, number);
+ EXPECT_NE(original, number + 0);
+ EXPECT_NE(original, number + 1);
+ EXPECT_NE(original, number + 2);
+ EXPECT_NE(original, number + 100);
+ EXPECT_NE(original, number + 1111111);
+ EXPECT_NE(original, number + 2147483646);
+ EXPECT_NE(original, number + MAX_SERIAL_INCREMENT);
+ EXPECT_NE(original, number + 2147483647);
+}
+
+void do_two_additions_test_first(const Serial &number) {
+ do_two_additions_test_second(number, number + 1);
+ do_two_additions_test_second(number, number + 2);
+ do_two_additions_test_second(number, number + 100);
+ do_two_additions_test_second(number, number + 1111111);
+ do_two_additions_test_second(number, number + 2147483646);
+ do_two_additions_test_second(number, number + MAX_SERIAL_INCREMENT);
+ do_two_additions_test_second(number, number + 2147483647);
+}
+
+TEST_F(SerialTest, two_additions_never_equal) {
+ do_two_additions_test_first(one);
+ do_two_additions_test_first(two);
+ do_two_additions_test_first(date_zero);
+ do_two_additions_test_first(date_one);
+ do_two_additions_test_first(min);
+ do_two_additions_test_first(max);
+ do_two_additions_test_first(number_low);
+ do_two_additions_test_first(number_medium);
+ do_two_additions_test_first(number_high);
+}
+
+//
+// RFC 1982 Section 4.3 and 4.4 have nothing to test
+//
+
+//
+// Tests from RFC 1982 examples
+//
+TEST(SerialTextRFCExamples, rfc_example_tests) {
+}
More information about the bind10-changes
mailing list