updater_python.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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/zone.h>
  28. #include <dns/python/name_python.h>
  29. #include <dns/python/rrset_python.h>
  30. #include <dns/python/rrclass_python.h>
  31. #include <dns/python/rrtype_python.h>
  32. #include "datasrc.h"
  33. #include "updater_python.h"
  34. #include "updater_inc.cc"
  35. #include "finder_inc.cc"
  36. using namespace std;
  37. using namespace isc::util::python;
  38. using namespace isc::datasrc;
  39. using namespace isc::datasrc::python;
  40. //
  41. // Definition of the classes
  42. //
  43. // For each class, we need a struct, a helper functions (init, destroy,
  44. // and static wrappers around the methods we export), a list of methods,
  45. // and a type description
  46. //
  47. // Zone Updater
  48. //
  49. // Trivial constructor.
  50. s_ZoneUpdater::s_ZoneUpdater() : cppobj(ZoneUpdaterPtr()) {
  51. }
  52. namespace {
  53. // Shortcut type which would be convenient for adding class variables safely.
  54. typedef CPPPyObjectContainer<s_ZoneUpdater, ZoneUpdater> ZoneUpdaterContainer;
  55. //
  56. // We declare the functions here, the definitions are below
  57. // the type definition of the object, since both can use the other
  58. //
  59. // General creation and destruction
  60. int
  61. ZoneUpdater_init(s_ZoneUpdater* self, PyObject* args) {
  62. // can't be called directly
  63. PyErr_SetString(PyExc_TypeError,
  64. "ZoneUpdater cannot be constructed directly");
  65. return (-1);
  66. }
  67. // This is a template of typical code logic of python object destructor.
  68. // In many cases you can use it without modification, but check that carefully.
  69. void
  70. ZoneUpdater_destroy(s_ZoneUpdater* const self) {
  71. // cppobj is a shared ptr, but to make sure things are not destroyed in
  72. // the wrong order, we reset it here.
  73. self->cppobj.reset();
  74. Py_TYPE(self)->tp_free(self);
  75. }
  76. // These are the functions we export
  77. //
  78. PyObject* ZoneUpdater_addRRset(PyObject* po_self, PyObject* args) {
  79. s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
  80. PyObject* rrset_obj;
  81. if (PyArg_ParseTuple(args, "O!", &isc::dns::python::rrset_type, &rrset_obj)) {
  82. try {
  83. self->cppobj->addRRset(isc::dns::python::PyRRset_ToRRset(rrset_obj));
  84. Py_RETURN_NONE;
  85. } catch (const DataSourceError& dse) {
  86. PyErr_SetString(getDataSourceException("Error"), dse.what());
  87. return (NULL);
  88. } catch (const std::exception& exc) {
  89. PyErr_SetString(getDataSourceException("Error"), exc.what());
  90. return (NULL);
  91. }
  92. } else {
  93. return (NULL);
  94. }
  95. }
  96. PyObject* ZoneUpdater_deleteRRset(PyObject* po_self, PyObject* args) {
  97. s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
  98. PyObject* rrset_obj;
  99. if (PyArg_ParseTuple(args, "O!", &isc::dns::python::rrset_type, &rrset_obj)) {
  100. try {
  101. self->cppobj->deleteRRset(isc::dns::python::PyRRset_ToRRset(rrset_obj));
  102. Py_RETURN_NONE;
  103. } catch (const DataSourceError& dse) {
  104. PyErr_SetString(getDataSourceException("Error"), dse.what());
  105. return (NULL);
  106. } catch (const std::exception& exc) {
  107. PyErr_SetString(getDataSourceException("Error"), exc.what());
  108. return (NULL);
  109. }
  110. } else {
  111. return (NULL);
  112. }
  113. }
  114. PyObject* ZoneUpdater_commit(PyObject* po_self, PyObject*) {
  115. s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
  116. try {
  117. self->cppobj->commit();
  118. Py_RETURN_NONE;
  119. } catch (const DataSourceError& dse) {
  120. PyErr_SetString(getDataSourceException("Error"), dse.what());
  121. return (NULL);
  122. } catch (const std::exception& exc) {
  123. PyErr_SetString(getDataSourceException("Error"), exc.what());
  124. return (NULL);
  125. }
  126. }
  127. // These are the functions we export
  128. //
  129. PyObject* ZoneUpdater_getClass(PyObject* po_self, PyObject*) {
  130. s_ZoneUpdater* self = static_cast<s_ZoneUpdater*>(po_self);
  131. try {
  132. return (isc::dns::python::createRRClassObject(self->cppobj->getFinder().getClass()));
  133. } catch (const std::exception& exc) {
  134. PyErr_SetString(getDataSourceException("Error"), exc.what());
  135. return (NULL);
  136. }
  137. }
  138. PyObject* ZoneUpdater_getOrigin(PyObject* po_self, PyObject*) {
  139. s_ZoneUpdater* self = static_cast<s_ZoneUpdater*>(po_self);
  140. try {
  141. return (isc::dns::python::createNameObject(self->cppobj->getFinder().getOrigin()));
  142. } catch (const std::exception& exc) {
  143. PyErr_SetString(getDataSourceException("Error"), exc.what());
  144. return (NULL);
  145. }
  146. }
  147. PyObject* ZoneUpdater_find(PyObject* po_self, PyObject* args) {
  148. s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
  149. PyObject *name;
  150. PyObject *rrtype;
  151. PyObject *target;
  152. int options_int;
  153. if (PyArg_ParseTuple(args, "O!O!OI", &isc::dns::python::name_type, &name,
  154. &isc::dns::python::rrtype_type, &rrtype,
  155. &target, &options_int)) {
  156. try {
  157. ZoneFinder::FindOptions options = static_cast<ZoneFinder::FindOptions>(options_int);
  158. ZoneFinder::FindResult find_result(
  159. self->cppobj->getFinder().find(isc::dns::python::PyName_ToName(name),
  160. isc::dns::python::PyRRType_ToRRType(rrtype),
  161. NULL,
  162. options
  163. ));
  164. ZoneFinder::Result r = find_result.code;
  165. isc::dns::ConstRRsetPtr rrsp = find_result.rrset;
  166. if (rrsp) {
  167. // Use N instead of O so the refcount isn't increased twice
  168. return Py_BuildValue("IN", r, isc::dns::python::createRRsetObject(*rrsp));
  169. } else {
  170. return Py_BuildValue("IO", r, Py_None);
  171. }
  172. } catch (const DataSourceError& dse) {
  173. PyErr_SetString(getDataSourceException("Error"), dse.what());
  174. return (NULL);
  175. } catch (const std::exception& exc) {
  176. PyErr_SetString(getDataSourceException("Error"), exc.what());
  177. return (NULL);
  178. }
  179. } else {
  180. return (NULL);
  181. }
  182. return Py_BuildValue("I", 1);
  183. }
  184. // This list contains the actual set of functions we have in
  185. // python. Each entry has
  186. // 1. Python method name
  187. // 2. Our static function here
  188. // 3. Argument type
  189. // 4. Documentation
  190. PyMethodDef ZoneUpdater_methods[] = {
  191. { "add_rrset", reinterpret_cast<PyCFunction>(ZoneUpdater_addRRset), METH_VARARGS,
  192. ZoneUpdater_addRRset_doc },
  193. { "delete_rrset", reinterpret_cast<PyCFunction>(ZoneUpdater_deleteRRset), METH_VARARGS,
  194. ZoneUpdater_deleteRRset_doc },
  195. { "commit", reinterpret_cast<PyCFunction>(ZoneUpdater_commit), METH_NOARGS,
  196. ZoneUpdater_commit_doc },
  197. // Instead of a getFinder, we implement the finder functionality directly
  198. // This is because ZoneFinder is non-copyable, and we should not create
  199. // a ZoneFinder object from a reference only (which is what is returned
  200. // by getFinder(). Apart from that
  201. { "get_origin", reinterpret_cast<PyCFunction>(ZoneUpdater_getOrigin), METH_NOARGS,
  202. ZoneFinder_getOrigin_doc },
  203. { "get_class", reinterpret_cast<PyCFunction>(ZoneUpdater_getClass), METH_NOARGS,
  204. ZoneFinder_getClass_doc },
  205. { "find", reinterpret_cast<PyCFunction>(ZoneUpdater_find), METH_VARARGS,
  206. ZoneFinder_find_doc },
  207. { NULL, NULL, 0, NULL }
  208. };
  209. } // end of unnamed namespace
  210. namespace isc {
  211. namespace datasrc {
  212. namespace python {
  213. PyTypeObject zoneupdater_type = {
  214. PyVarObject_HEAD_INIT(NULL, 0)
  215. "datasrc.ZoneUpdater",
  216. sizeof(s_ZoneUpdater), // tp_basicsize
  217. 0, // tp_itemsize
  218. reinterpret_cast<destructor>(ZoneUpdater_destroy), // tp_dealloc
  219. NULL, // tp_print
  220. NULL, // tp_getattr
  221. NULL, // tp_setattr
  222. NULL, // tp_reserved
  223. NULL, // tp_repr
  224. NULL, // tp_as_number
  225. NULL, // tp_as_sequence
  226. NULL, // tp_as_mapping
  227. NULL, // tp_hash
  228. NULL, // tp_call
  229. NULL, // tp_str
  230. NULL, // tp_getattro
  231. NULL, // tp_setattro
  232. NULL, // tp_as_buffer
  233. Py_TPFLAGS_DEFAULT, // tp_flags
  234. ZoneUpdater_doc,
  235. NULL, // tp_traverse
  236. NULL, // tp_clear
  237. NULL, // tp_richcompare
  238. 0, // tp_weaklistoffset
  239. NULL, // tp_iter
  240. NULL, // tp_iternext
  241. ZoneUpdater_methods, // tp_methods
  242. NULL, // tp_members
  243. NULL, // tp_getset
  244. NULL, // tp_base
  245. NULL, // tp_dict
  246. NULL, // tp_descr_get
  247. NULL, // tp_descr_set
  248. 0, // tp_dictoffset
  249. reinterpret_cast<initproc>(ZoneUpdater_init),// tp_init
  250. NULL, // tp_alloc
  251. PyType_GenericNew, // tp_new
  252. NULL, // tp_free
  253. NULL, // tp_is_gc
  254. NULL, // tp_bases
  255. NULL, // tp_mro
  256. NULL, // tp_cache
  257. NULL, // tp_subclasses
  258. NULL, // tp_weaklist
  259. NULL, // tp_del
  260. 0 // tp_version_tag
  261. };
  262. // Module Initialization, all statics are initialized here
  263. bool
  264. initModulePart_ZoneUpdater(PyObject* mod) {
  265. // We initialize the static description object with PyType_Ready(),
  266. // then add it to the module. This is not just a check! (leaving
  267. // this out results in segmentation faults)
  268. if (PyType_Ready(&zoneupdater_type) < 0) {
  269. return (false);
  270. }
  271. void* zip = &zoneupdater_type;
  272. if (PyModule_AddObject(mod, "ZoneUpdater", static_cast<PyObject*>(zip)) < 0) {
  273. return (false);
  274. }
  275. Py_INCREF(&zoneupdater_type);
  276. return (true);
  277. }
  278. PyObject*
  279. createZoneUpdaterObject(isc::datasrc::ZoneUpdaterPtr source) {
  280. s_ZoneUpdater* py_zi = static_cast<s_ZoneUpdater*>(
  281. zoneupdater_type.tp_alloc(&zoneupdater_type, 0));
  282. if (py_zi != NULL) {
  283. py_zi->cppobj = source;
  284. }
  285. return (py_zi);
  286. }
  287. } // namespace python
  288. } // namespace datasrc
  289. } // namespace isc