Commit a407cb3d authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files
parents 1cccbc68 081891b3
......@@ -842,6 +842,7 @@ AC_OUTPUT([doc/version.ent
src/lib/cc/session_config.h.pre
src/lib/cc/tests/session_unittests_config.h
src/lib/log/tests/run_time_init_test.sh
src/lib/util/python/mkpywrapper.py
tests/system/conf.sh
tests/system/glue/setup.sh
tests/system/glue/nsx1/b10-config.db
......@@ -867,6 +868,7 @@ AC_OUTPUT([doc/version.ent
chmod +x src/lib/dns/gen-rdatacode.py
chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
chmod +x src/lib/log/tests/run_time_init_test.sh
chmod +x src/lib/util/python/mkpywrapper.py
chmod +x tests/system/conf.sh
])
AC_OUTPUT
......
......@@ -1140,7 +1140,7 @@ MAN_LINKS = NO
# generate an XML file that captures the structure of
# the code including all documentation.
GENERATE_XML = NO
GENERATE_XML = YES
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
......@@ -1165,7 +1165,7 @@ XML_DTD =
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
XML_PROGRAMLISTING = YES
XML_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
......
......@@ -6,6 +6,8 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
pyexec_LTLIBRARIES = pydnspp.la
pydnspp_la_SOURCES = pydnspp.cc pydnspp_common.cc
pydnspp_la_SOURCES += rcode_python.cc rcode_python.h
pydnspp_la_SOURCES += tsigerror_python.cc tsigerror_python.h
pydnspp_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
......
......@@ -336,15 +336,15 @@ Message_getRcode(s_Message* self) {
rcode = static_cast<s_Rcode*>(rcode_type.tp_alloc(&rcode_type, 0));
if (rcode != NULL) {
rcode->rcode = NULL;
rcode->cppobj = NULL;
try {
rcode->rcode = new Rcode(self->message->getRcode());
rcode->cppobj = new Rcode(self->message->getRcode());
} catch (const InvalidMessageOperation& imo) {
PyErr_SetString(po_InvalidMessageOperation, imo.what());
} catch (...) {
PyErr_SetString(po_IscException, "Unexpected exception");
}
if (rcode->rcode == NULL) {
if (rcode->cppobj == NULL) {
Py_DECREF(rcode);
return (NULL);
}
......@@ -360,7 +360,7 @@ Message_setRcode(s_Message* self, PyObject* args) {
return (NULL);
}
try {
self->message->setRcode(*rcode->rcode);
self->message->setRcode(*rcode->cppobj);
Py_RETURN_NONE;
} catch (const InvalidMessageOperation& imo) {
PyErr_SetString(po_InvalidMessageOperation, imo.what());
......
......@@ -32,20 +32,32 @@
#include <exceptions/exceptions.h>
#include <util/buffer.h>
#include <dns/exceptions.h>
#include <dns/name.h>
#include <dns/messagerenderer.h>
#include <dns/python/pydnspp_common.h>
#include "pydnspp_common.h"
namespace isc {
namespace dns {
namespace python {
// For our 'general' isc::Exceptions
static PyObject* po_IscException;
static PyObject* po_InvalidParameter;
PyObject* po_IscException;
PyObject* po_InvalidParameter;
// For our own isc::dns::Exception
static PyObject* po_DNSMessageBADVERS;
PyObject* po_DNSMessageBADVERS;
}
}
}
#include "rcode_python.h"
#include "tsigerror_python.h"
// order is important here!
using namespace isc::dns::python;
#include <dns/python/messagerenderer_python.cc>
#include <dns/python/name_python.cc> // needs Messagerenderer
#include <dns/python/rrclass_python.cc> // needs Messagerenderer
......@@ -58,14 +70,14 @@ static PyObject* po_DNSMessageBADVERS;
#include <dns/python/tsigkey_python.cc> // needs Name
#include <dns/python/tsig_python.cc> // needs tsigkey
#include <dns/python/opcode_python.cc>
#include <dns/python/rcode_python.cc>
#include <dns/python/edns_python.cc> // needs Messagerenderer, Rcode
#include <dns/python/message_python.cc> // needs RRset, Question
//
// Definition of the module
//
static PyModuleDef pydnspp = {
namespace {
PyModuleDef pydnspp = {
{ PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
"pydnspp",
"Python bindings for the classes in the isc::dns namespace.\n\n"
......@@ -80,10 +92,11 @@ static PyModuleDef pydnspp = {
NULL,
NULL
};
}
PyMODINIT_FUNC
PyInit_pydnspp(void) {
PyObject *mod = PyModule_Create(&pydnspp);
PyObject* mod = PyModule_Create(&pydnspp);
if (mod == NULL) {
return (NULL);
}
......@@ -154,6 +167,10 @@ PyInit_pydnspp(void) {
return (NULL);
}
if (!initModulePart_TSIGError(mod)) {
return (NULL);
}
if (!initModulePart_TSIGContext(mod)) {
return (NULL);
}
......
......@@ -15,6 +15,9 @@
#include <Python.h>
#include <pydnspp_common.h>
namespace isc {
namespace dns {
namespace python {
int
readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {
PyObject* el = NULL;
......@@ -44,8 +47,15 @@ readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {
}
void addClassVariable(PyTypeObject& c, const char* name,
PyObject* obj)
{
PyDict_SetItemString(c.tp_dict, name, obj);
int
addClassVariable(PyTypeObject& c, const char* name, PyObject* obj) {
if (obj == NULL) {
PyErr_SetString(PyExc_ValueError,
"NULL object is specified for a class variable");
return (-1);
}
return (PyDict_SetItemString(c.tp_dict, name, obj));
}
}
}
}
......@@ -15,9 +15,22 @@
#ifndef __LIBDNS_PYTHON_COMMON_H
#define __LIBDNS_PYTHON_COMMON_H 1
//
// Shared functions for python/c API
//
#include <Python.h>
#include <stdexcept>
#include <string>
#include <util/python/pycppwrapper_util.h>
namespace isc {
namespace dns {
namespace python {
// For our 'general' isc::Exceptions
extern PyObject* po_IscException;
extern PyObject* po_InvalidParameter;
// For our own isc::dns::Exception
extern PyObject* po_DNSMessageBADVERS;
// This function reads 'bytes' from a sequence
// This sequence can be anything that implements the Sequence interface,
......@@ -31,6 +44,12 @@
// case nothing is removed
int readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence);
void addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
int addClassVariable(PyTypeObject& c, const char* name, PyObject* obj);
} // namespace python
} // namespace dns
} // namespace isc
#endif // __LIBDNS_PYTHON_COMMON_H
// Local Variables:
// mode: c++
// End:
......@@ -12,9 +12,15 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <exceptions/exceptions.h>
#include <dns/rcode.h>
#include "pydnspp_common.h"
#include "rcode_python.h"
using namespace isc::dns;
using namespace isc::dns::python;
//
// Declaration of the custom exceptions (None for this class)
......@@ -27,25 +33,14 @@ using namespace isc::dns;
// and static wrappers around the methods we export), a list of methods,
// and a type description
namespace {
//
// Rcode
//
// We added a helper variable static_code here
// Since we can create Rcodes dynamically with Rcode(int), but also
// use the static globals (Rcode::NOERROR() etc), we use this
// variable to see if the code came from one of the latter, in which
// case Rcode_destroy should not free it (the other option is to
// allocate new Rcodes for every use of the static ones, but this
// seems more efficient).
class s_Rcode : public PyObject {
public:
s_Rcode() : rcode(NULL), static_code(false) {}
const Rcode* rcode;
bool static_code;
};
// Trivial constructor.
s_Rcode::s_Rcode() : cppobj(NULL), static_code(false) {}
namespace {
int Rcode_init(s_Rcode* const self, PyObject* args);
void Rcode_destroy(s_Rcode* const self);
......@@ -118,57 +113,6 @@ PyMethodDef Rcode_methods[] = {
{ NULL, NULL, 0, NULL }
};
PyTypeObject rcode_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"pydnspp.Rcode",
sizeof(s_Rcode), // tp_basicsize
0, // tp_itemsize
(destructor)Rcode_destroy, // tp_dealloc
NULL, // tp_print
NULL, // tp_getattr
NULL, // tp_setattr
NULL, // tp_reserved
NULL, // tp_repr
NULL, // tp_as_number
NULL, // tp_as_sequence
NULL, // tp_as_mapping
NULL, // tp_hash
NULL, // tp_call
Rcode_str, // tp_str
NULL, // tp_getattro
NULL, // tp_setattro
NULL, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"The Rcode class objects represent standard RCODEs"
"of the header section of DNS messages.",
NULL, // tp_traverse
NULL, // tp_clear
(richcmpfunc)Rcode_richcmp, // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
Rcode_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)Rcode_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
};
int
Rcode_init(s_Rcode* const self, PyObject* args) {
long code = 0;
......@@ -193,9 +137,9 @@ Rcode_init(s_Rcode* const self, PyObject* args) {
}
try {
if (ext_code == -1) {
self->rcode = new Rcode(code);
self->cppobj = new Rcode(code);
} else {
self->rcode = new Rcode(code, ext_code);
self->cppobj = new Rcode(code, ext_code);
}
self->static_code = false;
} catch (const isc::OutOfRange& ex) {
......@@ -211,27 +155,27 @@ Rcode_init(s_Rcode* const self, PyObject* args) {
void
Rcode_destroy(s_Rcode* const self) {
// Depending on whether we created the rcode or are referring
// to a global one, we do or do not delete self->rcode here
// to a global one, we do or do not delete self->cppobj here
if (!self->static_code) {
delete self->rcode;
delete self->cppobj;
}
self->rcode = NULL;
self->cppobj = NULL;
Py_TYPE(self)->tp_free(self);
}
PyObject*
Rcode_getCode(const s_Rcode* const self) {
return (Py_BuildValue("I", self->rcode->getCode()));
return (Py_BuildValue("I", self->cppobj->getCode()));
}
PyObject*
Rcode_getExtendedCode(const s_Rcode* const self) {
return (Py_BuildValue("I", self->rcode->getExtendedCode()));
return (Py_BuildValue("I", self->cppobj->getExtendedCode()));
}
PyObject*
Rcode_toText(const s_Rcode* const self) {
return (Py_BuildValue("s", self->rcode->toText().c_str()));
return (Py_BuildValue("s", self->cppobj->toText().c_str()));
}
PyObject*
......@@ -245,7 +189,7 @@ PyObject*
Rcode_createStatic(const Rcode& rcode) {
s_Rcode* ret = PyObject_New(s_Rcode, &rcode_type);
if (ret != NULL) {
ret->rcode = &rcode;
ret->cppobj = &rcode;
ret->static_code = true;
}
return (ret);
......@@ -357,10 +301,10 @@ Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
return (NULL);
case Py_EQ:
c = (*self->rcode == *other->rcode);
c = (*self->cppobj == *other->cppobj);
break;
case Py_NE:
c = (*self->rcode != *other->rcode);
c = (*self->cppobj != *other->cppobj);
break;
case Py_GT:
PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode");
......@@ -374,6 +318,61 @@ Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other,
else
Py_RETURN_FALSE;
}
} // end of unnamed namespace
namespace isc {
namespace dns {
namespace python {
PyTypeObject rcode_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"pydnspp.Rcode",
sizeof(s_Rcode), // tp_basicsize
0, // tp_itemsize
(destructor)Rcode_destroy, // tp_dealloc
NULL, // tp_print
NULL, // tp_getattr
NULL, // tp_setattr
NULL, // tp_reserved
NULL, // tp_repr
NULL, // tp_as_number
NULL, // tp_as_sequence
NULL, // tp_as_mapping
NULL, // tp_hash
NULL, // tp_call
Rcode_str, // tp_str
NULL, // tp_getattro
NULL, // tp_setattro
NULL, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"The Rcode class objects represent standard RCODEs"
"of the header section of DNS messages.",
NULL, // tp_traverse
NULL, // tp_clear
reinterpret_cast<richcmpfunc>(Rcode_richcmp), // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
Rcode_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)Rcode_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
};
// Module Initialization, all statics are initialized here
bool
......@@ -428,4 +427,6 @@ initModulePart_Rcode(PyObject* mod) {
return (true);
}
} // end of unnamed namespace
} // 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_RCODE_H
#define __PYTHON_RCODE_H 1
#include <Python.h>
namespace isc {
namespace dns {
class Rcode;
namespace python {
// The s_* Class simply covers one instantiation of the object.
//
// We added a helper variable static_code here
// Since we can create Rcodes dynamically with Rcode(int), but also
// use the static globals (Rcode::NOERROR() etc), we use this
// variable to see if the code came from one of the latter, in which
// case Rcode_destroy should not free it (the other option is to
// allocate new Rcodes for every use of the static ones, but this
// seems more efficient).
//
// Follow-up note: we don't have to use the proxy function in the python lib;
// we can just define class specific constants directly (see TSIGError).
// We should make this cleanup later.
class s_Rcode : public PyObject {
public:
s_Rcode();
const Rcode* cppobj;
bool static_code;
};
extern PyTypeObject rcode_type;
bool initModulePart_Rcode(PyObject* mod);
} // namespace python
} // namespace dns
} // namespace isc
#endif // __PYTHON_RCODE_H
// Local Variables:
// mode: c++
// End:
......@@ -12,6 +12,7 @@ PYTESTS += rrset_python_test.py
PYTESTS += rrttl_python_test.py
PYTESTS += rrtype_python_test.py
PYTESTS += tsig_python_test.py
PYTESTS += tsigerror_python_test.py
PYTESTS += tsigkey_python_test.py
EXTRA_DIST = $(PYTESTS)
......
# 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.
import unittest
import sys
from pydnspp import *
class TSIGErrorTest(unittest.TestCase):
def test_from_code(self):
self.assertEqual(0, TSIGError(0).get_code())
self.assertEqual(18, TSIGError(18).get_code())
self.assertEqual(65535, TSIGError(65535).get_code())
self.assertRaises(ValueError, TSIGError, 65536)
self.assertRaises(ValueError, TSIGError, -1)
self.assertRaises(TypeError, TSIGError, "not yet supported")
def test_from_rcode(self):
# We use RCODE for code values from 0-15.
self.assertEqual(0, TSIGError(Rcode.NOERROR()).get_code())
self.assertEqual(15, TSIGError(Rcode(15)).get_code())
# From error code 16 TSIG errors define a separate space, so passing
# corresponding RCODE for such code values should be prohibited.
self.assertRaises(ValueError, TSIGError, Rcode(16))
def test_constants(self):
# We'll only test arbitrarily chosen subsets of the codes.
# This class is quite simple, so it should be suffice.
self.assertEqual(TSIGError.BAD_SIG_CODE, TSIGError(16).get_code())
self.assertEqual(TSIGError.BAD_KEY_CODE, TSIGError(17).get_code())
self.assertEqual(TSIGError.BAD_TIME_CODE, TSIGError(18).get_code())
self.assertEqual(0, TSIGError.NOERROR.get_code())
self.assertEqual(9, TSIGError.NOTAUTH.get_code())
self.assertEqual(14, TSIGError.RESERVED14.get_code())
self.assertEqual(TSIGError.BAD_SIG_CODE, TSIGError.BAD_SIG.get_code())
self.assertEqual(TSIGError.BAD_KEY_CODE, TSIGError.BAD_KEY.get_code())
self.assertEqual(TSIGError.BAD_TIME_CODE, TSIGError.BAD_TIME.get_code())
def test_equal(self):
self.assertTrue(TSIGError.NOERROR == TSIGError(Rcode.NOERROR()))
self.assertTrue(TSIGError(Rcode.NOERROR()) == TSIGError.NOERROR)
self.assertTrue(TSIGError.BAD_SIG == TSIGError(16))
self.assertTrue(TSIGError(16) == TSIGError.BAD_SIG)
def test_nequal(self):
self.assertTrue(TSIGError.BAD_KEY != TSIGError(Rcode.NOERROR()))
self.assertTrue(TSIGError(Rcode.NOERROR()) != TSIGError.BAD_KEY)
def test_to_text(self):
# TSIGError derived from the standard Rcode
self.assertEqual("NOERROR", TSIGError(Rcode.NOERROR()).to_text())
# Well known TSIG errors
self.assertEqual("BADSIG", TSIGError.BAD_SIG.to_text())
self.assertEqual("BADKEY", TSIGError.BAD_KEY.to_text())
self.assertEqual("BADTIME", TSIGError.BAD_TIME.to_text())
# Unknown (or not yet supported) codes. Simply converted as numeric.
self.assertEqual("19", TSIGError(19).to_text());
self.assertEqual("65535", TSIGError(65535).to_text());
# also check str() works same way
self.assertEqual("NOERROR", str(TSIGError(Rcode.NOERROR())))
self.assertEqual("BADSIG", str(TSIGError.BAD_SIG))
def test_to_rcode(self):
# TSIGError derived from the standard Rcode
self.assertEqual(Rcode.NOERROR(), TSIGError(Rcode.NOERROR()).to_rcode())
# Well known TSIG errors
self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_SIG.to_rcode())
self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_KEY.to_rcode())
self.assertEqual(Rcode.NOTAUTH(), TSIGError.BAD_TIME.to_rcode())
# Unknown (or not yet supported) codes are treated as SERVFAIL.
self.assertEqual(Rcode.SERVFAIL