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 : : #define PY_SSIZE_T_CLEAN
16 : : #include <Python.h>
17 : :
18 : : #include <string>
19 : : #include <stdexcept>
20 : :
21 : : #include <util/python/pycppwrapper_util.h>
22 : :
23 : : #include <dns/rdataclass.h>
24 : :
25 : : #include "pydnspp_common.h"
26 : : #include "pydnspp_towire.h"
27 : : #include "name_python.h"
28 : : #include "tsig_rdata_python.h"
29 : :
30 : : using namespace std;
31 : : using namespace isc::util::python;
32 : : using namespace isc::dns;
33 : : using namespace isc::dns::rdata;
34 : : using namespace isc::dns::python;
35 : :
36 : : // For each class, we need a struct, a helper functions (init, destroy,
37 : : // and static wrappers around the methods we export), a list of methods,
38 : : // and a type description
39 : :
40 : : namespace {
41 : : // The s_* Class simply covers one instantiation of the object
42 : : class s_TSIG : public PyObject {
43 : : public:
44 : : s_TSIG() : cppobj(NULL) {};
45 : : const rdata::any::TSIG* cppobj;
46 : : };
47 : :
48 : :
49 : : // Shortcut type which would be convenient for adding class variables safely.
50 : : typedef CPPPyObjectContainer<s_TSIG, any::TSIG> TSIGContainer;
51 : :
52 : : //
53 : : // We declare the functions here, the definitions are below
54 : : // the type definition of the object, since both can use the other
55 : : //
56 : :
57 : : // General creation and destruction
58 : : int TSIG_init(s_TSIG* self, PyObject* args);
59 : : void TSIG_destroy(s_TSIG* self);
60 : :
61 : : // These are the functions we export
62 : : // ADD/REMOVE/MODIFY THE FOLLOWING AS APPROPRIATE FOR THE ACTUAL CLASS.
63 : : //
64 : : PyObject* TSIG_toText(const s_TSIG* const self);
65 : : PyObject* TSIG_getAlgorithm(const s_TSIG* const self);
66 : : PyObject* TSIG_getTimeSigned(const s_TSIG* const self);
67 : : PyObject* TSIG_getFudge(const s_TSIG* const self);
68 : : PyObject* TSIG_getOriginalID(const s_TSIG* const self);
69 : : PyObject* TSIG_getError(const s_TSIG* const self);
70 : : PyObject* TSIG_getMAC(const s_TSIG* const self);
71 : : PyObject* TSIG_getOtherData(const s_TSIG* const self);
72 : : PyObject* TSIG_str(PyObject* self);
73 : : PyObject* TSIG_richcmp(const s_TSIG* const self,
74 : : const s_TSIG* const other, int op);
75 : : PyObject* TSIG_toWire(const s_TSIG* self, PyObject* args);
76 : :
77 : : // These are the functions we export
78 : : // For a minimal support, we don't need them.
79 : :
80 : : // This list contains the actual set of functions we have in
81 : : // python. Each entry has
82 : : // 1. Python method name
83 : : // 2. Our static function here
84 : : // 3. Argument type
85 : : // 4. Documentation
86 : : PyMethodDef TSIG_methods[] = {
87 : : { "get_algorithm", reinterpret_cast<PyCFunction>(TSIG_getAlgorithm),
88 : : METH_NOARGS,
89 : : "Return the algorithm name." },
90 : : { "get_timesigned", reinterpret_cast<PyCFunction>(TSIG_getTimeSigned),
91 : : METH_NOARGS,
92 : : "Return the value of the Time Signed field. "
93 : : "The returned value does not exceed 2^48-1."
94 : : },
95 : : { "get_fudge", reinterpret_cast<PyCFunction>(TSIG_getFudge),
96 : : METH_NOARGS,
97 : : "Return the value of the Fudge field." },
98 : : { "get_original_id", reinterpret_cast<PyCFunction>(TSIG_getOriginalID),
99 : : METH_NOARGS,
100 : : "Return the value of the Original ID field." },
101 : : { "get_error", reinterpret_cast<PyCFunction>(TSIG_getError),
102 : : METH_NOARGS,
103 : : "Return the value of the Error field." },
104 : : { "get_mac", reinterpret_cast<PyCFunction>(TSIG_getMAC),
105 : : METH_NOARGS,
106 : : "Return the value of the MAC field."
107 : : "If it's empty, return None." },
108 : : { "get_other_data", reinterpret_cast<PyCFunction>(TSIG_getOtherData),
109 : : METH_NOARGS,
110 : : "Return the value of the Other Data field."
111 : : "If it's empty, return None." },
112 : : { "to_text", reinterpret_cast<PyCFunction>(TSIG_toText), METH_NOARGS,
113 : : "Returns the text representation" },
114 : : { "to_wire", reinterpret_cast<PyCFunction>(TSIG_toWire), METH_VARARGS,
115 : : "Converts the TSIG object to wire format.\n"
116 : : "The argument can be either a MessageRenderer or an object that "
117 : : "implements the sequence interface. If the object is mutable "
118 : : "(for instance a bytearray()), the wire data is added in-place.\n"
119 : : "If it is not (for instance a bytes() object), a new object is "
120 : : "returned" },
121 : : { NULL, NULL, 0, NULL }
122 : : };
123 : :
124 : : int
125 : 33 : TSIG_init(s_TSIG* self, PyObject* args) {
126 : : try {
127 : : // constructor from string
128 : : const char* rdata_str;
129 [ + - ][ + - ]: 33 : if (PyArg_ParseTuple(args, "s", &rdata_str)) {
130 [ + - ][ + - ]: 33 : self->cppobj = new any::TSIG(string(rdata_str));
[ + - ]
131 : : return (0);
132 : : }
133 : 0 : } catch (const exception& ex) {
134 : : const string ex_what = "Failed to construct TSIG object: " +
135 [ # # ][ # # ]: 0 : string(ex.what());
136 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
137 : : return (-1);
138 [ # # ]: 0 : } catch (...) {
139 : : PyErr_SetString(po_IscException,
140 [ # # ]: 0 : "Unexpected exception in constructing TSIG");
141 : : return (-1);
142 : : }
143 : :
144 : : PyErr_SetString(PyExc_TypeError,
145 : 0 : "Invalid arguments to TSIG constructor");
146 : :
147 : 33 : return (-1);
148 : : }
149 : :
150 : : void
151 : 61 : TSIG_destroy(s_TSIG* const self) {
152 [ + - ]: 61 : delete self->cppobj;
153 : 61 : self->cppobj = NULL;
154 : 61 : Py_TYPE(self)->tp_free(self);
155 : 61 : }
156 : :
157 : : PyObject*
158 : 29 : TSIG_getAlgorithm(const s_TSIG* const self) {
159 : : try {
160 [ + - ][ + - ]: 29 : return (createNameObject(self->cppobj->getAlgorithm()));
161 : 0 : } catch (const exception& ex) {
162 : : const string ex_what =
163 [ # # ][ # # ]: 0 : "Failed to get TSIG algorithm: " + string(ex.what());
164 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
165 [ # # ]: 0 : } catch (...) {
166 : : PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
167 [ # # ]: 0 : "getting TSIG algorithm");
168 : : }
169 : : return (NULL);
170 : : }
171 : :
172 : : PyObject*
173 : 11 : TSIG_getTimeSigned(const s_TSIG* const self) {
174 : 11 : return (Py_BuildValue("K", self->cppobj->getTimeSigned()));
175 : : }
176 : :
177 : : PyObject*
178 : 9 : TSIG_getFudge(const s_TSIG* const self) {
179 : 9 : return (Py_BuildValue("H", self->cppobj->getFudge()));
180 : : }
181 : :
182 : : PyObject*
183 : 9 : TSIG_getOriginalID(const s_TSIG* const self) {
184 : 9 : return (Py_BuildValue("H", self->cppobj->getOriginalID()));
185 : : }
186 : :
187 : : PyObject*
188 : 9 : TSIG_getError(const s_TSIG* const self) {
189 : 9 : return (Py_BuildValue("H", self->cppobj->getError()));
190 : : }
191 : :
192 : : PyObject*
193 : 9 : TSIG_getMAC(const s_TSIG* const self) {
194 : : return (Py_BuildValue("y#", self->cppobj->getMAC(),
195 : 9 : self->cppobj->getMACSize()));
196 : : }
197 : :
198 : : PyObject*
199 : 9 : TSIG_getOtherData(const s_TSIG* const self) {
200 : : return (Py_BuildValue("y#", self->cppobj->getOtherData(),
201 : 9 : self->cppobj->getOtherLen()));
202 : : }
203 : :
204 : : PyObject*
205 : 0 : TSIG_toText(const s_TSIG* const self) {
206 : : try {
207 : : // toText() could throw, so we need to catch any exceptions below.
208 [ # # ][ # # ]: 0 : return (Py_BuildValue("s", self->cppobj->toText().c_str()));
209 : 0 : } catch (const exception& ex) {
210 : : const string ex_what =
211 : : "Failed to convert TSIG object to text: " +
212 [ # # ][ # # ]: 0 : string(ex.what());
213 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
214 [ # # ]: 0 : } catch (...) {
215 : : PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
216 [ # # ]: 0 : "converting TSIG object to text");
217 : : }
218 : : return (NULL);
219 : : }
220 : :
221 : : PyObject*
222 : 0 : TSIG_str(PyObject* self) {
223 : : // Simply call the to_text method we already defined
224 : : return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
225 : 0 : const_cast<char*>("")));
226 : : }
227 : :
228 : : PyObject*
229 : 0 : TSIG_toWire(const s_TSIG* const self, PyObject* args) {
230 : : typedef any::TSIG TSIGRdata;
231 : : return (toWireWrapper<s_TSIG, TSIGRdata, ToWireCallVoid<const TSIGRdata> >(
232 : 0 : self, args));
233 : : }
234 : :
235 : : PyObject*
236 : 0 : TSIG_richcmp(const s_TSIG* const self,
237 : : const s_TSIG* const other,
238 : : const int op)
239 : : {
240 : 0 : bool c = false;
241 : :
242 : : // Check for null and if the types match. If different type,
243 : : // simply return False
244 [ # # ][ # # ]: 0 : if (other == NULL || (self->ob_type != other->ob_type)) {
245 : 0 : Py_RETURN_FALSE;
246 : : }
247 : :
248 : : // Only equals and not equals here, unorderable type
249 : 0 : const int cmp = self->cppobj->compare(*other->cppobj);
250 [ # # # # : 0 : switch (op) {
# # # ]
251 : : case Py_EQ:
252 : 0 : c = (cmp == 0);
253 : 0 : break;
254 : : case Py_NE:
255 : 0 : c = (cmp != 0);
256 : 0 : break;
257 : : case Py_GT:
258 : 0 : c = (cmp > 0);
259 : 0 : break;
260 : : case Py_GE:
261 : 0 : c = (cmp >= 0);
262 : 0 : break;
263 : : case Py_LT:
264 : 0 : c = (cmp < 0);
265 : 0 : break;
266 : : case Py_LE:
267 : 0 : c = (cmp <= 0);
268 : 0 : break;
269 : : default:
270 : : PyErr_SetString(PyExc_IndexError,
271 : 0 : "Unhandled rich comparison operator for TSIG");
272 : 0 : return (NULL);
273 : : }
274 [ # # ]: 0 : if (c) {
275 : 0 : Py_RETURN_TRUE;
276 : : } else {
277 : 0 : Py_RETURN_FALSE;
278 : : }
279 : : }
280 : : } // end of unnamed namespace
281 : :
282 : : namespace isc {
283 : : namespace dns {
284 : : namespace python {
285 : : // This defines the complete type for reflection in python and
286 : : // parsing of PyObject* to s_TSIG
287 : : // Most of the functions are not actually implemented and NULL here.
288 : : PyTypeObject tsig_type = {
289 : : PyVarObject_HEAD_INIT(NULL, 0)
290 : : "pydnspp.TSIG",
291 : : sizeof(s_TSIG), // tp_basicsize
292 : : 0, // tp_itemsize
293 : : reinterpret_cast<destructor>(TSIG_destroy), // tp_dealloc
294 : : NULL, // tp_print
295 : : NULL, // tp_getattr
296 : : NULL, // tp_setattr
297 : : NULL, // tp_reserved
298 : : NULL, // tp_repr
299 : : NULL, // tp_as_number
300 : : NULL, // tp_as_sequence
301 : : NULL, // tp_as_mapping
302 : : NULL, // tp_hash
303 : : NULL, // tp_call
304 : : TSIG_str, // tp_str
305 : : NULL, // tp_getattro
306 : : NULL, // tp_setattro
307 : : NULL, // tp_as_buffer
308 : : Py_TPFLAGS_DEFAULT, // tp_flags
309 : : "The TSIG class objects represents the TSIG RDATA as defined in RFC2845.",
310 : : NULL, // tp_traverse
311 : : NULL, // tp_clear
312 : : reinterpret_cast<richcmpfunc>(TSIG_richcmp), // tp_richcompare
313 : : 0, // tp_weaklistoffset
314 : : NULL, // tp_iter
315 : : NULL, // tp_iternext
316 : : TSIG_methods, // tp_methods
317 : : NULL, // tp_members
318 : : NULL, // tp_getset
319 : : // At the moment, we leave tp_base NULL as we won't use this class
320 : : // in a polymorphic way for our immediate need.
321 : : NULL, // tp_base
322 : : NULL, // tp_dict
323 : : NULL, // tp_descr_get
324 : : NULL, // tp_descr_set
325 : : 0, // tp_dictoffset
326 : : reinterpret_cast<initproc>(TSIG_init), // tp_init
327 : : NULL, // tp_alloc
328 : : PyType_GenericNew, // tp_new
329 : : NULL, // tp_free
330 : : NULL, // tp_is_gc
331 : : NULL, // tp_bases
332 : : NULL, // tp_mro
333 : : NULL, // tp_cache
334 : : NULL, // tp_subclasses
335 : : NULL, // tp_weaklist
336 : : NULL, // tp_del
337 : : 0 // tp_version_tag
338 : : };
339 : :
340 : : PyObject*
341 : 28 : createTSIGObject(const any::TSIG& source) {
342 : 28 : TSIGContainer container(PyObject_New(s_TSIG, &tsig_type));
343 [ + - ][ + - ]: 28 : container.set(new any::TSIG(source));
[ + - ]
344 : 28 : return (container.release());
345 : : }
346 : :
347 : : bool
348 : 0 : PyTSIG_Check(PyObject* obj) {
349 [ # # ]: 0 : if (obj == NULL) {
350 [ # # ][ # # ]: 0 : isc_throw(PyCPPWrapperException, "obj argument NULL in typecheck");
351 : : }
352 [ # # ][ # # ]: 0 : return (PyObject_TypeCheck(obj, &tsig_type));
353 : : }
354 : :
355 : : const any::TSIG&
356 : 36 : PyTSIG_ToTSIG(const PyObject* tsig_obj) {
357 [ - + ]: 36 : if (tsig_obj == NULL) {
358 [ # # ][ # # ]: 0 : isc_throw(PyCPPWrapperException,
359 : : "obj argument NULL in TSIG PyObject conversion");
360 : : }
361 : 36 : const s_TSIG* tsig = static_cast<const s_TSIG*>(tsig_obj);
362 : 36 : return (*tsig->cppobj);
363 : : }
364 : :
365 : : } // namespace python
366 : : } // namespace dns
367 : 123 : } // namespace isc
|