Commit e7a49bee authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[trac905] main implementation for the support for TSIGError binding

parent ed62a7f4
# Copyright (C) 2010 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(), TSIGError(19).to_rcode())
self.assertEqual(Rcode.SERVFAIL(), TSIGError(65535).to_rcode())
# Check there's no redundant refcount (which would cause leak)
self.assertEqual(1, sys.getrefcount(TSIGError.BAD_SIG.to_rcode()))
if __name__ == '__main__':
unittest.main()
// 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 <string>
#include <stdexcept>
#include <util/python/pycppwrapper_util.h>
#include <dns/tsigerror.h>
#include "pydnspp_common.h"
#include "rcode_python.h"
#include "tsigerror_python.h"
using namespace std;
using namespace isc::util::python;
using namespace isc::dns;
using namespace isc::dns::python;
//
// Definition of the classes
//
// For each class, we need a struct, a helper functions (init, destroy,
// and static wrappers around the methods we export), a list of methods,
// and a type description
//
// TSIGError
//
// Trivial constructor.
s_TSIGError::s_TSIGError() : cppobj(NULL) {
}
namespace {
// Shortcut type which would be convenient for adding class variables safely.
typedef CPPPyObjectContainer<s_TSIGError, TSIGError> TSIGErrorContainer;
//
// We declare the functions here, the definitions are below
// the type definition of the object, since both can use the other
//
// General creation and destruction
int TSIGError_init(s_TSIGError* self, PyObject* args);
void TSIGError_destroy(s_TSIGError* self);
// These are the functions we export
PyObject* TSIGError_getCode(const s_TSIGError* const self);
PyObject* TSIGError_toText(const s_TSIGError* const self);
PyObject* TSIGError_toRcode(const s_TSIGError* const self);
PyObject* TSIGError_str(PyObject* self);
PyObject* TSIGError_richcmp(const s_TSIGError* const self,
const s_TSIGError* const other, int op);
// These are the functions we export
// For a minimal support, we don't need them.
// 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 TSIGError_methods[] = {
{ "get_code", reinterpret_cast<PyCFunction>(TSIGError_getCode),
METH_NOARGS,
"Returns the code value" },
{ "to_text", reinterpret_cast<PyCFunction>(TSIGError_toText), METH_NOARGS,
"Returns the text representation" },
{ "to_rcode", reinterpret_cast<PyCFunction>(TSIGError_toRcode),
METH_NOARGS,
"Convert the TSIGError to a Rcode" },
{ NULL, NULL, 0, NULL }
};
int
TSIGError_init(s_TSIGError* self, PyObject* args) {
try {
long code = 0;
if (PyArg_ParseTuple(args, "l", &code)) {
if (code < 0 || code > 0xffff) {
PyErr_SetString(PyExc_ValueError, "TSIG error out of range");
return (-1);
}
self->cppobj = new TSIGError(code);
return (0);
}
s_Rcode* py_rcode;
if (PyArg_ParseTuple(args, "O!", &rcode_type, &py_rcode)) {
self->cppobj = new TSIGError(*py_rcode->cppobj);
return (0);
}
} catch (const isc::OutOfRange& ex) {
const string ex_what = "Failed to construct TSIGError object: " +
string(ex.what());
PyErr_SetString(PyExc_ValueError, ex_what.c_str());
return (-1);
} catch (const exception& ex) {
const string ex_what = "Failed to construct TSIGError object: " +
string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
return (-1);
} catch (...) {
PyErr_SetString(po_IscException,
"Unexpected exception in constructing TSIGError");
return (-1);
}
PyErr_SetString(PyExc_TypeError,
"Invalid arguments to TSIGError constructor");
return (-1);
}
void
TSIGError_destroy(s_TSIGError* const self) {
delete self->cppobj;
self->cppobj = NULL;
Py_TYPE(self)->tp_free(self);
}
PyObject*
TSIGError_getCode(const s_TSIGError* const self) {
return (Py_BuildValue("I", self->cppobj->getCode()));
}
PyObject*
TSIGError_toText(const s_TSIGError* const self) {
try {
// toText() could throw, so we need to catch any exceptions below.
return (Py_BuildValue("s", self->cppobj->toText().c_str()));
} catch (const exception& ex) {
const string ex_what =
"Failed to convert TSIGError object to text: " +
string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
} catch (...) {
PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
"converting TSIGError object to text");
}
return (NULL);
}
PyObject*
TSIGError_str(PyObject* self) {
// Simply call the to_text method we already defined
return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
const_cast<char*>("")));
}
PyObject*
TSIGError_toRcode(const s_TSIGError* const self) {
typedef CPPPyObjectContainer<s_Rcode, Rcode> RcodePyObjectContainer;
try {
RcodePyObjectContainer rcode_container(PyObject_New(s_Rcode,
&rcode_type));
rcode_container.set(new Rcode(self->cppobj->toRcode()));
return (rcode_container.release());
} catch (const exception& ex) {
const string ex_what =
"Failed to convert TSIGError to Rcode: " + string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
} catch (...) {
PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
"converting TSIGError to Rcode");
}
return (NULL);
}
PyObject*
TSIGError_richcmp(const s_TSIGError* const self,
const s_TSIGError* const other,
const int op)
{
bool c = false;
// Check for null and if the types match. If different type,
// simply return False
if (other == NULL || (self->ob_type != other->ob_type)) {
Py_RETURN_FALSE;
}
// Only equals and not equals here, unorderable type
switch (op) {
case Py_LT:
PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
return (NULL);
case Py_LE:
PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
return (NULL);
case Py_EQ:
c = (*self->cppobj == *other->cppobj);
break;
case Py_NE:
c = (*self->cppobj != *other->cppobj);
break;
case Py_GT:
PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
return (NULL);
case Py_GE:
PyErr_SetString(PyExc_TypeError, "Unorderable type; TSIGError");
return (NULL);
}
if (c) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
} // 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_TSIGError
// Most of the functions are not actually implemented and NULL here.
PyTypeObject tsigerror_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"libdns_python.TSIGError",
sizeof(s_TSIGError), // tp_basicsize
0, // tp_itemsize
reinterpret_cast<destructor>(TSIGError_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
// THIS MAY HAVE TO BE CHANGED TO NULL:
TSIGError_str, // tp_str
NULL, // tp_getattro
NULL, // tp_setattro
NULL, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
"The TSIGError class objects represent standard errors related to "
"TSIG protocol operations as defined in related specifications, mainly "
"in RFC2845.",
NULL, // tp_traverse
NULL, // tp_clear
// THIS MAY HAVE TO BE CHANGED TO NULL:
reinterpret_cast<richcmpfunc>(TSIGError_richcmp), // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
TSIGError_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
reinterpret_cast<initproc>(TSIGError_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
};
namespace {
// Trivial shortcut to create and install TSIGError constants.
inline void
installTSIGErrorConstant(const char* name, const TSIGError& val) {
TSIGErrorContainer container(PyObject_New(s_TSIGError, &tsigerror_type));
container.installAsClassVariable(tsigerror_type, name, new TSIGError(val));
}
}
// Module Initialization, all statics are initialized here
bool
initModulePart_TSIGError(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(&tsigerror_type) < 0) {
return (false);
}
void* p = &tsigerror_type;
if (PyModule_AddObject(mod, "TSIGError", static_cast<PyObject*>(p)) < 0) {
return (false);
}
Py_INCREF(&tsigerror_type);
try {
// Constant class variables
// Error codes (bare values)
installClassVariable(tsigerror_type, "BAD_SIG_CODE",
Py_BuildValue("H", TSIGError::BAD_SIG_CODE));
installClassVariable(tsigerror_type, "BAD_KEY_CODE",
Py_BuildValue("H", TSIGError::BAD_KEY_CODE));
installClassVariable(tsigerror_type, "BAD_TIME_CODE",
Py_BuildValue("H", TSIGError::BAD_TIME_CODE));
// Error codes (constant objects)
installTSIGErrorConstant("NOERROR", TSIGError::NOERROR());
installTSIGErrorConstant("FORMERR", TSIGError::FORMERR());
installTSIGErrorConstant("SERVFAIL", TSIGError::SERVFAIL());
installTSIGErrorConstant("NXDOMAIN", TSIGError::NXDOMAIN());
installTSIGErrorConstant("NOTIMP", TSIGError::NOTIMP());
installTSIGErrorConstant("REFUSED", TSIGError::REFUSED());
installTSIGErrorConstant("YXDOMAIN", TSIGError::YXDOMAIN());
installTSIGErrorConstant("YXRRSET", TSIGError::YXRRSET());
installTSIGErrorConstant("NXRRSET", TSIGError::NXRRSET());
installTSIGErrorConstant("NOTAUTH", TSIGError::NOTAUTH());
installTSIGErrorConstant("NOTZONE", TSIGError::NOTZONE());
installTSIGErrorConstant("RESERVED11", TSIGError::RESERVED11());
installTSIGErrorConstant("RESERVED12", TSIGError::RESERVED12());
installTSIGErrorConstant("RESERVED13", TSIGError::RESERVED13());
installTSIGErrorConstant("RESERVED14", TSIGError::RESERVED14());
installTSIGErrorConstant("RESERVED15", TSIGError::RESERVED15());
installTSIGErrorConstant("BAD_SIG", TSIGError::BAD_SIG());
installTSIGErrorConstant("BAD_KEY", TSIGError::BAD_KEY());
installTSIGErrorConstant("BAD_TIME", TSIGError::BAD_TIME());
} catch (const exception& ex) {
const string ex_what =
"Unexpected failure in TSIGError initialization: " +
string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
return (false);
} catch (...) {
PyErr_SetString(PyExc_SystemError,
"Unexpected failure in TSIGError initialization");
return (false);
}
return (true);
}
} // 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_TSIGERROR_H
#define __PYTHON_TSIGERROR_H 1
#include <Python.h>
namespace isc {
namespace dns {
class TSIGError;
namespace python {
// The s_* Class simply covers one instantiation of the object
class s_TSIGError : public PyObject {
public:
s_TSIGError();
const TSIGError* cppobj;
};
extern PyTypeObject tsigerror_type;
bool initModulePart_TSIGError(PyObject* mod);
} // namespace python
} // namespace dns
} // namespace isc
#endif // __PYTHON_TSIGERROR_H
// Local Variables:
// mode: c++
// End:
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment