Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef __LIBDNS_PYTHON_TOWIRE_H
16 : : #define __LIBDNS_PYTHON_TOWIRE_H 1
17 : :
18 : : #include <Python.h>
19 : :
20 : : #include <stdexcept>
21 : : #include <string>
22 : :
23 : : #include <dns/messagerenderer.h>
24 : :
25 : : #include <util/buffer.h>
26 : : #include <util/python/pycppwrapper_util.h>
27 : :
28 : : #include "messagerenderer_python.h"
29 : :
30 : : namespace isc {
31 : : namespace dns {
32 : : namespace python {
33 : :
34 : : // The following two templated structures are a helper to use the same
35 : : // toWire() template implementation for two types of toWire() methods:
36 : : // return an integer or have no return value.
37 : : template <typename CPPCLASS>
38 : : struct ToWireCallVoid {
39 : : ToWireCallVoid(CPPCLASS& cppobj) : cppobj_(cppobj) {}
40 : : int operator()(AbstractMessageRenderer& renderer) const {
41 [ # # ][ # # ]: 0 : cppobj_.toWire(renderer);
42 : : return (0);
43 : : }
44 : : const CPPCLASS& cppobj_;
45 : : };
46 : :
47 : : template <typename CPPCLASS>
48 : : struct ToWireCallInt {
49 : : ToWireCallInt(CPPCLASS& cppobj) : cppobj_(cppobj) {}
50 : : int operator()(AbstractMessageRenderer& renderer) const {
51 [ # # ]: 0 : return (cppobj_.toWire(renderer));
52 : : }
53 : : const CPPCLASS& cppobj_;
54 : : };
55 : :
56 : : // This templated function gives a common implementation of the toWire()
57 : : // wrapper for various libdns++ classes. PYSTRUCT and CPPCLASS are
58 : : // (C++ binding of) python and (pure) C++ classes (e.g., s_Name and Name),
59 : : // and TOWIRECALLER is either ToWireCallVoid<CPPCLASS> or
60 : : // ToWireCallInt<CPPCLASS>, depending on the toWire() method of the class
61 : : // returns a value or not.
62 : : //
63 : : // See, e.g., tsigrecord_python.cc for how to use it.
64 : : //
65 : : // This should be able to be used without modification for most classes that
66 : : // have toWire(). But if the underlying toWire() has an extra argument, the
67 : : // definition will need to be adjusted accordingly.
68 : : template <typename PYSTRUCT, typename CPPCLASS, typename TOWIRECALLER>
69 : : PyObject*
70 : 19 : toWireWrapper(const PYSTRUCT* const self, PyObject* args) {
71 : : try {
72 : : // To OutputBuffer version
73 : : PyObject* bytes; // this won't have own reference, no risk of leak.
74 [ + - ][ + - ]: 19 : if (PyArg_ParseTuple(args, "O", &bytes) && PySequence_Check(bytes)) {
[ + - ][ - + ]
[ + - ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
75 : : // render the object into a buffer (this can throw)
76 : 19 : isc::util::OutputBuffer buffer(0);
77 [ + - ][ # # ]: 19 : self->cppobj->toWire(buffer);
78 : :
79 : : // convert the rendered data into PyObject. This could leak later,
80 : : // so we need to store it in a container.
81 : : PyObject* rd_bytes = PyBytes_FromStringAndSize(
82 : : static_cast<const char*>(buffer.getData()),
83 [ + - ][ # # ]: 19 : buffer.getLength());
84 [ + - ][ + - ]: 38 : isc::util::python::PyObjectContainer rd_bytes_container(rd_bytes);
[ # # ][ # # ]
85 : :
86 : : // concat the latest data to the given existing sequence. concat
87 : : // operation could fail, so we use a container to clean it up
88 : : // safely should that happen.
89 [ + - ][ # # ]: 19 : PyObject* result = PySequence_InPlaceConcat(bytes, rd_bytes);
90 [ + - ][ + - ]: 19 : isc::util::python::PyObjectContainer result_container(result);
[ # # ][ # # ]
91 : :
92 : : return (result_container.release());
93 : : }
94 : :
95 : : // To MessageRenderer version
96 : : PyObject* renderer;
97 [ # # ][ # # ]: 0 : if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &renderer)) {
[ # # ][ # # ]
98 : : const unsigned int n = TOWIRECALLER(*self->cppobj)(
99 [ # # ][ # # ]: 0 : PyMessageRenderer_ToMessageRenderer(renderer));
100 : :
101 [ # # ][ # # ]: 0 : return (Py_BuildValue("I", n));
102 : : }
103 : 0 : } catch (const std::exception& ex) {
104 : : const std::string ex_what =
105 : : "Failed to render an libdns++ object wire-format: "
106 [ # # ][ # # ]: 0 : + std::string(ex.what());
[ # # ][ # # ]
107 [ # # # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
108 : : return (NULL);
109 [ # # ][ # # ]: 0 : } catch (...) {
110 [ # # # # ]: 0 : PyErr_SetString(po_IscException, "Unexpectedly failed to render an "
111 : : "libdns++ object wire-format.");
112 : : return (NULL);
113 : : }
114 : :
115 : 0 : PyErr_Clear();
116 : 0 : PyErr_SetString(PyExc_TypeError,
117 : : "Incorrect arguments for a to_wire() method");
118 : 19 : return (NULL);
119 : : }
120 : : } // namespace python
121 : : } // namespace dns
122 : : } // namespace isc
123 : : #endif // __LIBDNS_PYTHON_TOWIRE_H
124 : :
125 : : // Local Variables:
126 : : // mode: c++
127 : : // End:
|