// Copyright (C) 2010 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 #include #include #include #include "pydnspp_common.h" #include "rcode_python.h" using namespace isc::dns; using namespace isc::dns::python; using namespace isc::util::python; namespace { // 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() : cppobj(NULL), static_code(false) {}; const Rcode* cppobj; bool static_code; }; typedef CPPPyObjectContainer RcodeContainer; int Rcode_init(s_Rcode* const self, PyObject* args); void Rcode_destroy(s_Rcode* const self); PyObject* Rcode_getCode(const s_Rcode* const self); PyObject* Rcode_getExtendedCode(const s_Rcode* const self); PyObject* Rcode_toText(const s_Rcode* const self); PyObject* Rcode_str(PyObject* self); PyObject* Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other, int op); PyMethodDef Rcode_methods[] = { { "get_code", reinterpret_cast(Rcode_getCode), METH_NOARGS, "Returns the code value" }, { "get_extended_code", reinterpret_cast(Rcode_getExtendedCode), METH_NOARGS, "Returns the upper 8-bit part of the extended code value" }, { "to_text", reinterpret_cast(Rcode_toText), METH_NOARGS, "Returns the text representation" }, { NULL, NULL, 0, NULL } }; int Rcode_init(s_Rcode* const self, PyObject* args) { long code = 0; int ext_code = 0; if (PyArg_ParseTuple(args, "l", &code)) { if (code < 0 || code > 0xffff) { PyErr_SetString(PyExc_ValueError, "Rcode out of range"); return (-1); } ext_code = -1; } else if (PyArg_ParseTuple(args, "li", &code, &ext_code)) { if (code < 0 || code > 0xff || ext_code < 0 || ext_code > 0xff) { PyErr_SetString(PyExc_ValueError, "Rcode out of range"); return (-1); } } else { PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "Invalid arguments to Rcode constructor"); return (-1); } try { if (ext_code == -1) { self->cppobj = new Rcode(code); } else { self->cppobj = new Rcode(code, ext_code); } self->static_code = false; } catch (const isc::OutOfRange& ex) { PyErr_SetString(PyExc_OverflowError, ex.what()); return (-1); } catch (...) { PyErr_SetString(po_IscException, "Unexpected exception"); return (-1); } return (0); } 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->cppobj here if (!self->static_code) { delete self->cppobj; } self->cppobj = NULL; Py_TYPE(self)->tp_free(self); } PyObject* Rcode_getCode(const s_Rcode* const self) { return (Py_BuildValue("I", self->cppobj->getCode())); } PyObject* Rcode_getExtendedCode(const s_Rcode* const self) { return (Py_BuildValue("I", self->cppobj->getExtendedCode())); } PyObject* Rcode_toText(const s_Rcode* const self) { return (Py_BuildValue("s", self->cppobj->toText().c_str())); } PyObject* Rcode_str(PyObject* self) { // Simply call the to_text method we already defined return (PyObject_CallMethod(self, const_cast("to_text"), const_cast(""))); } PyObject* Rcode_richcmp(const s_Rcode* const self, const s_Rcode* const other, const 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; } // Only equals and not equals here, unorderable type switch (op) { case Py_LT: PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode"); return (NULL); case Py_LE: PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode"); 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; Rcode"); return (NULL); case Py_GE: PyErr_SetString(PyExc_TypeError, "Unorderable type; Rcode"); return (NULL); } if (c) Py_RETURN_TRUE; 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(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 }; PyObject* createRcodeObject(const Rcode& source) { RcodeContainer container(PyObject_New(s_Rcode, &rcode_type)); container.set(new Rcode(source)); return (container.release()); } bool PyRcode_Check(PyObject* obj) { if (obj == NULL) { isc_throw(PyCPPWrapperException, "obj argument NULL in typecheck"); } return (PyObject_TypeCheck(obj, &rcode_type)); } const Rcode& PyRcode_ToRcode(const PyObject* rcode_obj) { if (rcode_obj == NULL) { isc_throw(PyCPPWrapperException, "obj argument NULL in Rcode PyObject conversion"); } const s_Rcode* rcode = static_cast(rcode_obj); return (*rcode->cppobj); } } // namespace python } // namespace dns } // namespace isc