client_python.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. // Enable this if you use s# variants with PyArg_ParseTuple(), see
  15. // http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
  16. //#define PY_SSIZE_T_CLEAN
  17. // Python.h needs to be placed at the head of the program file, see:
  18. // http://docs.python.org/py3k/extending/extending.html#a-simple-example
  19. #include <Python.h>
  20. #include <string>
  21. #include <stdexcept>
  22. #include <util/python/pycppwrapper_util.h>
  23. #include <datasrc/client.h>
  24. #include <datasrc/database.h>
  25. #include <datasrc/data_source.h>
  26. #include <datasrc/sqlite3_accessor.h>
  27. #include <datasrc/iterator.h>
  28. #include <dns/python/name_python.h>
  29. #include <dns/python/rrset_python.h>
  30. #include <dns/python/pydnspp_common.h>
  31. #include "datasrc.h"
  32. #include "client_python.h"
  33. #include "finder_python.h"
  34. #include "iterator_python.h"
  35. #include "updater_python.h"
  36. #include "client_inc.cc"
  37. using namespace std;
  38. using namespace isc::util::python;
  39. using namespace isc::datasrc;
  40. using namespace isc::datasrc::python;
  41. //
  42. // Definition of the classes
  43. //
  44. // For each class, we need a struct, a helper functions (init, destroy,
  45. // and static wrappers around the methods we export), a list of methods,
  46. // and a type description
  47. //
  48. // DataSourceClient
  49. //
  50. // Trivial constructor.
  51. s_DataSourceClient::s_DataSourceClient() : cppobj(NULL) {
  52. }
  53. namespace {
  54. // Shortcut type which would be convenient for adding class variables safely.
  55. typedef CPPPyObjectContainer<s_DataSourceClient, DataSourceClient>
  56. DataSourceClientContainer;
  57. //
  58. // We declare the functions here, the definitions are below
  59. // the type definition of the object, since both can use the other
  60. //
  61. // General creation and destruction
  62. int DataSourceClient_init(s_DataSourceClient* self, PyObject* args);
  63. void DataSourceClient_destroy(s_DataSourceClient* self);
  64. // These are the functions we export
  65. //
  66. PyObject*
  67. DataSourceClient_findZone(PyObject* po_self, PyObject* args) {
  68. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  69. PyObject *name;
  70. if (PyArg_ParseTuple(args, "O!", &isc::dns::python::name_type, &name)) {
  71. try {
  72. DataSourceClient::FindResult find_result(
  73. self->cppobj->findZone(isc::dns::python::PyName_ToName(name)));
  74. result::Result r = find_result.code;
  75. ZoneFinderPtr zfp = find_result.zone_finder;
  76. return Py_BuildValue("IO", r, createZoneFinderObject(zfp));
  77. } catch (const std::exception& exc) {
  78. PyErr_SetString(getDataSourceException("Error"), exc.what());
  79. return (NULL);
  80. }
  81. } else {
  82. return (NULL);
  83. }
  84. }
  85. PyObject*
  86. DataSourceClient_getIterator(PyObject* po_self, PyObject* args) {
  87. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  88. PyObject *name_obj;
  89. if (PyArg_ParseTuple(args, "O!", &isc::dns::python::name_type, &name_obj)) {
  90. try {
  91. return (createZoneIteratorObject(self->cppobj->getIterator(isc::dns::python::PyName_ToName(name_obj))));
  92. } catch (const isc::NotImplemented& ne) {
  93. PyErr_SetString(getDataSourceException("NotImplemented"), ne.what());
  94. } catch (const DataSourceError& dse) {
  95. PyErr_SetString(getDataSourceException("Error"), dse.what());
  96. } catch (const std::exception& exc) {
  97. PyErr_SetString(getDataSourceException("Error"), exc.what());
  98. return (NULL);
  99. }
  100. } else {
  101. return (NULL);
  102. }
  103. }
  104. PyObject*
  105. DataSourceClient_getUpdater(PyObject* po_self, PyObject* args) {
  106. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  107. PyObject *name_obj;
  108. PyObject *replace_obj;
  109. if (PyArg_ParseTuple(args, "O!O", &isc::dns::python::name_type, &name_obj, &replace_obj) && PyBool_Check(replace_obj)) {
  110. bool replace = (replace_obj != Py_False);
  111. try {
  112. return (createZoneUpdaterObject(self->cppobj->getUpdater(isc::dns::python::PyName_ToName(name_obj), replace)));
  113. } catch (const isc::NotImplemented& ne) {
  114. PyErr_SetString(getDataSourceException("NotImplemented"), ne.what());
  115. } catch (const DataSourceError& dse) {
  116. PyErr_SetString(getDataSourceException("Error"), dse.what());
  117. } catch (const std::exception& exc) {
  118. PyErr_SetString(getDataSourceException("Error"), exc.what());
  119. return (NULL);
  120. }
  121. } else {
  122. return (NULL);
  123. }
  124. }
  125. // These are the functions we export
  126. // This list contains the actual set of functions we have in
  127. // python. Each entry has
  128. // 1. Python method name
  129. // 2. Our static function here
  130. // 3. Argument type
  131. // 4. Documentation
  132. PyMethodDef DataSourceClient_methods[] = {
  133. { "find_zone", reinterpret_cast<PyCFunction>(DataSourceClient_findZone), METH_VARARGS,
  134. DataSourceClient_findZone_doc },
  135. { "get_iterator", reinterpret_cast<PyCFunction>(DataSourceClient_getIterator), METH_VARARGS,
  136. DataSourceClient_getIterator_doc },
  137. { "get_updater", reinterpret_cast<PyCFunction>(DataSourceClient_getUpdater), METH_VARARGS,
  138. DataSourceClient_getUpdater_doc },
  139. { NULL, NULL, 0, NULL }
  140. };
  141. // This is a template of typical code logic of python class initialization
  142. // with C++ backend. You'll need to adjust it according to details of the
  143. // actual C++ class.
  144. int
  145. DataSourceClient_init(s_DataSourceClient* self, PyObject* args) {
  146. // TODO: we should use the factory function which hasn't been written
  147. // yet. For now we hardcode the sqlite3 initialization, and pass it one
  148. // string for the database file. (similar to how the 'old direct'
  149. // sqlite3_ds code works)
  150. try {
  151. char* db_file_name;
  152. if (PyArg_ParseTuple(args, "s", &db_file_name)) {
  153. boost::shared_ptr<DatabaseAccessor> sqlite3_accessor(
  154. new SQLite3Accessor(db_file_name, isc::dns::RRClass::IN()));
  155. self->cppobj = new DatabaseClient(isc::dns::RRClass::IN(),
  156. sqlite3_accessor);
  157. return (0);
  158. } else {
  159. return (-1);
  160. }
  161. } catch (const exception& ex) {
  162. const string ex_what = "Failed to construct DataSourceClient object: " +
  163. string(ex.what());
  164. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  165. return (-1);
  166. } catch (...) {
  167. PyErr_SetString(PyExc_RuntimeError,
  168. "Unexpected exception in constructing DataSourceClient");
  169. return (-1);
  170. }
  171. PyErr_SetString(PyExc_TypeError,
  172. "Invalid arguments to DataSourceClient constructor");
  173. return (-1);
  174. }
  175. // This is a template of typical code logic of python object destructor.
  176. // In many cases you can use it without modification, but check that carefully.
  177. void
  178. DataSourceClient_destroy(s_DataSourceClient* const self) {
  179. delete self->cppobj;
  180. self->cppobj = NULL;
  181. Py_TYPE(self)->tp_free(self);
  182. }
  183. } // end anonymous namespace
  184. namespace isc {
  185. namespace datasrc {
  186. namespace python {
  187. // This defines the complete type for reflection in python and
  188. // parsing of PyObject* to s_DataSourceClient
  189. // Most of the functions are not actually implemented and NULL here.
  190. PyTypeObject datasourceclient_type = {
  191. PyVarObject_HEAD_INIT(NULL, 0)
  192. "datasrc.DataSourceClient",
  193. sizeof(s_DataSourceClient), // tp_basicsize
  194. 0, // tp_itemsize
  195. reinterpret_cast<destructor>(DataSourceClient_destroy), // tp_dealloc
  196. NULL, // tp_print
  197. NULL, // tp_getattr
  198. NULL, // tp_setattr
  199. NULL, // tp_reserved
  200. NULL, // tp_repr
  201. NULL, // tp_as_number
  202. NULL, // tp_as_sequence
  203. NULL, // tp_as_mapping
  204. NULL, // tp_hash
  205. NULL, // tp_call
  206. NULL, // tp_str
  207. NULL, // tp_getattro
  208. NULL, // tp_setattro
  209. NULL, // tp_as_buffer
  210. Py_TPFLAGS_DEFAULT, // tp_flags
  211. DataSourceClient_doc,
  212. NULL, // tp_traverse
  213. NULL, // tp_clear
  214. NULL, // tp_richcompare
  215. 0, // tp_weaklistoffset
  216. NULL, // tp_iter
  217. NULL, // tp_iternext
  218. DataSourceClient_methods, // tp_methods
  219. NULL, // tp_members
  220. NULL, // tp_getset
  221. NULL, // tp_base
  222. NULL, // tp_dict
  223. NULL, // tp_descr_get
  224. NULL, // tp_descr_set
  225. 0, // tp_dictoffset
  226. reinterpret_cast<initproc>(DataSourceClient_init), // tp_init
  227. NULL, // tp_alloc
  228. PyType_GenericNew, // tp_new
  229. NULL, // tp_free
  230. NULL, // tp_is_gc
  231. NULL, // tp_bases
  232. NULL, // tp_mro
  233. NULL, // tp_cache
  234. NULL, // tp_subclasses
  235. NULL, // tp_weaklist
  236. NULL, // tp_del
  237. 0 // tp_version_tag
  238. };
  239. // Module Initialization, all statics are initialized here
  240. bool
  241. initModulePart_DataSourceClient(PyObject* mod) {
  242. // We initialize the static description object with PyType_Ready(),
  243. // then add it to the module. This is not just a check! (leaving
  244. // this out results in segmentation faults)
  245. if (PyType_Ready(&datasourceclient_type) < 0) {
  246. return (false);
  247. }
  248. void* dscp = &datasourceclient_type;
  249. if (PyModule_AddObject(mod, "DataSourceClient", static_cast<PyObject*>(dscp)) < 0) {
  250. return (false);
  251. }
  252. Py_INCREF(&datasourceclient_type);
  253. isc::dns::python::addClassVariable(datasourceclient_type, "SUCCESS",
  254. Py_BuildValue("I", result::SUCCESS));
  255. isc::dns::python::addClassVariable(datasourceclient_type, "EXIST",
  256. Py_BuildValue("I", result::EXIST));
  257. isc::dns::python::addClassVariable(datasourceclient_type, "NOTFOUND",
  258. Py_BuildValue("I", result::NOTFOUND));
  259. isc::dns::python::addClassVariable(datasourceclient_type, "PARTIALMATCH",
  260. Py_BuildValue("I", result::PARTIALMATCH));
  261. return (true);
  262. }
  263. } // namespace python
  264. } // namespace datasrc
  265. } // namespace isc