LCOV - code coverage report
Current view: top level - python/isc/util/cio - socketsessionforwarder_python.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 66 84 78.6 %
Date: 2012-05-15 Functions: 8 10 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 41 98 41.8 %

           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                 :            : // Enable this if you use s# variants with PyArg_ParseTuple(), see
      16                 :            : // http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
      17                 :            : //#define PY_SSIZE_T_CLEAN
      18                 :            : 
      19                 :            : // Python.h needs to be placed at the head of the program file, see:
      20                 :            : // http://docs.python.org/py3k/extending/extending.html#a-simple-example
      21                 :            : #include <Python.h>
      22                 :            : 
      23                 :            : #include <sys/types.h>
      24                 :            : #include <sys/socket.h>
      25                 :            : #include <netdb.h>
      26                 :            : 
      27                 :            : #include <string>
      28                 :            : #include <stdexcept>
      29                 :            : 
      30                 :            : #include <boost/lexical_cast.hpp>
      31                 :            : 
      32                 :            : #include <exceptions/exceptions.h>
      33                 :            : 
      34                 :            : #include <util/io/sockaddr_util.h>
      35                 :            : #include <util/io/socketsession.h>
      36                 :            : #include <util/python/pycppwrapper_util.h>
      37                 :            : 
      38                 :            : #include "socketsession_python.h"
      39                 :            : #include "socketsessionforwarder_python.h"
      40                 :            : 
      41                 :            : using namespace std;
      42                 :            : using namespace isc::util::python;
      43                 :            : using namespace isc::util::io;
      44                 :            : using namespace isc::util::io::internal;
      45                 :            : using namespace isc::util::io::python;
      46                 :            : using boost::lexical_cast;
      47                 :            : 
      48                 :            : // Trivial constructor.
      49                 :          0 : s_SocketSessionForwarder::s_SocketSessionForwarder() : cppobj(NULL) {
      50                 :          0 : }
      51                 :            : 
      52                 :            : // Import pydoc text
      53                 :            : #include "socketsessionforwarder_inc.cc"
      54                 :            : 
      55                 :            : // See python/isc/log/log.cc for the use of namespace
      56                 :            : namespace clang_unnamed_namespace_workaround {
      57                 :            : // Internal exception class thrown when address parsing fails
      58                 :          3 : class AddressParseError: public isc::Exception {
      59                 :            : public:
      60                 :          3 :     AddressParseError(const char *file, size_t line, const char *what):
      61                 :          3 :         isc::Exception(file, line, what) {}
      62                 :            : };
      63                 :            : }
      64                 :            : using namespace clang_unnamed_namespace_workaround;
      65                 :            : 
      66                 :            : namespace {
      67                 :            : 
      68                 :            : int
      69                 :          7 : SocketSessionForwarder_init(PyObject* po_self, PyObject* args, PyObject*) {
      70                 :            :     s_SocketSessionForwarder* self =
      71                 :          7 :         static_cast<s_SocketSessionForwarder*>(po_self);
      72                 :            :     try {
      73                 :            :         const char* unix_file;
      74 [ +  - ][ +  + ]:          7 :         if (PyArg_ParseTuple(args, "s", &unix_file)) {
      75 [ +  - ][ +  - ]:          7 :             self->cppobj = new SocketSessionForwarder(unix_file);
                 [ +  - ]
      76                 :            :             return (0);
      77                 :            :         }
      78                 :          0 :     } catch (const exception& ex) {
      79                 :            :         const string ex_what =
      80                 :            :             "Failed to construct SocketSessionForwarder object: " +
      81 [ #  # ][ #  # ]:          0 :             string(ex.what());
      82         [ #  # ]:          0 :         PyErr_SetString(po_SocketSessionError, ex_what.c_str());
      83                 :            :         return (-1);
      84         [ #  # ]:          0 :     } catch (...) {
      85         [ #  # ]:          0 :         PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
      86                 :            :         return (-1);
      87                 :            :     }
      88                 :            : 
      89                 :            :     return (-1);
      90                 :            : }
      91                 :            : 
      92                 :            : void
      93                 :          7 : SocketSessionForwarder_destroy(PyObject* po_self) {
      94                 :            :     s_SocketSessionForwarder* self =
      95                 :          7 :         static_cast<s_SocketSessionForwarder*>(po_self);
      96         [ +  + ]:          7 :     delete self->cppobj;
      97                 :          7 :     self->cppobj = NULL;
      98                 :          7 :     Py_TYPE(self)->tp_free(self);
      99                 :          7 : }
     100                 :            : 
     101                 :            : // Convert a Python socket address object to an addrinfo structure by
     102                 :            : // getaddrinfo.
     103                 :            : void
     104                 :         41 : parsePySocketAddress(PyObject* obj, int type, int protocol,
     105                 :            :                      struct sockaddr_storage* ss)
     106                 :            : {
     107                 :            :     struct addrinfo hints;
     108                 :            :     memset(&hints, 0, sizeof(hints));
     109                 :         41 :     hints.ai_socktype = type;
     110                 :         41 :     hints.ai_protocol = protocol;
     111                 :         41 :     hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
     112                 :            : 
     113                 :            :     const char* addr;
     114                 :            :     int port, flowinfo, scopeid;
     115                 :            :     struct addrinfo *res;
     116         [ +  + ]:         41 :     if (PyArg_ParseTuple(obj, "si", &addr, &port)) {
     117                 :            :         // Possibly an IPv4 address.
     118                 :         28 :         hints.ai_family = AF_INET;
     119                 :            :         const int error = getaddrinfo(addr,
     120                 :         28 :                                       lexical_cast<string>(port).c_str(),
     121         [ +  - ]:         28 :                                       &hints, &res);
     122         [ +  + ]:         28 :         if (error == 0) {
     123         [ -  + ]:         26 :             assert(res->ai_addrlen <= sizeof(*ss));
     124                 :         26 :             memcpy(ss, res->ai_addr, res->ai_addrlen);
     125                 :            :             return;
     126                 :            :         }
     127 [ +  - ][ +  - ]:          4 :         isc_throw(AddressParseError, "Invalid or unsupported socket address: "
                 [ +  - ]
     128                 :            :                   << gai_strerror(error));
     129                 :            :     }
     130                 :         13 :     PyErr_Clear();
     131         [ +  + ]:         13 :     if (PyArg_ParseTuple(obj, "siii", &addr, &port, &flowinfo, &scopeid)) {
     132                 :            :         // Possibly an IPv6 address.  We ignore flowinfo.
     133                 :         12 :         hints.ai_family = AF_INET6;
     134                 :            :         const int error = getaddrinfo(addr,
     135                 :         12 :                                       lexical_cast<string>(port).c_str(),
     136         [ +  - ]:         12 :                                       &hints, &res);
     137         [ +  - ]:         12 :         if (error == 0) {
     138         [ -  + ]:         12 :             assert(res->ai_addrlen <= sizeof(*ss));
     139                 :         12 :             memcpy(ss, res->ai_addr, res->ai_addrlen);
     140                 :         12 :             void* p = ss;
     141                 :         12 :             static_cast<struct sockaddr_in6*>(p)->sin6_scope_id = scopeid;
     142                 :         12 :             return;
     143                 :            :         }
     144 [ #  # ][ #  # ]:          0 :         isc_throw(AddressParseError, "Invalid or unsupported socket address: "
                 [ #  # ]
     145                 :            :                   << gai_strerror(error));
     146                 :            :     }
     147                 :          1 :     PyErr_Clear();
     148 [ +  - ][ +  - ]:         40 :     isc_throw(AddressParseError, "Invalid or unsupported socket address, must "
     149                 :            :               "be AF_INET or AF_INET6 socket address.");
     150                 :            : }
     151                 :            : 
     152                 :            : PyObject*
     153                 :          3 : SocketSessionForwarder_connectToReceiver(PyObject* po_self, PyObject*) {
     154                 :            :     s_SocketSessionForwarder* const self =
     155                 :          3 :         static_cast<s_SocketSessionForwarder*>(po_self);
     156                 :            : 
     157                 :            :     try {
     158         [ +  - ]:          3 :         self->cppobj->connectToReceiver();
     159                 :          3 :         Py_RETURN_NONE;
     160                 :          0 :     } catch (const isc::BadValue& ex) {
     161         [ #  # ]:          0 :         PyErr_SetString(PyExc_TypeError, ex.what());
     162                 :            :         return (NULL);
     163                 :          0 :     } catch (const SocketSessionError& ex) {
     164         [ #  # ]:          0 :         PyErr_SetString(po_SocketSessionError, ex.what());
     165                 :            :         return (NULL);
     166                 :          0 :     } catch (const exception& ex) {
     167                 :            :         const string ex_what =
     168                 :            :             "Unexpected failure in connecting to receiver: " +
     169 [ #  # ][ #  # ]:          0 :             string(ex.what());
     170         [ #  # ]:          0 :         PyErr_SetString(PyExc_SystemError, ex_what.c_str());
     171                 :            :         return (NULL);
     172   [ #  #  #  # ]:          0 :     } catch (...) {
     173         [ #  # ]:          0 :         PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
     174                 :            :         return (NULL);
     175                 :            :     }
     176                 :            : }
     177                 :            : 
     178                 :            : PyObject*
     179                 :         25 : SocketSessionForwarder_push(PyObject* po_self, PyObject* args) {
     180                 :            :     s_SocketSessionForwarder* const self =
     181                 :         25 :         static_cast<s_SocketSessionForwarder*>(po_self);
     182                 :            : 
     183                 :            :     try {
     184                 :            :         int fd, family, type, protocol;
     185                 :            :         PyObject* po_local_end;
     186                 :            :         PyObject* po_remote_end;
     187                 :            :         Py_buffer py_buf;
     188                 :            : 
     189         [ +  + ]:         25 :         if (!PyArg_ParseTuple(args, "iiiiOOy*", &fd, &family, &type, &protocol,
     190         [ +  - ]:         25 :                               &po_local_end, &po_remote_end, &py_buf)) {
     191                 :            :             return (NULL);
     192                 :            :         }
     193                 :            :         struct sockaddr_storage ss_local, ss_remote;
     194         [ +  + ]:         22 :         parsePySocketAddress(po_local_end, type, protocol, &ss_local);
     195         [ +  - ]:         19 :         parsePySocketAddress(po_remote_end, type, protocol, &ss_remote);
     196                 :            :         self->cppobj->push(fd, family, type, protocol,
     197                 :            :                            *convertSockAddr(&ss_local),
     198                 :         19 :                            *convertSockAddr(&ss_remote),
     199         [ +  + ]:         19 :                            py_buf.buf, py_buf.len);
     200                 :         25 :         Py_RETURN_NONE;
     201                 :          6 :     } catch (const AddressParseError& ex) {
     202         [ -  + ]:          3 :         PyErr_SetString(PyExc_TypeError, ex.what());
     203                 :            :         return (NULL);
     204                 :         10 :     } catch (const isc::BadValue& ex) {
     205         [ -  + ]:          5 :         PyErr_SetString(PyExc_TypeError, ex.what());
     206                 :            :         return (NULL);
     207                 :          4 :     } catch (const SocketSessionError& ex) {
     208         [ -  + ]:          2 :         PyErr_SetString(po_SocketSessionError, ex.what());
     209                 :            :         return (NULL);
     210   [ +  +  +  - ]:         10 :     } catch (...) {
     211         [ #  # ]:          0 :         PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
     212                 :            :         return (NULL);
     213                 :            :     } 
     214                 :            : }
     215                 :            : 
     216                 :            : // This list contains the actual set of functions we have in
     217                 :            : // python. Each entry has
     218                 :            : // 1. Python method name
     219                 :            : // 2. Our static function here
     220                 :            : // 3. Argument type
     221                 :            : // 4. Documentation
     222                 :            : PyMethodDef SocketSessionForwarder_methods[] = {
     223                 :            :     { "push", SocketSessionForwarder_push, METH_VARARGS,
     224                 :            :       SocketSessionForwarder_push_doc },
     225                 :            :     { "connect_to_receiver", SocketSessionForwarder_connectToReceiver,
     226                 :            :       METH_NOARGS, SocketSessionForwarder_connectToReceiver_doc },
     227                 :            :     { NULL, NULL, 0, NULL }
     228                 :            : };
     229                 :            : } // end of unnamed namespace
     230                 :            : 
     231                 :            : namespace isc {
     232                 :            : namespace util {
     233                 :            : namespace io {
     234                 :            : namespace python {
     235                 :            : // This defines the complete type for reflection in python and
     236                 :            : // parsing of PyObject* to s_SocketSessionForwarder
     237                 :            : // Most of the functions are not actually implemented and NULL here.
     238                 :            : PyTypeObject socketsessionforwarder_type = {
     239                 :            :     PyVarObject_HEAD_INIT(NULL, 0)
     240                 :            :     "isc.util.cio.SocketSessionForwarder",
     241                 :            :     sizeof(s_SocketSessionForwarder),                 // tp_basicsize
     242                 :            :     0,                                  // tp_itemsize
     243                 :            :     SocketSessionForwarder_destroy,                 // tp_dealloc
     244                 :            :     NULL,                               // tp_print
     245                 :            :     NULL,                               // tp_getattr
     246                 :            :     NULL,                               // tp_setattr
     247                 :            :     NULL,                               // tp_reserved
     248                 :            :     NULL,                               // tp_repr
     249                 :            :     NULL,                               // tp_as_number
     250                 :            :     NULL,                               // tp_as_sequence
     251                 :            :     NULL,                               // tp_as_mapping
     252                 :            :     NULL,                               // tp_hash
     253                 :            :     NULL,                               // tp_call
     254                 :            :     NULL,                               // tp_str
     255                 :            :     NULL,                               // tp_getattro
     256                 :            :     NULL,                               // tp_setattro
     257                 :            :     NULL,                               // tp_as_buffer
     258                 :            :     Py_TPFLAGS_DEFAULT,                 // tp_flags
     259                 :            :     SocketSessionForwarder_doc,
     260                 :            :     NULL,                               // tp_traverse
     261                 :            :     NULL,                               // tp_clear
     262                 :            :     NULL,                               // tp_richcompare
     263                 :            :     0,                                  // tp_weaklistoffset
     264                 :            :     NULL,                               // tp_iter
     265                 :            :     NULL,                               // tp_iternext
     266                 :            :     SocketSessionForwarder_methods,                   // tp_methods
     267                 :            :     NULL,                               // tp_members
     268                 :            :     NULL,                               // tp_getset
     269                 :            :     NULL,                               // tp_base
     270                 :            :     NULL,                               // tp_dict
     271                 :            :     NULL,                               // tp_descr_get
     272                 :            :     NULL,                               // tp_descr_set
     273                 :            :     0,                                  // tp_dictoffset
     274                 :            :     SocketSessionForwarder_init,        // tp_init
     275                 :            :     NULL,                               // tp_alloc
     276                 :            :     PyType_GenericNew,                  // tp_new
     277                 :            :     NULL,                               // tp_free
     278                 :            :     NULL,                               // tp_is_gc
     279                 :            :     NULL,                               // tp_bases
     280                 :            :     NULL,                               // tp_mro
     281                 :            :     NULL,                               // tp_cache
     282                 :            :     NULL,                               // tp_subclasses
     283                 :            :     NULL,                               // tp_weaklist
     284                 :            :     NULL,                               // tp_del
     285                 :            :     0                                   // tp_version_tag
     286                 :            : };
     287                 :            : 
     288                 :            : // Module Initialization, all statics are initialized here
     289                 :            : bool
     290                 :          2 : initModulePart_SocketSessionForwarder(PyObject* mod) {
     291                 :            :     // We initialize the static description object with PyType_Ready(),
     292                 :            :     // then add it to the module. This is not just a check! (leaving
     293                 :            :     // this out results in segmentation faults)
     294         [ +  - ]:          2 :     if (PyType_Ready(&socketsessionforwarder_type) < 0) {
     295                 :            :         return (false);
     296                 :            :     }
     297                 :          2 :     void* p = &socketsessionforwarder_type;
     298         [ +  - ]:          2 :     if (PyModule_AddObject(mod, "SocketSessionForwarder",
     299                 :          2 :                            static_cast<PyObject*>(p)) < 0) {
     300                 :            :         return (false);
     301                 :            :     }
     302                 :          2 :     Py_INCREF(&socketsessionforwarder_type);
     303                 :            : 
     304                 :          2 :     return (true);
     305                 :            : }
     306                 :            : } // namespace python
     307                 :            : } // namespace io
     308                 :            : } // namespace util
     309                 :        160 : } // namespace isc

Generated by: LCOV version 1.9