LCOV - code coverage report
Current view: top level - dns/python - message_python.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 205 245 83.7 %
Date: 2012-05-15 Functions: 25 25 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 165 334 49.4 %

           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", &section)) {
     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", &section)) {
     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!", &section, &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

Generated by: LCOV version 1.9