Commit d365482e authored by JINMEI Tatuya's avatar JINMEI Tatuya

[master] Merge branch 'trac2437'

parents bd9b58b2 6e4caf9d
......@@ -25,6 +25,9 @@ libb10_pydnspp_la_SOURCES += tsigrecord_python.cc tsigrecord_python.h
libb10_pydnspp_la_SOURCES += tsig_python.cc tsig_python.h
libb10_pydnspp_la_SOURCES += edns_python.cc edns_python.h
libb10_pydnspp_la_SOURCES += message_python.cc message_python.h
libb10_pydnspp_la_SOURCES += rrset_collection_python.cc
libb10_pydnspp_la_SOURCES += rrset_collection_python.h
libb10_pydnspp_la_SOURCES += zone_checker_python.cc zone_checker_python.h
libb10_pydnspp_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
libb10_pydnspp_la_CXXFLAGS = $(AM_CXXFLAGS) $(PYTHON_CXXFLAGS)
......@@ -43,6 +46,8 @@ pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
EXTRA_DIST = tsigerror_python_inc.cc
EXTRA_DIST += message_python_inc.cc
EXTRA_DIST += nsec3hash_python_inc.cc
EXTRA_DIST += rrset_collection_python_inc.cc
EXTRA_DIST += zone_checker_python_inc.cc
# Python prefers .so, while some OSes (specifically MacOS) use a different
# suffix for dynamic objects. -module is necessary to work this around.
......
......@@ -50,12 +50,16 @@
#include "rrset_python.h"
#include "rrttl_python.h"
#include "rrtype_python.h"
#include "rrset_collection_python.h"
#include "serial_python.h"
#include "tsigerror_python.h"
#include "tsigkey_python.h"
#include "tsig_python.h"
#include "tsig_rdata_python.h"
#include "tsigrecord_python.h"
#include "zone_checker_python.h"
#include "zone_checker_python_inc.cc"
using namespace isc::dns;
using namespace isc::dns::python;
......@@ -728,6 +732,11 @@ initModulePart_TSIGRecord(PyObject* mod) {
return (true);
}
PyMethodDef methods[] = {
{ "check_zone", internal::pyCheckZone, METH_VARARGS, dns_checkZone_doc },
{ NULL, NULL, 0, NULL }
};
PyModuleDef pydnspp = {
{ PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
"pydnspp",
......@@ -737,13 +746,13 @@ PyModuleDef pydnspp = {
"and OutputBuffer for instance), and others may be necessary, but "
"were not up to now.",
-1,
NULL,
methods,
NULL,
NULL,
NULL,
NULL
};
}
} // unnamed namespace
PyMODINIT_FUNC
PyInit_pydnspp(void) {
......@@ -864,5 +873,13 @@ PyInit_pydnspp(void) {
return (NULL);
}
if (!initModulePart_RRsetCollectionBase(mod)) {
return (NULL);
}
if (!initModulePart_RRsetCollection(mod)) {
return (NULL);
}
return (mod);
}
// Copyright (C) 2013 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.
// Enable this if you use s# variants with PyArg_ParseTuple(), see
// http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
//#define PY_SSIZE_T_CLEAN
// Python.h needs to be placed at the head of the program file, see:
// http://docs.python.org/py3k/extending/extending.html#a-simple-example
#include <Python.h>
#include <exceptions/exceptions.h>
#include <dns/python/rrset_collection_python.h>
#include <dns/python/name_python.h>
#include <dns/python/rrtype_python.h>
#include <dns/python/rrclass_python.h>
#include <dns/python/rrset_python.h>
#include <dns/python/pydnspp_common.h>
#include <dns/rrset_collection_base.h>
#include <dns/rrset_collection.h>
#include <string>
#include <sstream>
#include <stdexcept>
using namespace std;
using namespace isc::util::python;
using namespace isc::dns;
using namespace isc::dns::python;
// Import pydoc text
#include "rrset_collection_python_inc.cc"
namespace {
// This is a template for a common pattern of type mismatch error handling,
// provided to save typing and repeating the mostly identical patterns.
PyObject*
setTypeError(PyObject* pobj, const char* var_name, const char* type_name) {
PyErr_Format(PyExc_TypeError, "%s must be a %s, not %.200s",
var_name, type_name, pobj->ob_type->tp_name);
return (NULL);
}
}
//
// RRsetCollectionBase
//
namespace {
int
RRsetCollectionBase_init(PyObject*, PyObject*, PyObject*) {
PyErr_SetString(PyExc_TypeError,
"RRsetCollectionBase cannot be instantiated directly");
return (-1);
}
void
RRsetCollectionBase_destroy(PyObject* po_self) {
s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
delete self->cppobj;
self->cppobj = NULL;
Py_TYPE(self)->tp_free(self);
}
PyObject*
RRsetCollectionBase_find(PyObject* po_self, PyObject* args) {
s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
if (self->cppobj == NULL) {
PyErr_Format(PyExc_TypeError, "find() is not implemented in the "
"derived RRsetCollection class");
return (NULL);
}
try {
PyObject* po_name;
PyObject* po_rrclass;
PyObject* po_rrtype;
if (PyArg_ParseTuple(args, "OOO", &po_name, &po_rrclass, &po_rrtype)) {
if (!PyName_Check(po_name)) {
return (setTypeError(po_name, "name", "Name"));
}
if (!PyRRClass_Check(po_rrclass)) {
return (setTypeError(po_rrclass, "rrclass", "RRClass"));
}
if (!PyRRType_Check(po_rrtype)) {
return (setTypeError(po_rrtype, "rrtype", "RRType"));
}
ConstRRsetPtr found_rrset = self->cppobj->find(
PyName_ToName(po_name), PyRRClass_ToRRClass(po_rrclass),
PyRRType_ToRRType(po_rrtype));
if (found_rrset) {
return (createRRsetObject(*found_rrset));
}
Py_RETURN_NONE;
}
} catch (const std::exception& ex) {
const string ex_what = "Unexpected failure in "
"RRsetCollectionBase.find: " + string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
return (NULL);
} catch (...) {
PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
return (NULL);
}
return (NULL);
}
// 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 RRsetCollectionBase_methods[] = {
{ "find", RRsetCollectionBase_find, METH_VARARGS,
RRsetCollectionBase_find_doc },
{ NULL, NULL, 0, NULL }
};
} // end of unnamed namespace
namespace isc {
namespace dns {
namespace python {
// This defines the complete type for reflection in python and
// parsing of PyObject* to s_RRsetCollection
// Most of the functions are not actually implemented and NULL here.
PyTypeObject rrset_collection_base_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"dns.RRsetCollectionBase",
sizeof(s_RRsetCollection), // tp_basicsize
0, // tp_itemsize
RRsetCollectionBase_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
NULL, // tp_str
NULL, // tp_getattro
NULL, // tp_setattro
NULL, // tp_as_buffer
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, // tp_flags (it's inheritable)
RRsetCollectionBase_doc,
NULL, // tp_traverse
NULL, // tp_clear
NULL, // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
RRsetCollectionBase_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
RRsetCollectionBase_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
initModulePart_RRsetCollectionBase(PyObject* mod) {
// We initialize the static description object with PyType_Ready(),
// then add it to the module. This is not just a check! (leaving
// this out results in segmentation faults)
if (PyType_Ready(&rrset_collection_base_type) < 0) {
return (false);
}
void* p = &rrset_collection_base_type;
if (PyModule_AddObject(mod, "RRsetCollectionBase",
static_cast<PyObject*>(p)) < 0) {
return (false);
}
Py_INCREF(&rrset_collection_base_type);
return (true);
}
//
// RRsetCollection
//
namespace {
// Shortcut type which would be convenient for adding class variables safely.
typedef CPPPyObjectContainer<s_RRsetCollection, RRsetCollection> RRsetCollectionContainer;
int
RRsetCollection_init(PyObject* po_self, PyObject* args, PyObject*) {
s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
try {
const char* filename;
PyObject* po_name;
PyObject* po_rrclass;
Py_buffer py_buf;
if (PyArg_ParseTuple(args, "sO!O!", &filename, &name_type, &po_name,
&rrclass_type, &po_rrclass)) {
self->cppobj =
new RRsetCollection(filename, PyName_ToName(po_name),
PyRRClass_ToRRClass(po_rrclass));
return (0);
} else if (PyArg_ParseTuple(args, "y*O!O!", &py_buf, &name_type,
&po_name,&rrclass_type, &po_rrclass)) {
PyErr_Clear(); // clear the error for the first ParseTuple
const char* const cp = static_cast<const char*>(py_buf.buf);
std::istringstream iss(string(cp, cp + py_buf.len));
self->cppobj =
new RRsetCollection(iss, PyName_ToName(po_name),
PyRRClass_ToRRClass(po_rrclass));
return (0);
} else if (PyArg_ParseTuple(args, "")) {
PyErr_Clear(); // clear the error for the second ParseTuple
self->cppobj = new RRsetCollection;
return (0);
}
} catch (const exception& ex) {
const string ex_what = "Failed to construct RRsetCollection object: " +
string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
return (-1);
} catch (...) {
PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
return (-1);
}
// Default error string isn't helpful when it takes multiple combinations
// of args. We provide our own.
PyErr_SetString(PyExc_TypeError, "Invalid argument(s) to RRsetCollection "
"constructor; see pydoc");
return (-1);
}
void
RRsetCollection_destroy(PyObject* po_self) {
s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
delete self->cppobj;
self->cppobj = NULL;
Py_TYPE(self)->tp_free(self);
}
PyObject*
RRsetCollection_addRRset(PyObject* po_self, PyObject* args) {
s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
try {
PyObject* po_rrset;
if (PyArg_ParseTuple(args, "O", &po_rrset)) {
if (!PyRRset_Check(po_rrset)) {
return (setTypeError(po_rrset, "rrset", "RRset"));
}
static_cast<RRsetCollection*>(self->cppobj)->addRRset(
PyRRset_ToRRsetPtr(po_rrset));
Py_RETURN_NONE;
}
} catch (const InvalidParameter& ex) { // duplicate add
PyErr_SetString(PyExc_ValueError, ex.what());
return (NULL);
} catch (const std::exception& ex) {
const string ex_what = "Unexpected failure in "
"RRsetCollection.add_rrset: " + string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
return (NULL);
} catch (...) {
PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
return (NULL);
}
return (NULL);
}
PyObject*
RRsetCollection_removeRRset(PyObject* po_self, PyObject* args) {
s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
try {
PyObject* po_name;
PyObject* po_rrclass;
PyObject* po_rrtype;
if (PyArg_ParseTuple(args, "OOO", &po_name, &po_rrclass, &po_rrtype)) {
if (!PyName_Check(po_name)) {
return (setTypeError(po_name, "name", "Name"));
}
if (!PyRRClass_Check(po_rrclass)) {
return (setTypeError(po_rrclass, "rrclass", "RRClass"));
}
if (!PyRRType_Check(po_rrtype)) {
return (setTypeError(po_rrtype, "rrtype", "RRType"));
}
const bool result =
static_cast<RRsetCollection*>(self->cppobj)->removeRRset(
PyName_ToName(po_name), PyRRClass_ToRRClass(po_rrclass),
PyRRType_ToRRType(po_rrtype));
if (result) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
} catch (...) {}
return (NULL);
}
// 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 RRsetCollection_methods[] = {
{ "add_rrset", RRsetCollection_addRRset, METH_VARARGS,
RRsetCollection_addRRset_doc },
{ "remove_rrset", RRsetCollection_removeRRset, METH_VARARGS,
RRsetCollection_removeRRset_doc },
{ NULL, NULL, 0, NULL }
};
} // end of unnamed namespace
// This defines the complete type for reflection in python and
// parsing of PyObject* to s_RRsetCollection
// Most of the functions are not actually implemented and NULL here.
PyTypeObject rrset_collection_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"dns.RRsetCollection",
sizeof(s_RRsetCollection), // tp_basicsize
0, // tp_itemsize
RRsetCollection_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
NULL, // tp_str
NULL, // tp_getattro
NULL, // tp_setattro
NULL, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
RRsetCollection_doc,
NULL, // tp_traverse
NULL, // tp_clear
NULL, // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
RRsetCollection_methods, // tp_methods
NULL, // tp_members
NULL, // tp_getset
&rrset_collection_base_type, // tp_base
NULL, // tp_dict
NULL, // tp_descr_get
NULL, // tp_descr_set
0, // tp_dictoffset
RRsetCollection_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
initModulePart_RRsetCollection(PyObject* mod) {
// We initialize the static description object with PyType_Ready(),
// then add it to the module. This is not just a check! (leaving
// this out results in segmentation faults)
if (PyType_Ready(&rrset_collection_type) < 0) {
return (false);
}
void* p = &rrset_collection_type;
if (PyModule_AddObject(mod, "RRsetCollection",
static_cast<PyObject*>(p)) < 0) {
return (false);
}
Py_INCREF(&rrset_collection_type);
return (true);
}
} // namespace python
} // namespace dns
} // namespace isc
// Copyright (C) 2013 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_RRSETCOLLECTION_H
#define PYTHON_RRSETCOLLECTION_H 1
#include <Python.h>
namespace isc {
namespace dns {
class RRsetCollectionBase;
namespace python {
// The s_* Class simply covers one instantiation of the object
// This structure will be commonly used for all derived classes of
// RRsetCollectionBase. cppobj will point to an instance of the specific
// derived class.
class s_RRsetCollection : public PyObject {
public:
s_RRsetCollection() : cppobj(NULL) {}
RRsetCollectionBase* cppobj;
};
// Python type information for RRsetCollectionBase
extern PyTypeObject rrset_collection_base_type;
// Python type information for dns.RRsetCollection
extern PyTypeObject rrset_collection_type;
bool initModulePart_RRsetCollectionBase(PyObject* mod);
bool initModulePart_RRsetCollection(PyObject* mod);
} // namespace python
} // namespace dns
} // namespace isc
#endif // PYTHON_RRSETCOLLECTION_H
// Local Variables:
// mode: c++
// End:
namespace {
// Modifications
// - libdns++ => isc.dns, libdatasrc => isc.datasrc
// - note about the constructor.
// - add note about iteration
const char* const RRsetCollectionBase_doc = "\
Generic class to represent a set of RRsets.\n\
\n\
This is a generic container and the stored set of RRsets does not\n\
necessarily form a valid zone (e.g. there doesn't necessarily have to\n\
be an SOA at the \"origin\"). Instead, it will be used to represent a\n\
single zone for the purpose of zone loading/checking. It provides a\n\
simple find() method to find an RRset for the given name and type (and\n\
maybe class) and a way to iterate over all RRsets.\n\
\n\
Note: in the initial version, iteration is not yet supported.\n\
\n\
See RRsetCollection for a simple isc.dns implementation. Other modules\n\
such as isc.datasrc will have another implementation.\n\
\n\
This base class cannot be directly instantiated, so no constructor is\n\
defined.\n\
\n\
";
// Modifications
// - ConstRRset => RRset
// - NULL => None
// - added types of params
const char* const RRsetCollectionBase_find_doc = "\
find(name, rrclass, rrtype) -> isc.dns.RRset\n\
\n\
Find a matching RRset in the collection.\n\
\n\
Returns the RRset in the collection that exactly matches the given\n\
name, rrclass and rrtype. If no matching RRset is found, None is\n\
returned.\n\
\n\
Parameters:\n\
name (isc.dns.Name) The name of the RRset to search for.\n\
rrtype (isc.dns.RRType) The type of the RRset to search for.\n\
rrclass (isc.dns.RRClass) The class of the RRset to search for.\n\
\n\
Return Value(s): The RRset if found, None otherwise.\n\
";
// Modifications
// - libdns++ => isc.dns
// - remove STL
// - MasterLoaderError => IscException
// - added types of params
// - input_stream => input, stream => bytes