Browse Source

[1245] move all s_ decls to inside the .cc

Added a lot of conversion functions for that
Jelte Jansen 13 years ago
parent
commit
1808345838
35 changed files with 821 additions and 466 deletions
  1. 52 20
      src/lib/dns/python/edns_python.cc
  2. 27 10
      src/lib/dns/python/edns_python.h
  3. 38 81
      src/lib/dns/python/message_python.cc
  4. 0 5
      src/lib/dns/python/message_python.h
  5. 50 1
      src/lib/dns/python/messagerenderer_python.cc
  6. 27 12
      src/lib/dns/python/messagerenderer_python.h
  7. 18 5
      src/lib/dns/python/name_python.cc
  8. 1 15
      src/lib/dns/python/name_python.h
  9. 30 0
      src/lib/dns/python/opcode_python.cc
  10. 27 13
      src/lib/dns/python/opcode_python.h
  11. 2 2
      src/lib/dns/python/pydnspp_towire.h
  12. 36 36
      src/lib/dns/python/question_python.cc
  13. 27 5
      src/lib/dns/python/question_python.h
  14. 42 4
      src/lib/dns/python/rcode_python.cc
  15. 27 20
      src/lib/dns/python/rcode_python.h
  16. 40 7
      src/lib/dns/python/rdata_python.cc
  17. 27 5
      src/lib/dns/python/rdata_python.h
  18. 11 5
      src/lib/dns/python/rrclass_python.cc
  19. 1 12
      src/lib/dns/python/rrclass_python.h
  20. 44 81
      src/lib/dns/python/rrset_python.cc
  21. 9 12
      src/lib/dns/python/rrset_python.h
  22. 29 4
      src/lib/dns/python/rrttl_python.cc
  23. 26 6
      src/lib/dns/python/rrttl_python.h
  24. 9 5
      src/lib/dns/python/rrtype_python.cc
  25. 1 8
      src/lib/dns/python/rrtype_python.h
  26. 29 16
      src/lib/dns/python/tsig_python.cc
  27. 19 7
      src/lib/dns/python/tsig_python.h
  28. 20 4
      src/lib/dns/python/tsig_rdata_python.cc
  29. 18 7
      src/lib/dns/python/tsig_rdata_python.h
  30. 10 12
      src/lib/dns/python/tsigerror_python.cc
  31. 1 7
      src/lib/dns/python/tsigerror_python.h
  32. 45 14
      src/lib/dns/python/tsigkey_python.cc
  33. 36 13
      src/lib/dns/python/tsigkey_python.h
  34. 24 5
      src/lib/dns/python/tsigrecord_python.cc
  35. 18 7
      src/lib/dns/python/tsigrecord_python.h

+ 52 - 20
src/lib/dns/python/edns_python.cc

@@ -19,6 +19,7 @@
 #include <dns/edns.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "edns_python.h"
 #include "name_python.h"
@@ -30,12 +31,20 @@
 #include "pydnspp_common.h"
 
 using namespace isc::dns;
-using namespace isc::util;
 using namespace isc::dns::rdata;
 using namespace isc::dns::python;
+using namespace isc::util;
+using namespace isc::util::python;
 
 namespace {
 
+class s_EDNS : public PyObject {
+public:
+    EDNS* cppobj;
+};
+
+typedef CPPPyObjectContainer<s_EDNS, EDNS> EDNSContainer;
+
 // General creation and destruction
 int EDNS_init(s_EDNS* self, PyObject* args);
 void EDNS_destroy(s_EDNS* self);
@@ -116,11 +125,11 @@ createFromRR(const Name& name, const RRClass& rrclass, const RRType& rrtype,
 int
 EDNS_init(s_EDNS* self, PyObject* args) {
     uint8_t version = EDNS::SUPPORTED_VERSION;
-    const s_Name* name;
-    const s_RRClass* rrclass;
-    const s_RRType* rrtype;
-    const s_RRTTL* rrttl;
-    const s_Rdata* rdata;
+    const PyObject* name;
+    const PyObject* rrclass;
+    const PyObject* rrtype;
+    const PyObject* rrttl;
+    const PyObject* rdata;
 
     if (PyArg_ParseTuple(args, "|b", &version)) {
         try {
@@ -140,9 +149,11 @@ EDNS_init(s_EDNS* self, PyObject* args) {
         // in this context so that we can share the try-catch logic with
         // EDNS_createFromRR() (see below).
         uint8_t extended_rcode;
-        self->cppobj = createFromRR(*name->cppobj, *rrclass->cppobj,
-                                  *rrtype->cppobj, *rrttl->cppobj,
-                                  *rdata->cppobj, extended_rcode);
+        self->cppobj = createFromRR(PyName_ToName(name),
+                                    PyRRClass_ToRRClass(rrclass),
+                                    PyRRType_ToRRType(rrtype),
+                                    PyRRTTL_ToRRTTL(rrttl),
+                                    PyRdata_ToRdata(rdata), extended_rcode);
         return (self->cppobj != NULL ? 0 : -1);
     }
 
@@ -177,7 +188,7 @@ PyObject*
 EDNS_toWire(const s_EDNS* const self, PyObject* args) {
     PyObject* bytes;
     uint8_t extended_rcode;
-    s_MessageRenderer* renderer;
+    PyObject* renderer;
 
     if (PyArg_ParseTuple(args, "Ob", &bytes, &extended_rcode) &&
         PySequence_Check(bytes)) {
@@ -194,8 +205,8 @@ EDNS_toWire(const s_EDNS* const self, PyObject* args) {
         return (result);
     } else if (PyArg_ParseTuple(args, "O!b", &messagerenderer_type,
                                 &renderer, &extended_rcode)) {
-        const unsigned int n = self->cppobj->toWire(*renderer->cppobj,
-                                                  extended_rcode);
+        const unsigned int n = self->cppobj->toWire(
+            PyMessageRenderer_ToMessageRenderer(renderer), extended_rcode);
 
         return (Py_BuildValue("I", n));
     }
@@ -253,11 +264,11 @@ EDNS_setUDPSize(s_EDNS* self, PyObject* args) {
 
 PyObject*
 EDNS_createFromRR(const s_EDNS* null_self, PyObject* args) {
-    const s_Name* name;
-    const s_RRClass* rrclass;
-    const s_RRType* rrtype;
-    const s_RRTTL* rrttl;
-    const s_Rdata* rdata;
+    const PyObject* name;
+    const PyObject* rrclass;
+    const PyObject* rrtype;
+    const PyObject* rrttl;
+    const PyObject* rdata;
     s_EDNS* edns_obj = NULL;
 
     assert(null_self == NULL);
@@ -271,9 +282,12 @@ EDNS_createFromRR(const s_EDNS* null_self, PyObject* args) {
             return (NULL);
         }
 
-        edns_obj->cppobj = createFromRR(*name->cppobj, *rrclass->cppobj,
-                                        *rrtype->cppobj, *rrttl->cppobj,
-                                        *rdata->cppobj, extended_rcode);
+        edns_obj->cppobj = createFromRR(PyName_ToName(name),
+                                        PyRRClass_ToRRClass(rrclass),
+                                        PyRRType_ToRRType(rrtype),
+                                        PyRRTTL_ToRRTTL(rrttl),
+                                        PyRdata_ToRdata(rdata),
+                                        extended_rcode);
         if (edns_obj->cppobj != NULL) {
             PyObject* extrcode_obj = Py_BuildValue("B", extended_rcode);
             return (Py_BuildValue("OO", edns_obj, extrcode_obj));
@@ -369,6 +383,24 @@ initModulePart_EDNS(PyObject* mod) {
 }
 } // end namespace internal
 
+PyObject*
+createEDNSObject(const EDNS& source) {
+    EDNSContainer container = PyObject_New(s_EDNS, &edns_type);
+    container.set(new EDNS(source));
+    return (container.release());
+}
+
+bool
+PyEDNS_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &edns_type));
+}
+
+const EDNS&
+PyEDNS_ToEDNS(const PyObject* edns_obj) {
+    const s_EDNS* edns = static_cast<const s_EDNS*>(edns_obj);
+    return (*edns->cppobj);
+}
+
 } // end namespace python
 } // end namespace dns
 } // end namespace isc

+ 27 - 10
src/lib/dns/python/edns_python.h

@@ -23,18 +23,35 @@ namespace isc {
 namespace dns {
 namespace python {
 
-//
-// Declaration of the custom exceptions
-// Initialization and addition of these go in the module init at the
-// end
-//
-class s_EDNS : public PyObject {
-public:
-    EDNS* cppobj;
-};
-
 extern PyTypeObject edns_type;
 
+/// This is a simple shortcut to create a python EDNS 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* createEDNSObject(const EDNS& source);
+
+/// \brief Checks if the given python object is a EDNS object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type EDNS, false otherwise
+bool PyEDNS_Check(PyObject* obj);
+
+/// \brief Returns a reference to the EDNS object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type EDNS; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyEDNS_Check()
+///
+/// \note This is not a copy; if the EDNS is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param edns_obj The edns object to convert
+const EDNS& PyEDNS_ToEDNS(const PyObject* edns_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 38 - 81
src/lib/dns/python/message_python.cc

@@ -40,6 +40,10 @@ using namespace isc::dns::python;
 using namespace isc::util;
 
 namespace {
+class s_Message : public PyObject {
+public:
+    isc::dns::Message* cppobj;
+};
 
 int Message_init(s_Message* self, PyObject* args);
 void Message_destroy(s_Message* self);
@@ -274,35 +278,25 @@ Message_setQid(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_getRcode(s_Message* self) {
-    s_Rcode* rcode;
-
-    rcode = static_cast<s_Rcode*>(rcode_type.tp_alloc(&rcode_type, 0));
-    if (rcode != NULL) {
-        rcode->cppobj = NULL;
-        try {
-            rcode->cppobj = new Rcode(self->cppobj->getRcode());
-        } catch (const InvalidMessageOperation& imo) {
-            PyErr_SetString(po_InvalidMessageOperation, imo.what());
-        } catch (...) {
-            PyErr_SetString(po_IscException, "Unexpected exception");
-        }
-        if (rcode->cppobj == NULL) {
-            Py_DECREF(rcode);
-            return (NULL);
-        }
+    try {
+        return (createRcodeObject(self->cppobj->getRcode()));
+    } catch (const InvalidMessageOperation& imo) {
+        PyErr_SetString(po_InvalidMessageOperation, imo.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(po_IscException, "Unexpected exception");
+        return (NULL);
     }
-
-    return (rcode);
 }
 
 PyObject*
 Message_setRcode(s_Message* self, PyObject* args) {
-    s_Rcode* rcode;
+    PyObject* rcode;
     if (!PyArg_ParseTuple(args, "O!", &rcode_type, &rcode)) {
         return (NULL);
     }
     try {
-        self->cppobj->setRcode(*rcode->cppobj);
+        self->cppobj->setRcode(PyRcode_ToRcode(rcode));
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -312,35 +306,25 @@ Message_setRcode(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_getOpcode(s_Message* self) {
-    s_Opcode* opcode;
-
-    opcode = static_cast<s_Opcode*>(opcode_type.tp_alloc(&opcode_type, 0));
-    if (opcode != NULL) {
-        opcode->cppobj = NULL;
-        try {
-            opcode->cppobj = new Opcode(self->cppobj->getOpcode());
-        } catch (const InvalidMessageOperation& imo) {
-            PyErr_SetString(po_InvalidMessageOperation, imo.what());
-        } catch (...) {
-            PyErr_SetString(po_IscException, "Unexpected exception");
-        }
-        if (opcode->cppobj == NULL) {
-            Py_DECREF(opcode);
-            return (NULL);
-        }
+    try {
+        return (createOpcodeObject(self->cppobj->getOpcode()));
+    } catch (const InvalidMessageOperation& imo) {
+        PyErr_SetString(po_InvalidMessageOperation, imo.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(po_IscException, "Unexpected exception");
+        return (NULL);
     }
-
-    return (opcode);
 }
 
 PyObject*
 Message_setOpcode(s_Message* self, PyObject* args) {
-    s_Opcode* opcode;
+    PyObject* opcode;
     if (!PyArg_ParseTuple(args, "O!", &opcode_type, &opcode)) {
         return (NULL);
     }
     try {
-        self->cppobj->setOpcode(*opcode->cppobj);
+        self->cppobj->setOpcode(PyOpcode_ToOpcode(opcode));
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -350,32 +334,21 @@ Message_setOpcode(s_Message* self, PyObject* args) {
 
 PyObject*
 Message_getEDNS(s_Message* self) {
-    s_EDNS* edns;
-    EDNS* edns_body;
     ConstEDNSPtr src = self->cppobj->getEDNS();
-
     if (!src) {
         Py_RETURN_NONE;
     }
-    if ((edns_body = new(nothrow) EDNS(*src)) == NULL) {
-        return (PyErr_NoMemory());
-    }
-    edns = static_cast<s_EDNS*>(opcode_type.tp_alloc(&edns_type, 0));
-    if (edns != NULL) {
-        edns->cppobj = edns_body;
-    }
-
-    return (edns);
+    return (createEDNSObject(*src));
 }
 
 PyObject*
 Message_setEDNS(s_Message* self, PyObject* args) {
-    s_EDNS* edns;
+    PyObject* edns;
     if (!PyArg_ParseTuple(args, "O!", &edns_type, &edns)) {
         return (NULL);
     }
     try {
-        self->cppobj->setEDNS(EDNSPtr(new EDNS(*edns->cppobj)));
+        self->cppobj->setEDNS(EDNSPtr(new EDNS(PyEDNS_ToEDNS(edns))));
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -446,20 +419,10 @@ Message_getQuestion(s_Message* self) {
     }
 
     for (; qi != qi_end; ++qi) {
-        s_Question *question = static_cast<s_Question*>(
-            question_type.tp_alloc(&question_type, 0));
-        if (question == NULL) {
-            Py_DECREF(question);
+        if (PyList_Append(list, createQuestionObject(**qi)) == -1) {
             Py_DECREF(list);
             return (NULL);
         }
-        question->cppobj = *qi;
-        if (PyList_Append(list, question) == -1) {
-            Py_DECREF(question);
-            Py_DECREF(list);
-            return (NULL);
-        }
-        Py_DECREF(question);
     }
     return (list);
 }
@@ -496,14 +459,7 @@ Message_getSection(s_Message* self, PyObject* args) {
         return (NULL);
     }
     for (; rrsi != rrsi_end; ++rrsi) {
-        s_RRset *rrset = static_cast<s_RRset*>(
-            rrset_type.tp_alloc(&rrset_type, 0));
-        if (rrset == NULL) {
-                Py_DECREF(rrset);
-                Py_DECREF(list);
-                return (NULL);
-        }
-        rrset->cppobj = *rrsi;
+        PyObject* rrset = createRRsetObject(**rrsi);
         if (PyList_Append(list, rrset) == -1) {
                 Py_DECREF(rrset);
                 Py_DECREF(list);
@@ -523,13 +479,13 @@ Message_getSection(s_Message* self, PyObject* args) {
 //static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
 PyObject*
 Message_addQuestion(s_Message* self, PyObject* args) {
-    s_Question *question;
+    PyObject* question;
 
     if (!PyArg_ParseTuple(args, "O!", &question_type, &question)) {
         return (NULL);
     }
 
-    self->cppobj->addQuestion(question->cppobj);
+    self->cppobj->addQuestion(PyQuestion_ToQuestion(question));
 
     Py_RETURN_NONE;
 }
@@ -538,7 +494,7 @@ PyObject*
 Message_addRRset(s_Message* self, PyObject* args) {
     PyObject *sign = Py_False;
     int section;
-    s_RRset* rrset;
+    PyObject* rrset;
     if (!PyArg_ParseTuple(args, "iO!|O!", &section, &rrset_type, &rrset,
                           &PyBool_Type, &sign)) {
         return (NULL);
@@ -546,7 +502,7 @@ Message_addRRset(s_Message* self, PyObject* args) {
 
     try {
         self->cppobj->addRRset(static_cast<Message::Section>(section),
-                               rrset->cppobj, sign == Py_True);
+                               PyRRset_ToRRsetPtr(rrset), sign == Py_True);
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
@@ -613,16 +569,17 @@ Message_str(PyObject* self) {
 
 PyObject*
 Message_toWire(s_Message* self, PyObject* args) {
-    s_MessageRenderer* mr;
-    s_TSIGContext* tsig_ctx = NULL;
+    PyObject* mr;
+    PyObject* tsig_ctx = NULL;
 
     if (PyArg_ParseTuple(args, "O!|O!", &messagerenderer_type, &mr,
                          &tsigcontext_type, &tsig_ctx)) {
         try {
             if (tsig_ctx == NULL) {
-                self->cppobj->toWire(*mr->cppobj);
+                self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
             } else {
-                self->cppobj->toWire(*mr->cppobj, *tsig_ctx->cppobj);
+                self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr),
+                                     PyTSIGContext_ToTSIGContext(tsig_ctx));
             }
             // If we return NULL it is seen as an error, so use this for
             // None returns

+ 0 - 5
src/lib/dns/python/message_python.h

@@ -33,11 +33,6 @@ extern PyObject* po_InvalidMessageSection;
 extern PyObject* po_InvalidMessageOperation;
 extern PyObject* po_InvalidMessageUDPSize;
 
-class s_Message : public PyObject {
-public:
-    isc::dns::Message* cppobj;
-};
-
 extern PyTypeObject message_type;
 
 } // namespace python

+ 50 - 1
src/lib/dns/python/messagerenderer_python.cc

@@ -17,6 +17,7 @@
 #include <util/buffer.h>
 
 #include <dns/messagerenderer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "pydnspp_common.h"
 #include "messagerenderer_python.h"
@@ -24,8 +25,21 @@
 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.
+//
+// since we don't use *Buffer in the python version (but work with
+// the already existing bytearray type where we use these custom buffers
+// in C++, we need to keep track of one here.
+class s_MessageRenderer : public PyObject {
+public:
+    s_MessageRenderer();
+    isc::util::OutputBuffer* outputbuffer;
+    MessageRenderer* cppobj;
+};
+
 int MessageRenderer_init(s_MessageRenderer* self);
 void MessageRenderer_destroy(s_MessageRenderer* self);
 
@@ -81,7 +95,7 @@ MessageRenderer_destroy(s_MessageRenderer* self) {
 PyObject*
 MessageRenderer_getData(s_MessageRenderer* self) {
     return (Py_BuildValue("y#",
-                         self->cppobj->getData(),
+                          self->cppobj->getData(),
                           self->cppobj->getLength()));
 }
 
@@ -244,6 +258,41 @@ bool initModulePart_MessageRenderer(PyObject* mod) {
 }
 } // end namespace internal
 
+PyObject*
+createMessageRendererObject(const MessageRenderer& source) {
+    // should we copy? can we?
+    // copy the existing buffer into a new one, then create a new renderer with
+    // that buffer
+    s_MessageRenderer* mr = static_cast<s_MessageRenderer*>(
+        messagerenderer_type.tp_alloc(&messagerenderer_type, 0));
+    if (mr == NULL) {
+        isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+                  "probably due to short memory");
+    }
+    try {
+        mr->outputbuffer = new OutputBuffer(4096);
+        mr->outputbuffer->writeData(source.getData(), source.getLength());
+        mr->cppobj = new MessageRenderer(*mr->outputbuffer);
+
+        return (mr);
+    } catch (const std::bad_alloc&) {
+        isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+                  "probably due to short memory");
+    }
+}
+
+bool
+PyMessageRenderer_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &messagerenderer_type));
+}
+
+MessageRenderer&
+PyMessageRenderer_ToMessageRenderer(PyObject* messagerenderer_obj) {
+    s_MessageRenderer* messagerenderer = static_cast<s_MessageRenderer*>(messagerenderer_obj);
+    return (*messagerenderer->cppobj);
+}
+
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 27 - 12
src/lib/dns/python/messagerenderer_python.h

@@ -24,20 +24,35 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object.
-//
-// since we don't use *Buffer in the python version (but work with
-// the already existing bytearray type where we use these custom buffers
-// in C++, we need to keep track of one here.
-class s_MessageRenderer : public PyObject {
-public:
-    s_MessageRenderer();
-    isc::util::OutputBuffer* outputbuffer;
-    MessageRenderer* cppobj;
-};
-
 extern PyTypeObject messagerenderer_type;
 
+/// This is a simple shortcut to create a python MessageRenderer 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* createMessageRendererObject(const MessageRenderer& source);
+
+/// \brief Checks if the given python object is a MessageRenderer object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type MessageRenderer, false otherwise
+bool PyMessageRenderer_Check(PyObject* obj);
+
+/// \brief Returns a reference to the MessageRenderer object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type MessageRenderer; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyMessageRenderer_Check()
+///
+/// \note This is not a copy; if the MessageRenderer is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param messagerenderer_obj The messagerenderer object to convert
+MessageRenderer& PyMessageRenderer_ToMessageRenderer(PyObject* messagerenderer_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 18 - 5
src/lib/dns/python/name_python.cc

@@ -31,6 +31,19 @@ using namespace isc::util;
 using namespace isc::util::python;
 
 namespace {
+// The s_* Class simply covers one instantiation of the object.
+class s_NameComparisonResult : public PyObject {
+public:
+    s_NameComparisonResult() : cppobj(NULL) {}
+    NameComparisonResult* cppobj;
+};
+
+class s_Name : public PyObject {
+public:
+    s_Name() : cppobj(NULL), position(0) {}
+    Name* cppobj;
+    size_t position;
+};
 
 int NameComparisonResult_init(s_NameComparisonResult*, PyObject*);
 void NameComparisonResult_destroy(s_NameComparisonResult* self);
@@ -282,7 +295,7 @@ Name_str(PyObject* self) {
 PyObject*
 Name_toWire(s_Name* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -296,7 +309,7 @@ Name_toWire(s_Name* self, PyObject* args) {
         Py_DECREF(name_bytes);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->cppobj);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -719,9 +732,9 @@ PyName_Check(PyObject* obj) {
     return (PyObject_TypeCheck(obj, &name_type));
 }
 
-Name&
-PyName_ToName(PyObject* name_obj) {
-    s_Name* name = static_cast<s_Name*>(name_obj);
+const Name&
+PyName_ToName(const PyObject* name_obj) {
+    const s_Name* name = static_cast<const s_Name*>(name_obj);
     return (*name->cppobj);
 }
 

+ 1 - 15
src/lib/dns/python/name_python.h

@@ -44,20 +44,6 @@ extern PyObject* po_DNSMessageFORMERR;
 //
 extern PyObject* po_NameRelation;
 
-// The s_* Class simply covers one instantiation of the object.
-class s_NameComparisonResult : public PyObject {
-public:
-    s_NameComparisonResult() : cppobj(NULL) {}
-    NameComparisonResult* cppobj;
-};
-
-class s_Name : public PyObject {
-public:
-    s_Name() : cppobj(NULL), position(0) {}
-    Name* cppobj;
-    size_t position;
-};
-
 extern PyTypeObject name_comparison_result_type;
 extern PyTypeObject name_type;
 
@@ -86,7 +72,7 @@ bool PyName_Check(PyObject* obj);
 /// may be destroyed, the caller must copy it itself.
 ///
 /// \param name_obj The name object to convert
-Name& PyName_ToName(PyObject* name_obj);
+const Name& PyName_ToName(const PyObject* name_obj);
 
 } // namespace python
 } // namespace dns

+ 30 - 0
src/lib/dns/python/opcode_python.cc

@@ -15,6 +15,7 @@
 #include <Python.h>
 
 #include <dns/opcode.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "pydnspp_common.h"
 #include "opcode_python.h"
@@ -23,9 +24,19 @@
 using namespace isc::dns;
 using namespace isc::dns::python;
 using namespace isc::util;
+using namespace isc::util::python;
 
 namespace {
 
+class s_Opcode : public PyObject {
+public:
+    s_Opcode() : cppobj(NULL), static_code(false) {}
+    const isc::dns::Opcode* cppobj;
+    bool static_code;
+};
+
+typedef CPPPyObjectContainer<s_Opcode, Opcode> OpcodeContainer;
+
 int Opcode_init(s_Opcode* const self, PyObject* args);
 void Opcode_destroy(s_Opcode* const self);
 
@@ -383,6 +394,25 @@ initModulePart_Opcode(PyObject* mod) {
 }
 } // end namespace internal
 
+
+PyObject*
+createOpcodeObject(const Opcode& source) {
+    OpcodeContainer container = PyObject_New(s_Opcode, &opcode_type);
+    container.set(new Opcode(source));
+    return (container.release());
+}
+
+bool
+PyOpcode_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &opcode_type));
+}
+
+const Opcode&
+PyOpcode_ToOpcode(const PyObject* opcode_obj) {
+    const s_Opcode* opcode = static_cast<const s_Opcode*>(opcode_obj);
+    return (*opcode->cppobj);
+}
+
 } // end python namespace
 } // end dns namespace
 } // end isc namespace

+ 27 - 13
src/lib/dns/python/opcode_python.h

@@ -23,21 +23,35 @@ namespace isc {
 namespace dns {
 namespace python {
 
-//
-// Declaration of the custom exceptions
-// Initialization and addition of these go in the module init at the
-// end
-//
-
-class s_Opcode : public PyObject {
-public:
-    s_Opcode() : cppobj(NULL), static_code(false) {}
-    const isc::dns::Opcode* cppobj;
-    bool static_code;
-};
-
 extern PyTypeObject opcode_type;
 
+/// This is a simple shortcut to create a python Opcode 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* createOpcodeObject(const Opcode& source);
+
+/// \brief Checks if the given python object is a Opcode object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Opcode, false otherwise
+bool PyOpcode_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Opcode object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Opcode; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyOpcode_Check()
+///
+/// \note This is not a copy; if the Opcode is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param opcode_obj The opcode object to convert
+const Opcode& PyOpcode_ToOpcode(const PyObject* opcode_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 2 - 2
src/lib/dns/python/pydnspp_towire.h

@@ -93,10 +93,10 @@ toWireWrapper(const PYSTRUCT* const self, PyObject* args) {
         }
 
         // To MessageRenderer version
-        s_MessageRenderer* renderer;
+        PyObject* renderer;
         if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &renderer)) {
             const unsigned int n = TOWIRECALLER(*self->cppobj)(
-                *renderer->cppobj);
+                PyMessageRenderer_ToMessageRenderer(renderer));
 
             return (Py_BuildValue("I", n));
         }

+ 36 - 36
src/lib/dns/python/question_python.cc

@@ -32,6 +32,10 @@ using namespace isc::util;
 using namespace isc;
 
 namespace {
+class s_Question : public PyObject {
+public:
+    isc::dns::QuestionPtr cppobj;
+};
 
 static int Question_init(s_Question* self, PyObject* args);
 static void Question_destroy(s_Question* self);
@@ -79,9 +83,9 @@ Question_init(s_Question* self, PyObject* args) {
     // that if we try several like here. Otherwise the *next* python
     // call will suddenly appear to throw an exception.
     // (the way to do exceptions is to set PyErr and return -1)
-    s_Name* name;
-    s_RRClass* rrclass;
-    s_RRType* rrtype;
+    PyObject* name;
+    PyObject* rrclass;
+    PyObject* rrtype;
 
     const char* b;
     Py_ssize_t len;
@@ -89,12 +93,12 @@ Question_init(s_Question* self, PyObject* args) {
 
     try {
         if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &name,
-                                               &rrclass_type, &rrclass,
-                                               &rrtype_type, &rrtype
+                                             &rrclass_type, &rrclass,
+                                             &rrtype_type, &rrtype
            )) {
-            self->cppobj = QuestionPtr(new Question(*name->cppobj,
-                                       *rrclass->cppobj,
-                                       *rrtype->cppobj));
+            self->cppobj = QuestionPtr(new Question(PyName_ToName(name),
+                                                    PyRRClass_ToRRClass(rrclass),
+                                                    PyRRType_ToRRType(rrtype)));
             return (0);
         } else if (PyArg_ParseTuple(args, "y#|I", &b, &len, &position)) {
             PyErr_Clear();
@@ -133,42 +137,19 @@ Question_destroy(s_Question* self) {
 
 static PyObject*
 Question_getName(s_Question* self) {
-    s_Name* name;
-
-    // is this the best way to do this?
-    name = static_cast<s_Name*>(name_type.tp_alloc(&name_type, 0));
-    if (name != NULL) {
-        name->cppobj = new Name(self->cppobj->getName());
-    }
-
-    return (name);
+    return (createNameObject(self->cppobj->getName()));
 }
 
 static PyObject*
 Question_getType(s_Question* self) {
-    s_RRType* rrtype;
-
-    rrtype = static_cast<s_RRType*>(rrtype_type.tp_alloc(&rrtype_type, 0));
-    if (rrtype != NULL) {
-        rrtype->cppobj = new RRType(self->cppobj->getType());
-    }
-
-    return (rrtype);
+    return (createRRTypeObject(self->cppobj->getType()));
 }
 
 static PyObject*
 Question_getClass(s_Question* self) {
-    s_RRClass* rrclass;
-
-    rrclass = static_cast<s_RRClass*>(rrclass_type.tp_alloc(&rrclass_type, 0));
-    if (rrclass != NULL) {
-        rrclass->cppobj = new RRClass(self->cppobj->getClass());
-    }
-
-    return (rrclass);
+    return (createRRClassObject(self->cppobj->getClass()));
 }
 
-
 static PyObject*
 Question_toText(s_Question* self) {
     // Py_BuildValue makes python objects from native data
@@ -186,7 +167,7 @@ Question_str(PyObject* self) {
 static PyObject*
 Question_toWire(s_Question* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -202,7 +183,7 @@ Question_toWire(s_Question* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->cppobj);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -292,6 +273,25 @@ initModulePart_Question(PyObject* mod) {
 }
 } // end namespace internal
 
+PyObject*
+createQuestionObject(const Question& source) {
+    s_Question* question =
+        static_cast<s_Question*>(question_type.tp_alloc(&question_type, 0));
+    question->cppobj = QuestionPtr(new Question(source));
+    return (question);
+}
+
+bool
+PyQuestion_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &question_type));
+}
+
+const Question&
+PyQuestion_ToQuestion(const PyObject* question_obj) {
+    const s_Question* question = static_cast<const s_Question*>(question_obj);
+    return (*question->cppobj);
+}
+
 } // end python namespace
 } // end dns namespace
 } // end isc namespace

+ 27 - 5
src/lib/dns/python/question_python.h

@@ -30,13 +30,35 @@ namespace python {
 //
 extern PyObject* po_EmptyQuestion;
 
-class s_Question : public PyObject {
-public:
-    isc::dns::QuestionPtr cppobj;
-};
-
 extern PyTypeObject question_type;
 
+/// This is a simple shortcut to create a python Question 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* createQuestionObject(const Question& source);
+
+/// \brief Checks if the given python object is a Question object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Question, false otherwise
+bool PyQuestion_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Question object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Question; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyQuestion_Check()
+///
+/// \note This is not a copy; if the Question is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param question_obj The question object to convert
+const Question& PyQuestion_ToQuestion(const PyObject* question_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 42 - 4
src/lib/dns/python/rcode_python.cc

@@ -15,19 +15,39 @@
 #include <Python.h>
 
 #include <exceptions/exceptions.h>
-
 #include <dns/rcode.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "pydnspp_common.h"
 #include "rcode_python.h"
 
 using namespace isc::dns;
 using namespace isc::dns::python;
-
-// Trivial constructor.
-s_Rcode::s_Rcode() : cppobj(NULL), static_code(false) {}
+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<s_Rcode, Rcode> RcodeContainer;
+
 int Rcode_init(s_Rcode* const self, PyObject* args);
 void Rcode_destroy(s_Rcode* const self);
 
@@ -416,6 +436,24 @@ initModulePart_Rcode(PyObject* mod) {
 }
 } // end namespace internal
 
+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) {
+    return (PyObject_TypeCheck(obj, &rcode_type));
+}
+
+const Rcode&
+PyRcode_ToRcode(const PyObject* rcode_obj) {
+    const s_Rcode* rcode = static_cast<const s_Rcode*>(rcode_obj);
+    return (*rcode->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 27 - 20
src/lib/dns/python/rcode_python.h

@@ -23,28 +23,35 @@ namespace isc {
 namespace dns {
 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;
 
+/// This is a simple shortcut to create a python Rcode 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* createRcodeObject(const Rcode& source);
+
+/// \brief Checks if the given python object is a Rcode object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Rcode, false otherwise
+bool PyRcode_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Rcode object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Rcode; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRcode_Check()
+///
+/// \note This is not a copy; if the Rcode is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rcode_obj The rcode object to convert
+const Rcode& PyRcode_ToRcode(const PyObject* rcode_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 40 - 7
src/lib/dns/python/rdata_python.cc

@@ -17,6 +17,7 @@
 #include <dns/rdata.h>
 #include <dns/messagerenderer.h>
 #include <util/buffer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "rdata_python.h"
 #include "rrtype_python.h"
@@ -26,9 +27,16 @@
 using namespace isc::dns;
 using namespace isc::dns::python;
 using namespace isc::util;
+using namespace isc::util::python;
 using namespace isc::dns::rdata;
 
 namespace {
+class s_Rdata : public PyObject {
+public:
+    isc::dns::rdata::ConstRdataPtr cppobj;
+};
+
+typedef CPPPyObjectContainer<s_Rdata, Rdata> RdataContainer;
 
 //
 // We declare the functions here, the definitions are below
@@ -68,8 +76,8 @@ PyMethodDef Rdata_methods[] = {
 
 int
 Rdata_init(s_Rdata* self, PyObject* args) {
-    s_RRType* rrtype;
-    s_RRClass* rrclass;
+    PyObject* rrtype;
+    PyObject* rrclass;
     const char* s;
     const char* data;
     Py_ssize_t len;
@@ -78,13 +86,15 @@ Rdata_init(s_Rdata* self, PyObject* args) {
     if (PyArg_ParseTuple(args, "O!O!s", &rrtype_type, &rrtype,
                                         &rrclass_type, &rrclass,
                                         &s)) {
-        self->cppobj = createRdata(*rrtype->cppobj, *rrclass->cppobj, s);
+        self->cppobj = createRdata(PyRRType_ToRRType(rrtype),
+                                   PyRRClass_ToRRClass(rrclass), s);
         return (0);
     } else if (PyArg_ParseTuple(args, "O!O!y#", &rrtype_type, &rrtype,
                                 &rrclass_type, &rrclass, &data, &len)) {
         InputBuffer input_buffer(data, len);
-        self->cppobj = createRdata(*rrtype->cppobj, *rrclass->cppobj,
-                                  input_buffer, len);
+        self->cppobj = createRdata(PyRRType_ToRRType(rrtype),
+                                   PyRRClass_ToRRClass(rrclass),
+                                   input_buffer, len);
         return (0);
     }
 
@@ -116,7 +126,7 @@ Rdata_str(PyObject* self) {
 PyObject*
 Rdata_toWire(s_Rdata* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -130,7 +140,7 @@ Rdata_toWire(s_Rdata* self, PyObject* args) {
         Py_DECREF(rd_bytes);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->cppobj);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -282,6 +292,29 @@ initModulePart_Rdata(PyObject* mod) {
 }
 } // end namespace internal
 
+PyObject*
+createRdataObject(ConstRdataPtr source) {
+    s_Rdata* py_rdata =
+        static_cast<s_Rdata*>(rdata_type.tp_alloc(&rdata_type, 0));
+    if (py_rdata == NULL) {
+        isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
+                  "probably due to short memory");
+    }
+    py_rdata->cppobj = source;
+    return (py_rdata);
+}
+
+bool
+PyRdata_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &rdata_type));
+}
+
+const Rdata&
+PyRdata_ToRdata(const PyObject* rdata_obj) {
+    const s_Rdata* rdata = static_cast<const s_Rdata*>(rdata_obj);
+    return (*rdata->cppobj);
+}
+
 } // end python namespace
 } // end dns namespace
 } // end isc namespace

+ 27 - 5
src/lib/dns/python/rdata_python.h

@@ -30,13 +30,35 @@ namespace python {
 //
 extern PyObject* po_EmptyRdata;
 
-class s_Rdata : public PyObject {
-public:
-    isc::dns::rdata::RdataPtr cppobj;
-};
-
 extern PyTypeObject rdata_type;
 
+/// This is a simple shortcut to create a python Rdata 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* createRdataObject(isc::dns::rdata::ConstRdataPtr source);
+
+/// \brief Checks if the given python object is a Rdata object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type Rdata, false otherwise
+bool PyRdata_Check(PyObject* obj);
+
+/// \brief Returns a reference to the Rdata object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type Rdata; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRdata_Check()
+///
+/// \note This is not a copy; if the Rdata is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rdata_obj The rdata object to convert
+const isc::dns::rdata::Rdata& PyRdata_ToRdata(const PyObject* rdata_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 11 - 5
src/lib/dns/python/rrclass_python.cc

@@ -28,6 +28,12 @@ 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_RRClass : public PyObject {
+public:
+    s_RRClass() : cppobj(NULL) {};
+    RRClass* cppobj;
+};
 
 //
 // We declare the functions here, the definitions are below
@@ -155,7 +161,7 @@ RRClass_str(PyObject* self) {
 PyObject*
 RRClass_toWire(s_RRClass* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -169,7 +175,7 @@ RRClass_toWire(s_RRClass* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->cppobj);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -369,9 +375,9 @@ PyRRClass_Check(PyObject* obj) {
     return (PyObject_TypeCheck(obj, &rrclass_type));
 }
 
-RRClass&
-PyRRClass_ToRRClassPtr(PyObject* rrclass_obj) {
-    s_RRClass* rrclass = static_cast<s_RRClass*>(rrclass_obj);
+const RRClass&
+PyRRClass_ToRRClass(const PyObject* rrclass_obj) {
+    const s_RRClass* rrclass = static_cast<const s_RRClass*>(rrclass_obj);
     return (*rrclass->cppobj);
 }
 

+ 1 - 12
src/lib/dns/python/rrclass_python.h

@@ -26,17 +26,6 @@ namespace python {
 extern PyObject* po_InvalidRRClass;
 extern PyObject* po_IncompleteRRClass;
 
-//
-// Declaration of the custom exceptions
-// Initialization and addition of these go in the module init at the
-// end
-//
-// The s_* Class simply covers one instantiation of the object
-class s_RRClass : public PyObject {
-public:
-    RRClass* cppobj;
-};
-
 extern PyTypeObject rrclass_type;
 
 /// This is a simple shortcut to create a python RRClass object (in the
@@ -64,7 +53,7 @@ bool PyRRClass_Check(PyObject* obj);
 /// may be destroyed, the caller must copy it itself.
 ///
 /// \param rrclass_obj The rrclass object to convert
-RRClass& PyRRClass_ToRRClass(PyObject* rrclass_obj);
+const RRClass& PyRRClass_ToRRClass(const PyObject* rrclass_obj);
 
 
 } // namespace python

+ 44 - 81
src/lib/dns/python/rrset_python.cc

@@ -36,6 +36,19 @@ using namespace isc::util::python;
 
 namespace {
 
+// The s_* Class simply coverst one instantiation of the object
+
+// Using a shared_ptr here should not really be necessary (PyObject
+// is already reference-counted), however internally on the cpp side,
+// not doing so might result in problems, since we can't copy construct
+// rdata field, adding them to rrsets results in a problem when the
+// rrset is destroyed later
+class s_RRset : public PyObject {
+public:
+    isc::dns::RRsetPtr cppobj;
+};
+
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_RRset, RRset> RRsetContainer;
 
@@ -93,18 +106,20 @@ PyMethodDef RRset_methods[] = {
 
 int
 RRset_init(s_RRset* self, PyObject* args) {
-    s_Name* name;
-    s_RRClass* rrclass;
-    s_RRType* rrtype;
-    s_RRTTL* rrttl;
+    PyObject* name;
+    PyObject* rrclass;
+    PyObject* rrtype;
+    PyObject* rrttl;
 
     if (PyArg_ParseTuple(args, "O!O!O!O!", &name_type, &name,
                                            &rrclass_type, &rrclass,
                                            &rrtype_type, &rrtype,
                                            &rrttl_type, &rrttl
        )) {
-        self->cppobj = RRsetPtr(new RRset(*name->cppobj, *rrclass->cppobj,
-                                *rrtype->cppobj, *rrttl->cppobj));
+        self->cppobj = RRsetPtr(new RRset(PyName_ToName(name),
+                                          PyRRClass_ToRRClass(rrclass),
+                                          PyRRType_ToRRType(rrtype),
+                                          PyRRTTL_ToRRTTL(rrttl)));
         return (0);
     }
 
@@ -127,90 +142,41 @@ RRset_getRdataCount(s_RRset* self) {
 
 PyObject*
 RRset_getName(s_RRset* self) {
-    s_Name* name;
-
-    // is this the best way to do this?
-    name = static_cast<s_Name*>(name_type.tp_alloc(&name_type, 0));
-    if (name != NULL) {
-        name->cppobj = new Name(self->cppobj->getName());
-        if (name->cppobj == NULL)
-          {
-            Py_DECREF(name);
-            return (NULL);
-          }
-    }
-
-    return (name);
+    return (createNameObject(self->cppobj->getName()));
 }
 
 PyObject*
 RRset_getClass(s_RRset* self) {
-    s_RRClass* rrclass;
-
-    rrclass = static_cast<s_RRClass*>(rrclass_type.tp_alloc(&rrclass_type, 0));
-    if (rrclass != NULL) {
-        rrclass->cppobj = new RRClass(self->cppobj->getClass());
-        if (rrclass->cppobj == NULL)
-          {
-            Py_DECREF(rrclass);
-            return (NULL);
-          }
-    }
-
-    return (rrclass);
+    return (createRRClassObject(self->cppobj->getClass()));
 }
 
 PyObject*
 RRset_getType(s_RRset* self) {
-    s_RRType* rrtype;
-
-    rrtype = static_cast<s_RRType*>(rrtype_type.tp_alloc(&rrtype_type, 0));
-    if (rrtype != NULL) {
-        rrtype->cppobj = new RRType(self->cppobj->getType());
-        if (rrtype->cppobj == NULL)
-          {
-            Py_DECREF(rrtype);
-            return (NULL);
-          }
-    }
-
-    return (rrtype);
+    return (createRRTypeObject(self->cppobj->getType()));
 }
 
 PyObject*
 RRset_getTTL(s_RRset* self) {
-    s_RRTTL* rrttl;
-
-    rrttl = static_cast<s_RRTTL*>(rrttl_type.tp_alloc(&rrttl_type, 0));
-    if (rrttl != NULL) {
-        rrttl->cppobj = new RRTTL(self->cppobj->getTTL());
-        if (rrttl->cppobj == NULL)
-          {
-            Py_DECREF(rrttl);
-            return (NULL);
-          }
-    }
-
-    return (rrttl);
+    return (createRRTTLObject(self->cppobj->getTTL()));
 }
 
 PyObject*
 RRset_setName(s_RRset* self, PyObject* args) {
-    s_Name* name;
+    PyObject* name;
     if (!PyArg_ParseTuple(args, "O!", &name_type, &name)) {
         return (NULL);
     }
-    self->cppobj->setName(*name->cppobj);
+    self->cppobj->setName(PyName_ToName(name));
     Py_RETURN_NONE;
 }
 
 PyObject*
 RRset_setTTL(s_RRset* self, PyObject* args) {
-    s_RRTTL* rrttl;
+    PyObject* rrttl;
     if (!PyArg_ParseTuple(args, "O!", &rrttl_type, &rrttl)) {
         return (NULL);
     }
-    self->cppobj->setTTL(*rrttl->cppobj);
+    self->cppobj->setTTL(PyRRTTL_ToRRTTL(rrttl));
     Py_RETURN_NONE;
 }
 
@@ -235,7 +201,7 @@ RRset_str(PyObject* self) {
 PyObject*
 RRset_toWire(s_RRset* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     try {
         if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
@@ -250,7 +216,7 @@ RRset_toWire(s_RRset* self, PyObject* args) {
             Py_DECREF(n);
             return (result);
         } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-            self->cppobj->toWire(*mr->cppobj);
+            self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
             // If we return NULL it is seen as an error, so use this for
             // None returns
             Py_RETURN_NONE;
@@ -268,12 +234,12 @@ RRset_toWire(s_RRset* self, PyObject* args) {
 
 PyObject*
 RRset_addRdata(s_RRset* self, PyObject* args) {
-    s_Rdata* rdata;
+    PyObject* rdata;
     if (!PyArg_ParseTuple(args, "O!", &rdata_type, &rdata)) {
         return (NULL);
     }
     try {
-        self->cppobj->addRdata(*rdata->cppobj);
+        self->cppobj->addRdata(PyRdata_ToRdata(rdata));
         Py_RETURN_NONE;
     } catch (const std::bad_cast&) {
         PyErr_Clear();
@@ -290,18 +256,10 @@ RRset_getRdata(s_RRset* self) {
     RdataIteratorPtr it = self->cppobj->getRdataIterator();
 
     for (; !it->isLast(); it->next()) {
-        s_Rdata *rds = static_cast<s_Rdata*>(rdata_type.tp_alloc(&rdata_type, 0));
-        if (rds != NULL) {
-            // hmz them iterators/shared_ptrs and private constructors
-            // make this a bit weird, so we create a new one with
-            // the data available
-            const rdata::Rdata *rd = &it->getCurrent();
-            rds->cppobj = createRdata(self->cppobj->getType(),
-                                      self->cppobj->getClass(), *rd);
-            PyList_Append(list, rds);
-        } else {
-            return (NULL);
-        }
+        const rdata::Rdata *rd = &it->getCurrent();
+        PyList_Append(list,
+                      createRdataObject(createRdata(self->cppobj->getType(),
+                                        self->cppobj->getClass(), *rd)));
     }
 
     return (list);
@@ -423,8 +381,8 @@ initModulePart_RRset(PyObject* mod) {
 
 PyObject*
 createRRsetObject(const RRset& source) {
-    isc::dns::python::s_RRset* py_rrset = static_cast<isc::dns::python::s_RRset*>(
-        isc::dns::python::rrset_type.tp_alloc(&isc::dns::python::rrset_type, 0));
+    s_RRset* py_rrset =
+        static_cast<s_RRset*>(rrset_type.tp_alloc(&rrset_type, 0));
     if (py_rrset == NULL) {
         isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
                   "probably due to short memory");
@@ -464,6 +422,11 @@ PyRRset_ToRRset(PyObject* rrset_obj) {
     return (*rrset->cppobj);
 }
 
+RRsetPtr
+PyRRset_ToRRsetPtr(PyObject* rrset_obj) {
+    s_RRset* rrset = static_cast<s_RRset*>(rrset_obj);
+    return (rrset->cppobj);
+}
 
 
 } // end python namespace

+ 9 - 12
src/lib/dns/python/rrset_python.h

@@ -32,18 +32,6 @@ namespace python {
 //
 extern PyObject* po_EmptyRRset;
 
-// The s_* Class simply coverst one instantiation of the object
-
-// Using a shared_ptr here should not really be necessary (PyObject
-// is already reference-counted), however internally on the cpp side,
-// not doing so might result in problems, since we can't copy construct
-// rdata field, adding them to rrsets results in a problem when the
-// rrset is destroyed later
-class s_RRset : public PyObject {
-public:
-    isc::dns::RRsetPtr cppobj;
-};
-
 extern PyTypeObject rrset_type;
 
 /// This is a simple shortcut to create a python RRset object (in the
@@ -73,6 +61,15 @@ bool PyRRset_Check(PyObject* obj);
 /// \param rrset_obj The rrset object to convert
 RRset& PyRRset_ToRRset(PyObject* rrset_obj);
 
+/// \brief Returns the shared_ptr of the RRset object contained within the
+///        given Python object.
+///
+/// \note The given object MUST be of type RRset; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRRset_Check()
+///
+/// \param rrset_obj The rrset object to convert
+RRsetPtr PyRRset_ToRRsetPtr(PyObject* rrset_obj);
+
 
 } // namespace python
 } // namespace dns

+ 29 - 4
src/lib/dns/python/rrttl_python.cc

@@ -18,6 +18,7 @@
 #include <dns/rrttl.h>
 #include <dns/messagerenderer.h>
 #include <util/buffer.h>
+#include <util/python/pycppwrapper_util.h>
 
 #include "rrttl_python.h"
 #include "pydnspp_common.h"
@@ -27,11 +28,17 @@ 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_RRTTL : public PyObject {
+public:
+    s_RRTTL() : cppobj(NULL) {};
+    isc::dns::RRTTL* cppobj;
+};
 
-int RRTTL_init(s_RRTTL* self, PyObject* args);
-void RRTTL_destroy(s_RRTTL* self);
+typedef CPPPyObjectContainer<s_RRTTL, RRTTL> RRTTLContainer;
 
 PyObject* RRTTL_toText(s_RRTTL* self);
 // This is a second version of toText, we need one where the argument
@@ -143,7 +150,7 @@ RRTTL_str(PyObject* self) {
 PyObject*
 RRTTL_toWire(s_RRTTL* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -158,7 +165,7 @@ RRTTL_toWire(s_RRTTL* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->cppobj);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -308,6 +315,24 @@ initModulePart_RRTTL(PyObject* mod) {
 }
 } // end namespace internal
 
+PyObject*
+createRRTTLObject(const RRTTL& source) {
+    RRTTLContainer container = PyObject_New(s_RRTTL, &rrttl_type);
+    container.set(new RRTTL(source));
+    return (container.release());
+}
+
+bool
+PyRRTTL_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &rrttl_type));
+}
+
+const RRTTL&
+PyRRTTL_ToRRTTL(const PyObject* rrttl_obj) {
+    const s_RRTTL* rrttl = static_cast<const s_RRTTL*>(rrttl_obj);
+    return (*rrttl->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 26 - 6
src/lib/dns/python/rrttl_python.h

@@ -31,14 +31,34 @@ namespace python {
 extern PyObject* po_InvalidRRTTL;
 extern PyObject* po_IncompleteRRTTL;
 
-// The s_* Class simply covers one instantiation of the object
-class s_RRTTL : public PyObject {
-public:
-    isc::dns::RRTTL* cppobj;
-};
+extern PyTypeObject rrttl_type;
 
+/// This is a simple shortcut to create a python RRTTL 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* createRRTTLObject(const RRTTL& source);
 
-extern PyTypeObject rrttl_type;
+/// \brief Checks if the given python object is a RRTTL object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type RRTTL, false otherwise
+bool PyRRTTL_Check(PyObject* obj);
+
+/// \brief Returns a reference to the RRTTL object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type RRTTL; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyRRTTL_Check()
+///
+/// \note This is not a copy; if the RRTTL is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rrttl_obj The rrttl object to convert
+const RRTTL& PyRRTTL_ToRRTTL(const PyObject* rrttl_obj);
 
 } // namespace python
 } // namespace dns

+ 9 - 5
src/lib/dns/python/rrtype_python.cc

@@ -30,6 +30,11 @@ using namespace isc::util;
 using namespace isc::util::python;
 
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_RRType : public PyObject {
+public:
+    const RRType* cppobj;
+};
 
 // General creation and destruction
 int RRType_init(s_RRType* self, PyObject* args);
@@ -185,7 +190,7 @@ RRType_str(PyObject* self) {
 PyObject*
 RRType_toWire(s_RRType* self, PyObject* args) {
     PyObject* bytes;
-    s_MessageRenderer* mr;
+    PyObject* mr;
 
     if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
         PyObject* bytes_o = bytes;
@@ -199,7 +204,7 @@ RRType_toWire(s_RRType* self, PyObject* args) {
         Py_DECREF(n);
         return (result);
     } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-        self->cppobj->toWire(*mr->cppobj);
+        self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
         // If we return NULL it is seen as an error, so use this for
         // None returns
         Py_RETURN_NONE;
@@ -458,15 +463,14 @@ createRRTypeObject(const RRType& source) {
     return (container.release());
 }
 
-
 bool
 PyRRType_Check(PyObject* obj) {
     return (PyObject_TypeCheck(obj, &rrtype_type));
 }
 
 const RRType&
-PyRRType_ToRRType(PyObject* rrtype_obj) {
-    s_RRType* rrtype = static_cast<s_RRType*>(rrtype_obj);
+PyRRType_ToRRType(const PyObject* rrtype_obj) {
+    const s_RRType* rrtype = static_cast<const s_RRType*>(rrtype_obj);
     return (*rrtype->cppobj);
 }
 

+ 1 - 8
src/lib/dns/python/rrtype_python.h

@@ -31,13 +31,6 @@ namespace python {
 extern PyObject* po_InvalidRRType;
 extern PyObject* po_IncompleteRRType;
 
-// The s_* Class simply covers one instantiation of the object
-class s_RRType : public PyObject {
-public:
-    const RRType* cppobj;
-};
-
-
 extern PyTypeObject rrtype_type;
 
 /// This is a simple shortcut to create a python RRType object (in the
@@ -65,7 +58,7 @@ bool PyRRType_Check(PyObject* obj);
 /// may be destroyed, the caller must copy it itself.
 ///
 /// \param rrtype_obj The rrtype object to convert
-const RRType& PyRRType_ToRRType(PyObject* rrtype_obj);
+const RRType& PyRRType_ToRRType(const PyObject* rrtype_obj);
 
 
 } // namespace python

+ 29 - 16
src/lib/dns/python/tsig_python.cc

@@ -48,12 +48,14 @@ using namespace isc::dns::python;
 //
 // TSIGContext
 //
-
-// Trivial constructor.
-s_TSIGContext::s_TSIGContext() : cppobj(NULL) {
-}
-
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGContext : public PyObject {
+public:
+    s_TSIGContext() : cppobj(NULL) {};
+    TSIGContext* cppobj;
+};
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIGContext, TSIGContext> TSIGContextContainer;
 
@@ -101,23 +103,23 @@ int
 TSIGContext_init(s_TSIGContext* self, PyObject* args) {
     try {
         // "From key" constructor
-        const s_TSIGKey* tsigkey_obj;
+        const PyObject* tsigkey_obj;
         if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey_obj)) {
-            self->cppobj = new TSIGContext(*tsigkey_obj->cppobj);
+            self->cppobj = new TSIGContext(PyTSIGKey_ToTSIGKey(tsigkey_obj));
             return (0);
         }
 
         // "From key param + keyring" constructor
         PyErr_Clear();
-        const s_Name* keyname_obj;
-        const s_Name* algname_obj;
-        const s_TSIGKeyRing* keyring_obj;
+        const PyObject* keyname_obj;
+        const PyObject* algname_obj;
+        const PyObject* keyring_obj;
         if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &keyname_obj,
                              &name_type, &algname_obj, &tsigkeyring_type,
                              &keyring_obj)) {
-            self->cppobj = new TSIGContext(*keyname_obj->cppobj,
-                                           *algname_obj->cppobj,
-                                           *keyring_obj->cppobj);
+            self->cppobj = new TSIGContext(PyName_ToName(keyname_obj),
+                                           PyName_ToName(algname_obj),
+                                           PyTSIGKeyRing_ToTSIGKeyRing(keyring_obj));
             return (0);
         }
     } catch (const exception& ex) {
@@ -205,13 +207,13 @@ PyObject*
 TSIGContext_verify(s_TSIGContext* self, PyObject* args) {
     const char* data;
     Py_ssize_t data_len;
-    s_TSIGRecord* py_record;
+    PyObject* py_record;
     PyObject* py_maybe_none;
-    TSIGRecord* record;
+    const TSIGRecord* record;
 
     if (PyArg_ParseTuple(args, "O!y#", &tsigrecord_type, &py_record,
                          &data, &data_len)) {
-        record = py_record->cppobj;
+        record = &PyTSIGRecord_ToTSIGRecord(py_record);
     } else if (PyArg_ParseTuple(args, "Oy#", &py_maybe_none, &data,
                                 &data_len)) {
         record = NULL;
@@ -362,6 +364,17 @@ initModulePart_TSIGContext(PyObject* mod) {
 }
 } // end namespace internal
 
+bool
+PyTSIGContext_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigcontext_type));
+}
+
+TSIGContext&
+PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj) {
+    s_TSIGContext* tsigcontext = static_cast<s_TSIGContext*>(tsigcontext_obj);
+    return (*tsigcontext->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 19 - 7
src/lib/dns/python/tsig_python.h

@@ -23,18 +23,30 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIGContext : public PyObject {
-public:
-    s_TSIGContext();
-    TSIGContext* cppobj;
-};
-
 extern PyTypeObject tsigcontext_type;
 
 // Class specific exceptions
 extern PyObject* po_TSIGContextError;
 
+/// \brief Checks if the given python object is a TSIGContext object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGContext, false otherwise
+bool PyTSIGContext_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGContext object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGContext; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGContext_Check()
+///
+/// \note This is not a copy; if the TSIGContext is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsigcontext_obj The tsigcontext object to convert
+TSIGContext& PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj);
+
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 20 - 4
src/lib/dns/python/tsig_rdata_python.cc

@@ -45,11 +45,15 @@ using namespace isc::dns::python;
 // TSIG RDATA
 //
 
-// Trivial constructor.
-s_TSIG::s_TSIG() : cppobj(NULL) {
-}
-
 namespace {
+    // The s_* Class simply covers one instantiation of the object
+class s_TSIG : public PyObject {
+public:
+    s_TSIG() : cppobj(NULL) {};
+    const rdata::any::TSIG* cppobj;
+};
+
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIG, any::TSIG> TSIGContainer;
 
@@ -367,6 +371,18 @@ createTSIGObject(const any::TSIG& source) {
     container.set(new any::TSIG(source));
     return (container.release());
 }
+
+bool
+PyTSIG_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsig_type));
+}
+
+const any::TSIG&
+PyTSIG_ToTSIG(const PyObject* tsig_obj) {
+    const s_TSIG* tsig = static_cast<const s_TSIG*>(tsig_obj);
+    return (*tsig->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 18 - 7
src/lib/dns/python/tsig_rdata_python.h

@@ -27,13 +27,6 @@ class TSIG;
 
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIG : public PyObject {
-public:
-    s_TSIG();
-    const rdata::any::TSIG* cppobj;
-};
-
 extern PyTypeObject tsig_type;
 
 /// This is A simple shortcut to create a python TSIG object (in the
@@ -45,6 +38,24 @@ extern PyTypeObject tsig_type;
 /// followed by necessary setup for python exception.
 PyObject* createTSIGObject(const rdata::any::TSIG& source);
 
+/// \brief Checks if the given python object is a TSIG object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIG, false otherwise
+bool PyTSIG_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIG object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIG; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIG_Check()
+///
+/// \note This is not a copy; if the TSIG is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsig_obj The tsig object to convert
+const rdata::any::TSIG& PyTSIG_ToTSIG(const PyObject* tsig_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 10 - 12
src/lib/dns/python/tsigerror_python.cc

@@ -42,14 +42,17 @@ using namespace isc::dns::python;
 // TSIGError
 //
 
-// Trivial constructor.
-s_TSIGError::s_TSIGError() : cppobj(NULL) {
-}
-
 // Import pydoc text
 #include "tsigerror_python_inc.cc"
 
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGError : public PyObject {
+public:
+    s_TSIGError() : cppobj(NULL) {};
+    const TSIGError* cppobj;
+};
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIGError, TSIGError> TSIGErrorContainer;
 
@@ -107,9 +110,9 @@ TSIGError_init(s_TSIGError* self, PyObject* args) {
 
         // Constructor from Rcode
         PyErr_Clear();
-        s_Rcode* py_rcode;
+        PyObject* py_rcode;
         if (PyArg_ParseTuple(args, "O!", &rcode_type, &py_rcode)) {
-            self->cppobj = new TSIGError(*py_rcode->cppobj);
+            self->cppobj = new TSIGError(PyRcode_ToRcode(py_rcode));
             return (0);
         }
     } catch (const isc::OutOfRange& ex) {
@@ -172,13 +175,8 @@ TSIGError_str(PyObject* self) {
 
 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());
+        return (createRcodeObject(self->cppobj->toRcode()));
     } catch (const exception& ex) {
         const string ex_what =
             "Failed to convert TSIGError to Rcode: " + string(ex.what());

+ 1 - 7
src/lib/dns/python/tsigerror_python.h

@@ -23,13 +23,6 @@ namespace isc {
 namespace dns {
 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;
 
 /// This is A simple shortcut to create a python TSIGError object (in the
@@ -40,6 +33,7 @@ extern PyTypeObject tsigerror_type;
 /// This function is expected to be called with in a try block
 /// followed by necessary setup for python exception.
 PyObject* createTSIGErrorObject(const TSIGError& source);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 45 - 14
src/lib/dns/python/tsigkey_python.cc

@@ -43,11 +43,14 @@ using namespace isc::dns::python;
 // TSIGKey
 //
 
+namespace {
 // The s_* Class simply covers one instantiation of the object
+class s_TSIGKey : public PyObject {
+public:
+    s_TSIGKey() : cppobj(NULL) {};
+    TSIGKey* cppobj;
+};
 
-s_TSIGKey::s_TSIGKey() : cppobj(NULL) {}
-
-namespace {
 //
 // We declare the functions here, the definitions are below
 // the type definition of the object, since both can use the other
@@ -96,8 +99,8 @@ TSIGKey_init(s_TSIGKey* self, PyObject* args) {
         }
 
         PyErr_Clear();
-        const s_Name* key_name;
-        const s_Name* algorithm_name;
+        const PyObject* key_name;
+        const PyObject* algorithm_name;
         PyObject* bytes_obj;
         const char* secret;
         Py_ssize_t secret_len;
@@ -107,8 +110,8 @@ TSIGKey_init(s_TSIGKey* self, PyObject* args) {
             if (secret_len == 0) {
                 secret = NULL;
             }
-            self->cppobj = new TSIGKey(*key_name->cppobj,
-                                       *algorithm_name->cppobj,
+            self->cppobj = new TSIGKey(PyName_ToName(key_name),
+                                       PyName_ToName(algorithm_name),
                                        secret, secret_len);
             return (0);
         }
@@ -279,6 +282,17 @@ initModulePart_TSIGKey(PyObject* mod) {
 }
 } // end namespace internal
 
+bool
+PyTSIGKey_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigkey_type));
+}
+
+const TSIGKey&
+PyTSIGKey_ToTSIGKey(const PyObject* tsigkey_obj) {
+    const s_TSIGKey* tsigkey = static_cast<const s_TSIGKey*>(tsigkey_obj);
+    return (*tsigkey->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc
@@ -294,9 +308,13 @@ initModulePart_TSIGKey(PyObject* mod) {
 
 // The s_* Class simply covers one instantiation of the object
 
-s_TSIGKeyRing::s_TSIGKeyRing() : cppobj(NULL) {}
-
 namespace {
+class s_TSIGKeyRing : public PyObject {
+public:
+    s_TSIGKeyRing() : cppobj(NULL) {};
+    TSIGKeyRing* cppobj;
+};
+
 //
 // We declare the functions here, the definitions are below
 // the type definition of the object, since both can use the other
@@ -377,11 +395,11 @@ TSIGKeyRing_add(const s_TSIGKeyRing* const self, PyObject* args) {
 
 PyObject*
 TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
-    s_Name* key_name;
+    PyObject* key_name;
 
     if (PyArg_ParseTuple(args, "O!", &name_type, &key_name)) {
         const TSIGKeyRing::Result result =
-            self->cppobj->remove(*key_name->cppobj);
+            self->cppobj->remove(PyName_ToName(key_name));
         return (Py_BuildValue("I", result));
     }
 
@@ -393,13 +411,14 @@ TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
 
 PyObject*
 TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args) {
-    s_Name* key_name;
-    s_Name* algorithm_name;
+    PyObject* key_name;
+    PyObject* algorithm_name;
 
     if (PyArg_ParseTuple(args, "O!O!", &name_type, &key_name,
                          &name_type, &algorithm_name)) {
         const TSIGKeyRing::FindResult result =
-            self->cppobj->find(*key_name->cppobj, *algorithm_name->cppobj);
+            self->cppobj->find(PyName_ToName(key_name),
+                               PyName_ToName(algorithm_name));
         if (result.key != NULL) {
             s_TSIGKey* key = PyObject_New(s_TSIGKey, &tsigkey_type);
             if (key == NULL) {
@@ -500,6 +519,18 @@ initModulePart_TSIGKeyRing(PyObject* mod) {
 }
 } // end namespace internal
 
+bool
+PyTSIGKeyRing_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigkeyring_type));
+}
+
+const TSIGKeyRing&
+PyTSIGKeyRing_ToTSIGKeyRing(const PyObject* tsigkeyring_obj) {
+    const s_TSIGKeyRing* tsigkeyring =
+        static_cast<const s_TSIGKeyRing*>(tsigkeyring_obj);
+    return (*tsigkeyring->cppobj);
+}
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 36 - 13
src/lib/dns/python/tsigkey_python.h

@@ -23,22 +23,45 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIGKey : public PyObject {
-public:
-    s_TSIGKey();
-    TSIGKey* cppobj;
-};
-
-class s_TSIGKeyRing : public PyObject {
-public:
-    s_TSIGKeyRing();
-    TSIGKeyRing* cppobj;
-};
-
 extern PyTypeObject tsigkey_type;
 extern PyTypeObject tsigkeyring_type;
 
+/// \brief Checks if the given python object is a TSIGKey object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGKey, false otherwise
+bool PyTSIGKey_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGKey object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGKey; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGKey_Check()
+///
+/// \note This is not a copy; if the TSIGKey is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsigkey_obj The tsigkey object to convert
+const TSIGKey& PyTSIGKey_ToTSIGKey(const PyObject* tsigkey_obj);
+
+/// \brief Checks if the given python object is a TSIGKeyRing object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGKeyRing, false otherwise
+bool PyTSIGKeyRing_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGKeyRing object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGKeyRing; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGKeyRing_Check()
+///
+/// \note This is not a copy; if the TSIGKeyRing is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param tsigkeyring_obj The tsigkeyring object to convert
+const TSIGKeyRing& PyTSIGKeyRing_ToTSIGKeyRing(const PyObject* tsigkeyring_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 24 - 5
src/lib/dns/python/tsigrecord_python.cc

@@ -45,10 +45,15 @@ using namespace isc::dns::python;
 //
 
 // Trivial constructor.
-s_TSIGRecord::s_TSIGRecord() : cppobj(NULL) {
-}
 
 namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_TSIGRecord : public PyObject {
+public:
+    s_TSIGRecord() : cppobj(NULL) {};
+    TSIGRecord* cppobj;
+};
+
 // Shortcut type which would be convenient for adding class variables safely.
 typedef CPPPyObjectContainer<s_TSIGRecord, TSIGRecord> TSIGRecordContainer;
 
@@ -102,11 +107,12 @@ PyMethodDef TSIGRecord_methods[] = {
 int
 TSIGRecord_init(s_TSIGRecord* self, PyObject* args) {
     try {
-        const s_Name* py_name;
-        const s_TSIG* py_tsig;
+        const PyObject* py_name;
+        const PyObject* py_tsig;
         if (PyArg_ParseTuple(args, "O!O!", &name_type, &py_name,
                              &tsig_type, &py_tsig)) {
-            self->cppobj = new TSIGRecord(*py_name->cppobj, *py_tsig->cppobj);
+            self->cppobj = new TSIGRecord(PyName_ToName(py_name),
+                                          PyTSIG_ToTSIG(py_tsig));
             return (0);
         }
     } catch (const exception& ex) {
@@ -308,6 +314,19 @@ createTSIGRecordObject(const TSIGRecord& source) {
     container.set(new TSIGRecord(source));
     return (container.release());
 }
+
+bool
+PyTSIGRecord_Check(PyObject* obj) {
+    return (PyObject_TypeCheck(obj, &tsigrecord_type));
+}
+
+const TSIGRecord&
+PyTSIGRecord_ToTSIGRecord(PyObject* tsigrecord_obj) {
+    s_TSIGRecord* tsigrecord = static_cast<s_TSIGRecord*>(tsigrecord_obj);
+    return (*tsigrecord->cppobj);
+}
+
+
 } // namespace python
 } // namespace dns
 } // namespace isc

+ 18 - 7
src/lib/dns/python/tsigrecord_python.h

@@ -23,13 +23,6 @@ namespace isc {
 namespace dns {
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
-class s_TSIGRecord : public PyObject {
-public:
-    s_TSIGRecord();
-    TSIGRecord* cppobj;
-};
-
 extern PyTypeObject tsigrecord_type;
 
 /// This is A simple shortcut to create a python TSIGRecord object (in the
@@ -41,6 +34,24 @@ extern PyTypeObject tsigrecord_type;
 /// followed by necessary setup for python exception.
 PyObject* createTSIGRecordObject(const TSIGRecord& source);
 
+/// \brief Checks if the given python object is a TSIGRecord object
+///
+/// \param obj The object to check the type of
+/// \return true if the object is of type TSIGRecord, false otherwise
+bool PyTSIGRecord_Check(PyObject* obj);
+
+/// \brief Returns a reference to the TSIGRecord object contained within the given
+///        Python object.
+///
+/// \note The given object MUST be of type TSIGRecord; this can be checked with
+///       either the right call to ParseTuple("O!"), or with PyTSIGRecord_Check()
+///
+/// \note This is not a copy; if the TSIGRecord is needed when the PyObject
+/// may be destroyed, the caller must copy it itself.
+///
+/// \param rrtype_obj The rrtype object to convert
+const TSIGRecord& PyTSIGRecord_ToTSIGRecord(PyObject* tsigrecord_obj);
+
 } // namespace python
 } // namespace dns
 } // namespace isc