Branch data Line data Source code
1 : : // Copyright (C) 2010 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 <exceptions/exceptions.h>
19 : : #include <util/python/pycppwrapper_util.h>
20 : : #include <dns/message.h>
21 : : #include <dns/rcode.h>
22 : : #include <dns/tsig.h>
23 : : #include <dns/exceptions.h>
24 : : #include <dns/messagerenderer.h>
25 : :
26 : : #include "name_python.h"
27 : : #include "question_python.h"
28 : : #include "edns_python.h"
29 : : #include "rcode_python.h"
30 : : #include "opcode_python.h"
31 : : #include "rrset_python.h"
32 : : #include "message_python.h"
33 : : #include "messagerenderer_python.h"
34 : : #include "tsig_python.h"
35 : : #include "tsigrecord_python.h"
36 : : #include "pydnspp_common.h"
37 : :
38 : : using namespace std;
39 : : using namespace isc::dns;
40 : : using namespace isc::dns::python;
41 : : using namespace isc::util;
42 : : using namespace isc::util::python;
43 : :
44 : : // Import pydoc text
45 : : #include "message_python_inc.cc"
46 : :
47 : : namespace {
48 : : class s_Message : public PyObject {
49 : : public:
50 : : isc::dns::Message* cppobj;
51 : : };
52 : :
53 : : int Message_init(s_Message* self, PyObject* args);
54 : : void Message_destroy(s_Message* self);
55 : :
56 : : PyObject* Message_getHeaderFlag(s_Message* self, PyObject* args);
57 : : PyObject* Message_setHeaderFlag(s_Message* self, PyObject* args);
58 : : PyObject* Message_getQid(s_Message* self);
59 : : PyObject* Message_setQid(s_Message* self, PyObject* args);
60 : : PyObject* Message_getRcode(s_Message* self);
61 : : PyObject* Message_setRcode(s_Message* self, PyObject* args);
62 : : PyObject* Message_getOpcode(s_Message* self);
63 : : PyObject* Message_setOpcode(s_Message* self, PyObject* args);
64 : : PyObject* Message_getEDNS(s_Message* self);
65 : : PyObject* Message_setEDNS(s_Message* self, PyObject* args);
66 : : PyObject* Message_getTSIGRecord(s_Message* self);
67 : : PyObject* Message_getRRCount(s_Message* self, PyObject* args);
68 : : // use direct iterators for these? (or simply lists for now?)
69 : : PyObject* Message_getQuestion(PyObject* self, PyObject*);
70 : : PyObject* Message_getSection(PyObject* self, PyObject* args);
71 : : //static PyObject* Message_beginQuestion(s_Message* self, PyObject* args);
72 : : //static PyObject* Message_endQuestion(s_Message* self, PyObject* args);
73 : : //static PyObject* Message_beginSection(s_Message* self, PyObject* args);
74 : : //static PyObject* Message_endSection(s_Message* self, PyObject* args);
75 : :
76 : : PyObject* Message_addQuestion(s_Message* self, PyObject* args);
77 : : PyObject* Message_addRRset(s_Message* self, PyObject* args);
78 : : PyObject* Message_clear(s_Message* self, PyObject* args);
79 : : PyObject* Message_makeResponse(s_Message* self);
80 : : PyObject* Message_toText(s_Message* self);
81 : : PyObject* Message_str(PyObject* self);
82 : : PyObject* Message_toWire(s_Message* self, PyObject* args);
83 : : PyObject* Message_fromWire(PyObject* pyself, PyObject* args);
84 : :
85 : : // This list contains the actual set of functions we have in
86 : : // python. Each entry has
87 : : // 1. Python method name
88 : : // 2. Our static function here
89 : : // 3. Argument type
90 : : // 4. Documentation
91 : : PyMethodDef Message_methods[] = {
92 : : { "get_header_flag", reinterpret_cast<PyCFunction>(Message_getHeaderFlag),
93 : : METH_VARARGS,
94 : : "Return whether the specified header flag bit is set in the "
95 : : "header section. Takes a MessageFlag object as the only argument." },
96 : : { "set_header_flag",
97 : : reinterpret_cast<PyCFunction>(Message_setHeaderFlag), METH_VARARGS,
98 : : "Sets the specified header flag bit to 1. The message must be in "
99 : : "RENDER mode. If not, an InvalidMessageOperation is raised. "
100 : : "Takes a MessageFlag object as the only argument." },
101 : : { "get_qid", reinterpret_cast<PyCFunction>(Message_getQid), METH_NOARGS,
102 : : "Returns the query id" },
103 : : { "set_qid", reinterpret_cast<PyCFunction>(Message_setQid), METH_VARARGS,
104 : : "Sets the query id. If the message is not in RENDER mode, an "
105 : : "InvalidMessageOperation is raised.\n"
106 : : "The argument must be an integer" },
107 : : { "get_rcode", reinterpret_cast<PyCFunction>(Message_getRcode), METH_NOARGS,
108 : : "Returns the message Response code (an Rcode object)" },
109 : : { "set_rcode", reinterpret_cast<PyCFunction>(Message_setRcode), METH_VARARGS,
110 : : "Sets the message Response code (an Rcode object).\n"
111 : : "If the message is not in RENDER mode, an "
112 : : "InvalidMessageOperation is raised."},
113 : : { "get_opcode", reinterpret_cast<PyCFunction>(Message_getOpcode), METH_NOARGS,
114 : : "Returns the message opcode (an Opcode object)" },
115 : : { "set_opcode", reinterpret_cast<PyCFunction>(Message_setOpcode), METH_VARARGS,
116 : : "Sets the message opcode (an Opcode object).\n"
117 : : "If the message is not in RENDER mode, an "
118 : : "InvalidMessageOperation is raised."},
119 : : { "get_edns", reinterpret_cast<PyCFunction>(Message_getEDNS), METH_NOARGS,
120 : : "Return, if any, the EDNS associated with the message."
121 : : },
122 : : { "set_edns", reinterpret_cast<PyCFunction>(Message_setEDNS), METH_VARARGS,
123 : : "Set EDNS for the message."
124 : : },
125 : : { "get_tsig_record",
126 : : reinterpret_cast<PyCFunction>(Message_getTSIGRecord), METH_NOARGS,
127 : : "Return, if any, the TSIG record contained in the received message. "
128 : : "If no TSIG RR is set in the message, None will be returned."
129 : : },
130 : : { "get_rr_count", reinterpret_cast<PyCFunction>(Message_getRRCount), METH_VARARGS,
131 : : "Returns the number of RRs contained in the given section." },
132 : : { "get_question", Message_getQuestion, METH_NOARGS,
133 : : "Returns a list of all Question objects in the message "
134 : : "(should be either 0 or 1)" },
135 : : { "get_section", Message_getSection, METH_VARARGS,
136 : : "Returns a list of all RRset objects in the given section of the message\n"
137 : : "The argument must be of type Section" },
138 : : { "add_question", reinterpret_cast<PyCFunction>(Message_addQuestion), METH_VARARGS,
139 : : "Add a Question to the message."
140 : : "If the message is not in RENDER mode, an "
141 : : "InvalidMessageOperation is raised."},
142 : : { "add_rrset", reinterpret_cast<PyCFunction>(Message_addRRset), METH_VARARGS,
143 : : "Add an RRset to the given section of the message.\n"
144 : : "The first argument is of type Section\n"
145 : : "The second is of type RRset\n"
146 : : "The third argument is an optional Boolean specifying whether "
147 : : "the RRset is signed"},
148 : : { "clear", reinterpret_cast<PyCFunction>(Message_clear), METH_VARARGS,
149 : : "Clears the message content (if any) and reinitialize the "
150 : : "message in the given mode\n"
151 : : "The argument must be either Message.PARSE or Message.RENDER"},
152 : : { "make_response", reinterpret_cast<PyCFunction>(Message_makeResponse), METH_NOARGS,
153 : : "Prepare for making a response from a request.\n"
154 : : "This will clear the DNS header except those fields that should be kept "
155 : : "for the response, and clear answer and the following sections. "
156 : : "See also dns_message_reply() of BIND9."},
157 : : { "to_text", reinterpret_cast<PyCFunction>(Message_toText), METH_NOARGS,
158 : : "Returns the string representation of the message" },
159 : : { "to_wire", reinterpret_cast<PyCFunction>(Message_toWire), METH_VARARGS,
160 : : "Render the message in wire format.\n"
161 : : "The argument must be a MessageRenderer.\n"
162 : : "If the given message is not in RENDER mode, an "
163 : : "InvalidMessageOperation is raised.\n"
164 : : },
165 : : { "from_wire", Message_fromWire, METH_VARARGS, Message_fromWire_doc },
166 : : { NULL, NULL, 0, NULL }
167 : : };
168 : :
169 : : int
170 : 715 : Message_init(s_Message* self, PyObject* args) {
171 : : int i;
172 : :
173 [ + + ]: 715 : if (PyArg_ParseTuple(args, "i", &i)) {
174 : 714 : PyErr_Clear();
175 [ + + ]: 714 : if (i == Message::PARSE) {
176 [ + - ]: 373 : self->cppobj = new Message(Message::PARSE);
177 : 373 : return (0);
178 [ + + ]: 341 : } else if (i == Message::RENDER) {
179 [ + - ]: 339 : self->cppobj = new Message(Message::RENDER);
180 : 339 : return (0);
181 : : } else {
182 : 2 : PyErr_SetString(PyExc_TypeError, "Message mode must be Message.PARSE or Message.RENDER");
183 : 2 : return (-1);
184 : : }
185 : : }
186 : 1 : PyErr_Clear();
187 : : PyErr_SetString(PyExc_TypeError,
188 : 1 : "no valid type in constructor argument");
189 : 715 : return (-1);
190 : : }
191 : :
192 : : void
193 : 715 : Message_destroy(s_Message* self) {
194 [ + + ]: 715 : delete self->cppobj;
195 : 715 : self->cppobj = NULL;
196 : 715 : Py_TYPE(self)->tp_free(self);
197 : 715 : }
198 : :
199 : : PyObject*
200 : 122 : Message_getHeaderFlag(s_Message* self, PyObject* args) {
201 : : unsigned int messageflag;
202 [ + + ]: 122 : if (!PyArg_ParseTuple(args, "I", &messageflag)) {
203 : 1 : PyErr_Clear();
204 : : PyErr_SetString(PyExc_TypeError,
205 : 1 : "no valid type in get_header_flag argument");
206 : 1 : return (NULL);
207 : : }
208 : :
209 [ + + ]: 121 : if (self->cppobj->getHeaderFlag(
210 : 121 : static_cast<Message::HeaderFlag>(messageflag))) {
211 : 109 : Py_RETURN_TRUE;
212 : : } else {
213 : 122 : Py_RETURN_FALSE;
214 : : }
215 : : }
216 : :
217 : : PyObject*
218 : 504 : Message_setHeaderFlag(s_Message* self, PyObject* args) {
219 : : long messageflag;
220 : 504 : PyObject *on = Py_True;
221 : :
222 [ + + ]: 504 : if (!PyArg_ParseTuple(args, "l|O!", &messageflag, &PyBool_Type, &on)) {
223 : 1 : PyErr_Clear();
224 : : PyErr_SetString(PyExc_TypeError,
225 : 1 : "no valid type in set_header_flag argument");
226 : 1 : return (NULL);
227 : : }
228 [ + + ]: 503 : if (messageflag < 0 || messageflag > 0xffff) {
229 : 2 : PyErr_SetString(PyExc_ValueError, "Message header flag out of range");
230 : 2 : return (NULL);
231 : : }
232 : :
233 : : try {
234 : : self->cppobj->setHeaderFlag(
235 [ + + ]: 501 : static_cast<Message::HeaderFlag>(messageflag), on == Py_True);
236 : 504 : Py_RETURN_NONE;
237 : 2 : } catch (const InvalidMessageOperation& imo) {
238 [ - + ]: 1 : PyErr_Clear();
239 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
240 : : return (NULL);
241 [ - + + ]: 7 : } catch (const isc::InvalidParameter& ip) {
242 [ - + ]: 3 : PyErr_Clear();
243 [ - + ]: 3 : PyErr_SetString(po_InvalidParameter, ip.what());
244 : : return (NULL);
245 : : }
246 : : }
247 : :
248 : : PyObject*
249 : 202 : Message_getQid(s_Message* self) {
250 : 202 : return (Py_BuildValue("I", self->cppobj->getQid()));
251 : : }
252 : :
253 : : PyObject*
254 : 421 : Message_setQid(s_Message* self, PyObject* args) {
255 : : long id;
256 [ + + ]: 421 : if (!PyArg_ParseTuple(args, "l", &id)) {
257 : 1 : PyErr_Clear();
258 : : PyErr_SetString(PyExc_TypeError,
259 : 1 : "no valid type in set_qid argument");
260 : 1 : return (NULL);
261 : : }
262 [ + + ]: 420 : if (id < 0 || id > 0xffff) {
263 : : PyErr_SetString(PyExc_ValueError,
264 : 2 : "Message id out of range");
265 : 2 : return (NULL);
266 : : }
267 : :
268 : : try {
269 [ + + ]: 418 : self->cppobj->setQid(id);
270 : 421 : Py_RETURN_NONE;
271 [ - + ]: 2 : } catch (const InvalidMessageOperation& imo) {
272 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
273 : : return (NULL);
274 : : }
275 : : }
276 : :
277 : : PyObject*
278 : 209 : Message_getRcode(s_Message* self) {
279 : : try {
280 [ + + ][ + - ]: 210 : return (createRcodeObject(self->cppobj->getRcode()));
281 : 2 : } catch (const InvalidMessageOperation& imo) {
282 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
283 : : return (NULL);
284 [ + - ]: 1 : } catch (...) {
285 [ # # ]: 0 : PyErr_SetString(po_IscException, "Unexpected exception");
286 : : return (NULL);
287 : : }
288 : : }
289 : :
290 : : PyObject*
291 : 428 : Message_setRcode(s_Message* self, PyObject* args) {
292 : : PyObject* rcode;
293 [ + + ]: 428 : if (!PyArg_ParseTuple(args, "O!", &rcode_type, &rcode)) {
294 : : return (NULL);
295 : : }
296 : : try {
297 [ + - ][ + + ]: 427 : self->cppobj->setRcode(PyRcode_ToRcode(rcode));
298 : 428 : Py_RETURN_NONE;
299 [ - + ]: 2 : } catch (const InvalidMessageOperation& imo) {
300 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
301 : : return (NULL);
302 : : }
303 : : }
304 : :
305 : : PyObject*
306 : 122 : Message_getOpcode(s_Message* self) {
307 : : try {
308 [ + + ][ + - ]: 123 : return (createOpcodeObject(self->cppobj->getOpcode()));
309 : 2 : } catch (const InvalidMessageOperation& imo) {
310 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
311 : : return (NULL);
312 : 0 : } catch (const exception& ex) {
313 : : const string ex_what =
314 [ # # ][ # # ]: 0 : "Failed to get message opcode: " + string(ex.what());
315 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
316 : : return (NULL);
317 [ + - - ]: 1 : } catch (...) {
318 : : PyErr_SetString(po_IscException,
319 [ # # ]: 0 : "Unexpected exception getting opcode from message");
320 : : return (NULL);
321 : : }
322 : : }
323 : :
324 : : PyObject*
325 : 422 : Message_setOpcode(s_Message* self, PyObject* args) {
326 : : PyObject* opcode;
327 [ + + ]: 422 : if (!PyArg_ParseTuple(args, "O!", &opcode_type, &opcode)) {
328 : : return (NULL);
329 : : }
330 : : try {
331 [ + - ][ + + ]: 421 : self->cppobj->setOpcode(PyOpcode_ToOpcode(opcode));
332 : 422 : Py_RETURN_NONE;
333 [ - + ]: 2 : } catch (const InvalidMessageOperation& imo) {
334 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
335 : : return (NULL);
336 : : }
337 : : }
338 : :
339 : : PyObject*
340 : 3 : Message_getEDNS(s_Message* self) {
341 : 3 : ConstEDNSPtr src = self->cppobj->getEDNS();
342 [ + + ]: 3 : if (!src) {
343 : 1 : Py_RETURN_NONE;
344 : : }
345 : : try {
346 [ + - ]: 2 : return (createEDNSObject(*src));
347 : 0 : } catch (const exception& ex) {
348 : : const string ex_what =
349 [ # # ][ # # ]: 0 : "Failed to get EDNS from message: " + string(ex.what());
350 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
351 [ # # ][ # # ]: 0 : } catch (...) {
352 : : PyErr_SetString(PyExc_SystemError,
353 [ # # ]: 0 : "Unexpected failure getting EDNS from message");
354 : : }
355 : : return (NULL);
356 : : }
357 : :
358 : : PyObject*
359 : 3 : Message_setEDNS(s_Message* self, PyObject* args) {
360 : : PyObject* edns;
361 [ + - ]: 3 : if (!PyArg_ParseTuple(args, "O!", &edns_type, &edns)) {
362 : : return (NULL);
363 : : }
364 : : try {
365 [ + - ][ + - ]: 6 : self->cppobj->setEDNS(EDNSPtr(new EDNS(PyEDNS_ToEDNS(edns))));
[ + + ]
366 : 3 : Py_RETURN_NONE;
367 [ - + ]: 2 : } catch (const InvalidMessageOperation& imo) {
368 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
369 : : return (NULL);
370 : : }
371 : : }
372 : :
373 : : PyObject*
374 : 325 : Message_getTSIGRecord(s_Message* self) {
375 : : try {
376 [ + + ]: 325 : const TSIGRecord* tsig_record = self->cppobj->getTSIGRecord();
377 : :
378 [ + + ]: 324 : if (tsig_record == NULL) {
379 : 161 : Py_RETURN_NONE;
380 : : } else {
381 [ + - ]: 325 : return (createTSIGRecordObject(*tsig_record));
382 : : }
383 : 2 : } catch (const InvalidMessageOperation& ex) {
384 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, ex.what());
385 : 0 : } catch (const exception& ex) {
386 : : const string ex_what =
387 : : "Unexpected failure in getting TSIGRecord from message: " +
388 [ # # ][ # # ]: 0 : string(ex.what());
389 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
390 [ + - - ]: 1 : } catch (...) {
391 : : PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
392 [ # # ]: 0 : "getting TSIGRecord from message");
393 : : }
394 : : return (NULL);
395 : : }
396 : :
397 : : PyObject*
398 : 283 : Message_getRRCount(s_Message* self, PyObject* args) {
399 : : unsigned int section;
400 [ + + ]: 283 : if (!PyArg_ParseTuple(args, "I", §ion)) {
401 : 1 : PyErr_Clear();
402 : : PyErr_SetString(PyExc_TypeError,
403 : 1 : "no valid type in get_rr_count argument");
404 : 1 : return (NULL);
405 : : }
406 : : try {
407 : : return (Py_BuildValue("I", self->cppobj->getRRCount(
408 [ + + ][ + - ]: 284 : static_cast<Message::Section>(section))));
409 [ - + ]: 2 : } catch (const isc::OutOfRange& ex) {
410 [ - + ]: 1 : PyErr_SetString(PyExc_OverflowError, ex.what());
411 : : return (NULL);
412 : : }
413 : : }
414 : :
415 : : // This is a helper templated class commonly used for getQuestion and
416 : : // getSection in order to build a list of Message section items.
417 : : template <typename ItemType, typename CreatorParamType>
418 : : class SectionInserter {
419 : : typedef PyObject* (*creator_t)(const CreatorParamType&);
420 : : public:
421 : : SectionInserter(PyObject* pylist, creator_t creator) :
422 : 239 : pylist_(pylist), creator_(creator)
423 : : {}
424 : : void operator()(ItemType item) {
425 [ + - ][ + - ]: 359 : if (PyList_Append(pylist_, PyObjectContainer(creator_(*item)).get())
[ + - ][ + - ]
[ - + ][ + - ]
[ + - ][ + - ]
[ + - ][ - + ]
426 : : == -1) {
427 [ # # ][ # # ]: 0 : isc_throw(PyCPPWrapperException, "PyList_Append failed, "
[ # # ][ # # ]
[ # # ][ # # ]
428 : : "probably due to short memory");
429 : : }
430 : : }
431 : : private:
432 : : PyObject* pylist_;
433 : : creator_t creator_;
434 : : };
435 : :
436 : : typedef SectionInserter<ConstQuestionPtr, Question> QuestionInserter;
437 : : typedef SectionInserter<ConstRRsetPtr, AbstractRRset> RRsetInserter;
438 : :
439 : : // TODO use direct iterators for these? (or simply lists for now?)
440 : : PyObject*
441 : 107 : Message_getQuestion(PyObject* po_self, PyObject*) {
442 : 107 : const s_Message* const self = static_cast<s_Message*>(po_self);
443 : :
444 : : try {
445 [ + - ][ + - ]: 214 : PyObjectContainer list_container(PyList_New(0));
[ + - ]
446 [ + - ]: 107 : for_each(self->cppobj->beginQuestion(),
447 [ + - ]: 107 : self->cppobj->endQuestion(),
448 [ + - ][ + - ]: 107 : QuestionInserter(list_container.get(), createQuestionObject));
449 : : return (list_container.release());
450 : 0 : } catch (const InvalidMessageSection& ex) {
451 [ # # ]: 0 : PyErr_SetString(po_InvalidMessageSection, ex.what());
452 : 0 : } catch (const exception& ex) {
453 : : const string ex_what =
454 : : "Unexpected failure in Message.get_question: " +
455 [ # # ][ # # ]: 0 : string(ex.what());
456 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
457 [ # # # ]: 0 : } catch (...) {
458 : : PyErr_SetString(PyExc_SystemError,
459 [ # # ]: 0 : "Unexpected failure in Message.get_question");
460 : : }
461 : : return (NULL);
462 : : }
463 : :
464 : : PyObject*
465 : 133 : Message_getSection(PyObject* po_self, PyObject* args) {
466 : 133 : const s_Message* const self = static_cast<s_Message*>(po_self);
467 : :
468 : : unsigned int section;
469 [ + + ]: 133 : if (!PyArg_ParseTuple(args, "I", §ion)) {
470 : 1 : PyErr_Clear();
471 : : PyErr_SetString(PyExc_TypeError,
472 : 1 : "no valid type in get_section argument");
473 : 1 : return (NULL);
474 : : }
475 : :
476 : : try {
477 [ + - ][ + - ]: 265 : PyObjectContainer list_container(PyList_New(0));
[ + - ]
478 : : const Message::Section msgsection =
479 : 132 : static_cast<Message::Section>(section);
480 [ + - ]: 132 : for_each(self->cppobj->beginSection(msgsection),
481 [ + - ]: 132 : self->cppobj->endSection(msgsection),
482 [ + - ][ + - ]: 132 : RRsetInserter(list_container.get(), createRRsetObject));
483 : : return (list_container.release());
484 : 0 : } catch (const isc::OutOfRange& ex) {
485 [ # # ]: 0 : PyErr_SetString(PyExc_OverflowError, ex.what());
486 : 0 : } catch (const InvalidMessageSection& ex) {
487 [ # # ]: 0 : PyErr_SetString(po_InvalidMessageSection, ex.what());
488 : 0 : } catch (const exception& ex) {
489 : : const string ex_what =
490 : : "Unexpected failure in Message.get_section: " +
491 [ # # ][ # # ]: 0 : string(ex.what());
492 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
493 [ # # # # ]: 0 : } catch (...) {
494 : : PyErr_SetString(PyExc_SystemError,
495 [ # # ]: 0 : "Unexpected failure in Message.get_section");
496 : : }
497 : : return (NULL);
498 : : }
499 : :
500 : : //static PyObject* Message_beginQuestion(s_Message* self, PyObject* args);
501 : : //static PyObject* Message_endQuestion(s_Message* self, PyObject* args);
502 : : //static PyObject* Message_beginSection(s_Message* self, PyObject* args);
503 : : //static PyObject* Message_endSection(s_Message* self, PyObject* args);
504 : : //static PyObject* Message_addQuestion(s_Message* self, PyObject* args);
505 : : PyObject*
506 : 372 : Message_addQuestion(s_Message* self, PyObject* args) {
507 : : PyObject* question;
508 : :
509 [ + + ]: 372 : if (!PyArg_ParseTuple(args, "O!", &question_type, &question)) {
510 : : return (NULL);
511 : : }
512 : :
513 : 371 : self->cppobj->addQuestion(PyQuestion_ToQuestion(question));
514 : :
515 : 372 : Py_RETURN_NONE;
516 : : }
517 : :
518 : : PyObject*
519 : 402 : Message_addRRset(s_Message* self, PyObject* args) {
520 : 402 : PyObject *sign = Py_False;
521 : : int section;
522 : : PyObject* rrset;
523 [ + + ]: 402 : if (!PyArg_ParseTuple(args, "iO!|O!", §ion, &rrset_type, &rrset,
524 : 402 : &PyBool_Type, &sign)) {
525 : : return (NULL);
526 : : }
527 : :
528 : : try {
529 : : self->cppobj->addRRset(static_cast<Message::Section>(section),
530 [ + - ][ + + ]: 400 : PyRRset_ToRRsetPtr(rrset), sign == Py_True);
531 : 402 : Py_RETURN_NONE;
532 : 4 : } catch (const InvalidMessageOperation& imo) {
533 [ - + ]: 2 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
534 : : return (NULL);
535 : 4 : } catch (const isc::OutOfRange& ex) {
536 [ - + ]: 2 : PyErr_SetString(PyExc_OverflowError, ex.what());
537 : : return (NULL);
538 [ + + - ]: 4 : } catch (...) {
539 : : PyErr_SetString(po_IscException,
540 [ # # ]: 0 : "Unexpected exception in adding RRset");
541 : : return (NULL);
542 : : }
543 : : }
544 : :
545 : : PyObject*
546 : 162 : Message_clear(s_Message* self, PyObject* args) {
547 : : int i;
548 [ + + ]: 162 : if (PyArg_ParseTuple(args, "i", &i)) {
549 : 161 : PyErr_Clear();
550 [ + + ]: 161 : if (i == Message::PARSE) {
551 : 24 : self->cppobj->clear(Message::PARSE);
552 : 24 : Py_RETURN_NONE;
553 [ + + ]: 137 : } else if (i == Message::RENDER) {
554 : 136 : self->cppobj->clear(Message::RENDER);
555 : 136 : Py_RETURN_NONE;
556 : : } else {
557 : : PyErr_SetString(PyExc_TypeError,
558 : 1 : "Message mode must be Message.PARSE or Message.RENDER");
559 : 162 : return (NULL);
560 : : }
561 : : } else {
562 : : return (NULL);
563 : : }
564 : : }
565 : :
566 : : PyObject*
567 : 26 : Message_makeResponse(s_Message* self) {
568 : 26 : self->cppobj->makeResponse();
569 : 26 : Py_RETURN_NONE;
570 : : }
571 : :
572 : : PyObject*
573 : 4 : Message_toText(s_Message* self) {
574 : : // Py_BuildValue makes python objects from native data
575 : : try {
576 [ + + ][ + - ]: 6 : return (Py_BuildValue("s", self->cppobj->toText().c_str()));
577 : 4 : } catch (const InvalidMessageOperation& imo) {
578 [ - + ]: 2 : PyErr_Clear();
579 [ - + ]: 2 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
580 : : return (NULL);
581 [ + - ]: 2 : } catch (...) {
582 [ # # ]: 0 : PyErr_SetString(po_IscException, "Unexpected exception");
583 : : return (NULL);
584 : : }
585 : : }
586 : :
587 : : PyObject*
588 : 1 : Message_str(PyObject* self) {
589 : : // Simply call the to_text method we already defined
590 : : return (PyObject_CallMethod(self,
591 : : const_cast<char*>("to_text"),
592 : 1 : const_cast<char*>("")));
593 : : }
594 : :
595 : : PyObject*
596 : 446 : Message_toWire(s_Message* self, PyObject* args) {
597 : : PyObject* mr;
598 : 446 : PyObject* tsig_ctx = NULL;
599 : :
600 [ + + ]: 446 : if (PyArg_ParseTuple(args, "O!|O!", &messagerenderer_type, &mr,
601 : 446 : &tsigcontext_type, &tsig_ctx)) {
602 : : try {
603 [ + + ]: 445 : if (tsig_ctx == NULL) {
604 [ + - ][ + + ]: 302 : self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr));
605 : : } else {
606 [ + - ]: 143 : self->cppobj->toWire(PyMessageRenderer_ToMessageRenderer(mr),
607 [ + - ][ + + ]: 286 : PyTSIGContext_ToTSIGContext(tsig_ctx));
608 : : }
609 : : // If we return NULL it is seen as an error, so use this for
610 : : // None returns
611 : 440 : Py_RETURN_NONE;
612 : 6 : } catch (const InvalidMessageOperation& imo) {
613 [ - + ]: 3 : PyErr_Clear();
614 [ - + ]: 3 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
615 : : return (NULL);
616 : 0 : } catch (const TSIGContextError& ex) {
617 : : // toWire() with a TSIG context can fail due to this if the
618 : : // python program has a bug.
619 [ # # ]: 0 : PyErr_SetString(po_TSIGContextError, ex.what());
620 : : return (NULL);
621 : 4 : } catch (const std::exception& ex) {
622 : : // Other exceptions should be rare (most likely an implementation
623 : : // bug)
624 [ - + ]: 2 : PyErr_SetString(po_TSIGContextError, ex.what());
625 : : return (NULL);
626 [ + - + - ]: 5 : } catch (...) {
627 : : PyErr_SetString(PyExc_RuntimeError,
628 [ # # ]: 0 : "Unexpected C++ exception in Message.to_wire");
629 : : return (NULL);
630 : : }
631 : : }
632 : 1 : PyErr_Clear();
633 : : PyErr_SetString(PyExc_TypeError,
634 : 1 : "toWire argument must be a MessageRenderer");
635 : 446 : return (NULL);
636 : : }
637 : :
638 : : PyObject*
639 : 374 : Message_fromWire(PyObject* pyself, PyObject* args) {
640 : 374 : s_Message* const self = static_cast<s_Message*>(pyself);
641 : : const char* b;
642 : : Py_ssize_t len;
643 : 374 : unsigned int options = Message::PARSE_DEFAULT;
644 : :
645 [ + + + + ]: 633 : if (PyArg_ParseTuple(args, "y#", &b, &len) ||
[ + + ]
646 : 259 : PyArg_ParseTuple(args, "y#I", &b, &len, &options)) {
647 : : // We need to clear the error in case the first call to ParseTuple
648 : : // fails.
649 : 373 : PyErr_Clear();
650 : :
651 : 373 : InputBuffer inbuf(b, len);
652 : : try {
653 : : self->cppobj->fromWire(
654 [ + + ]: 373 : inbuf, static_cast<Message::ParseOptions>(options));
655 : 355 : Py_RETURN_NONE;
656 : 2 : } catch (const InvalidMessageOperation& imo) {
657 [ - + ]: 1 : PyErr_SetString(po_InvalidMessageOperation, imo.what());
658 : : return (NULL);
659 : 14 : } catch (const DNSMessageFORMERR& dmfe) {
660 [ - + ]: 7 : PyErr_SetString(po_DNSMessageFORMERR, dmfe.what());
661 : : return (NULL);
662 : 2 : } catch (const DNSMessageBADVERS& dmfe) {
663 [ - + ]: 1 : PyErr_SetString(po_DNSMessageBADVERS, dmfe.what());
664 : : return (NULL);
665 : 16 : } catch (const MessageTooShort& mts) {
666 [ - + ]: 8 : PyErr_SetString(po_MessageTooShort, mts.what());
667 : : return (NULL);
668 : 2 : } catch (const InvalidBufferPosition& ex) {
669 [ - + ]: 1 : PyErr_SetString(po_DNSMessageFORMERR, ex.what());
670 : : return (NULL);
671 : 0 : } catch (const exception& ex) {
672 : : const string ex_what =
673 [ # # ][ # # ]: 0 : "Error in Message.from_wire: " + string(ex.what());
674 [ # # ]: 0 : PyErr_SetString(PyExc_RuntimeError, ex_what.c_str());
675 : : return (NULL);
676 [ + + + + : 18 : } catch (...) {
+ - - ]
677 : : PyErr_SetString(PyExc_RuntimeError,
678 [ # # ]: 0 : "Unexpected exception in Message.from_wire");
679 : : return (NULL);
680 : : }
681 : : }
682 : :
683 : : PyErr_SetString(PyExc_TypeError,
684 : : "from_wire() arguments must be a byte object and "
685 : 1 : "(optional) parse options");
686 : 374 : return (NULL);
687 : : }
688 : :
689 : : } // end of unnamed namespace
690 : :
691 : : namespace isc {
692 : : namespace dns {
693 : : namespace python {
694 : :
695 : : //
696 : : // Declaration of the custom exceptions
697 : : // Initialization and addition of these go in the initModulePart
698 : : // function in pydnspp.cc
699 : : //
700 : : PyObject* po_MessageTooShort;
701 : : PyObject* po_InvalidMessageSection;
702 : : PyObject* po_InvalidMessageOperation;
703 : : PyObject* po_InvalidMessageUDPSize;
704 : :
705 : : // This defines the complete type for reflection in python and
706 : : // parsing of PyObject* to s_Message
707 : : // Most of the functions are not actually implemented and NULL here.
708 : : PyTypeObject message_type = {
709 : : PyVarObject_HEAD_INIT(NULL, 0)
710 : : "pydnspp.Message",
711 : : sizeof(s_Message), // tp_basicsize
712 : : 0, // tp_itemsize
713 : : (destructor)Message_destroy, // tp_dealloc
714 : : NULL, // tp_print
715 : : NULL, // tp_getattr
716 : : NULL, // tp_setattr
717 : : NULL, // tp_reserved
718 : : NULL, // tp_repr
719 : : NULL, // tp_as_number
720 : : NULL, // tp_as_sequence
721 : : NULL, // tp_as_mapping
722 : : NULL, // tp_hash
723 : : NULL, // tp_call
724 : : Message_str, // tp_str
725 : : NULL, // tp_getattro
726 : : NULL, // tp_setattro
727 : : NULL, // tp_as_buffer
728 : : Py_TPFLAGS_DEFAULT, // tp_flags
729 : : "The Message class encapsulates a standard DNS message.",
730 : : NULL, // tp_traverse
731 : : NULL, // tp_clear
732 : : NULL, // tp_richcompare
733 : : 0, // tp_weaklistoffset
734 : : NULL, // tp_iter
735 : : NULL, // tp_iternext
736 : : Message_methods, // tp_methods
737 : : NULL, // tp_members
738 : : NULL, // tp_getset
739 : : NULL, // tp_base
740 : : NULL, // tp_dict
741 : : NULL, // tp_descr_get
742 : : NULL, // tp_descr_set
743 : : 0, // tp_dictoffset
744 : : (initproc)Message_init, // tp_init
745 : : NULL, // tp_alloc
746 : : PyType_GenericNew, // tp_new
747 : : NULL, // tp_free
748 : : NULL, // tp_is_gc
749 : : NULL, // tp_bases
750 : : NULL, // tp_mro
751 : : NULL, // tp_cache
752 : : NULL, // tp_subclasses
753 : : NULL, // tp_weaklist
754 : : NULL, // tp_del
755 : : 0 // tp_version_tag
756 : : };
757 : :
758 : : } // end python namespace
759 : : } // end dns namespace
760 : 123 : } // end isc namespace
|