Commit 2ae72d76 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

Merge branch 'trac1278'

parents 1ecbd2b1 0b5da8bd
......@@ -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);
}
......
......@@ -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
......
......@@ -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
......
......@@ -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"
......@@ -491,6 +492,18 @@ initModulePart_RRType(PyObject* mod) {
return (true);
}
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) {
......@@ -804,6 +817,10 @@ PyInit_pydnspp(void) {
return (NULL);
}
if (!initModulePart_Serial(mod)) {
return (NULL);
}
if (!initModulePart_TSIGKey(mod)) {
return (NULL);
}
......
// 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
// 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:
......@@ -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
......
# 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()
......@@ -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
......
......@@ -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.
......
// 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.