tsig_rdata_python.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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. #include <Python.h>
  15. #include <string>
  16. #include <stdexcept>
  17. #include <util/python/pycppwrapper_util.h>
  18. #include <dns/rdataclass.h>
  19. #include "pydnspp_common.h"
  20. #include "pydnspp_towire.h"
  21. #include "name_python.h"
  22. #include "tsig_rdata_python.h"
  23. using namespace std;
  24. using namespace isc::util::python;
  25. using namespace isc::dns;
  26. using namespace isc::dns::rdata;
  27. using namespace isc::dns::python;
  28. //
  29. // Definition of the classes
  30. //
  31. // For each class, we need a struct, a helper functions (init, destroy,
  32. // and static wrappers around the methods we export), a list of methods,
  33. // and a type description
  34. //
  35. // TSIG RDATA
  36. //
  37. // Trivial constructor.
  38. s_TSIG::s_TSIG() : cppobj(NULL) {
  39. }
  40. namespace {
  41. // Shortcut type which would be convenient for adding class variables safely.
  42. typedef CPPPyObjectContainer<s_TSIG, any::TSIG> TSIGContainer;
  43. //
  44. // We declare the functions here, the definitions are below
  45. // the type definition of the object, since both can use the other
  46. //
  47. // General creation and destruction
  48. int TSIG_init(s_TSIG* self, PyObject* args);
  49. void TSIG_destroy(s_TSIG* self);
  50. // These are the functions we export
  51. // ADD/REMOVE/MODIFY THE FOLLOWING AS APPROPRIATE FOR THE ACTUAL CLASS.
  52. //
  53. PyObject* TSIG_toText(const s_TSIG* const self);
  54. PyObject* TSIG_getAlgorithm(const s_TSIG* const self);
  55. PyObject* TSIG_getTimeSigned(const s_TSIG* const self);
  56. PyObject* TSIG_getFudge(const s_TSIG* const self);
  57. PyObject* TSIG_getOriginalID(const s_TSIG* const self);
  58. PyObject* TSIG_getError(const s_TSIG* const self);
  59. PyObject* TSIG_getMAC(const s_TSIG* const self);
  60. PyObject* TSIG_getOtherData(const s_TSIG* const self);
  61. PyObject* TSIG_str(PyObject* self);
  62. PyObject* TSIG_richcmp(const s_TSIG* const self,
  63. const s_TSIG* const other, int op);
  64. PyObject* TSIG_toWire(const s_TSIG* self, PyObject* args);
  65. // These are the functions we export
  66. // For a minimal support, we don't need them.
  67. // This list contains the actual set of functions we have in
  68. // python. Each entry has
  69. // 1. Python method name
  70. // 2. Our static function here
  71. // 3. Argument type
  72. // 4. Documentation
  73. PyMethodDef TSIG_methods[] = {
  74. { "get_algorithm", reinterpret_cast<PyCFunction>(TSIG_getAlgorithm),
  75. METH_NOARGS,
  76. "Return the algorithm name." },
  77. { "get_timesigned", reinterpret_cast<PyCFunction>(TSIG_getTimeSigned),
  78. METH_NOARGS,
  79. "Return the value of the Time Signed field. "
  80. "The returned value does not exceed 2^48-1."
  81. },
  82. { "get_fudge", reinterpret_cast<PyCFunction>(TSIG_getFudge),
  83. METH_NOARGS,
  84. "Return the value of the Fudge field." },
  85. { "get_original_id", reinterpret_cast<PyCFunction>(TSIG_getOriginalID),
  86. METH_NOARGS,
  87. "Return the value of the Original ID field." },
  88. { "get_error", reinterpret_cast<PyCFunction>(TSIG_getError),
  89. METH_NOARGS,
  90. "Return the value of the Error field." },
  91. { "get_mac", reinterpret_cast<PyCFunction>(TSIG_getMAC),
  92. METH_NOARGS,
  93. "Return the value of the MAC field."
  94. "If it's empty, return None." },
  95. { "get_other_data", reinterpret_cast<PyCFunction>(TSIG_getOtherData),
  96. METH_NOARGS,
  97. "Return the value of the Other Data field."
  98. "If it's empty, return None." },
  99. { "to_text", reinterpret_cast<PyCFunction>(TSIG_toText), METH_NOARGS,
  100. "Returns the text representation" },
  101. { "to_wire", reinterpret_cast<PyCFunction>(TSIG_toWire), METH_VARARGS,
  102. "Converts the TSIG object to wire format.\n"
  103. "The argument can be either a MessageRenderer or an object that "
  104. "implements the sequence interface. If the object is mutable "
  105. "(for instance a bytearray()), the wire data is added in-place.\n"
  106. "If it is not (for instance a bytes() object), a new object is "
  107. "returned" },
  108. { NULL, NULL, 0, NULL }
  109. };
  110. int
  111. TSIG_init(s_TSIG* self, PyObject* args) {
  112. try {
  113. // constructor from string
  114. const char* rdata_str;
  115. if (PyArg_ParseTuple(args, "s", &rdata_str)) {
  116. self->cppobj = new any::TSIG(string(rdata_str));
  117. return (0);
  118. }
  119. } catch (const exception& ex) {
  120. const string ex_what = "Failed to construct TSIG object: " +
  121. string(ex.what());
  122. PyErr_SetString(po_IscException, ex_what.c_str());
  123. return (-1);
  124. } catch (...) {
  125. PyErr_SetString(po_IscException,
  126. "Unexpected exception in constructing TSIG");
  127. return (-1);
  128. }
  129. PyErr_SetString(PyExc_TypeError,
  130. "Invalid arguments to TSIG constructor");
  131. return (-1);
  132. }
  133. void
  134. TSIG_destroy(s_TSIG* const self) {
  135. delete self->cppobj;
  136. self->cppobj = NULL;
  137. Py_TYPE(self)->tp_free(self);
  138. }
  139. PyObject*
  140. TSIG_getAlgorithm(const s_TSIG* const self) {
  141. try {
  142. return (createNameObject(self->cppobj->getAlgorithm()));
  143. } catch (const exception& ex) {
  144. const string ex_what =
  145. "Failed to get TSIG algorithm: " + string(ex.what());
  146. PyErr_SetString(po_IscException, ex_what.c_str());
  147. } catch (...) {
  148. PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
  149. "getting TSIG algorithm");
  150. }
  151. return (NULL);
  152. }
  153. PyObject*
  154. TSIG_getTimeSigned(const s_TSIG* const self) {
  155. return (Py_BuildValue("K", self->cppobj->getTimeSigned()));
  156. }
  157. PyObject*
  158. TSIG_getFudge(const s_TSIG* const self) {
  159. return (Py_BuildValue("H", self->cppobj->getFudge()));
  160. }
  161. PyObject*
  162. TSIG_getOriginalID(const s_TSIG* const self) {
  163. return (Py_BuildValue("H", self->cppobj->getOriginalID()));
  164. }
  165. PyObject*
  166. TSIG_getError(const s_TSIG* const self) {
  167. return (Py_BuildValue("H", self->cppobj->getError()));
  168. }
  169. PyObject*
  170. TSIG_getMAC(const s_TSIG* const self) {
  171. return (Py_BuildValue("y#", self->cppobj->getMAC(),
  172. self->cppobj->getMACSize()));
  173. }
  174. PyObject*
  175. TSIG_getOtherData(const s_TSIG* const self) {
  176. return (Py_BuildValue("y#", self->cppobj->getOtherData(),
  177. self->cppobj->getOtherLen()));
  178. }
  179. PyObject*
  180. TSIG_toText(const s_TSIG* const self) {
  181. try {
  182. // toText() could throw, so we need to catch any exceptions below.
  183. return (Py_BuildValue("s", self->cppobj->toText().c_str()));
  184. } catch (const exception& ex) {
  185. const string ex_what =
  186. "Failed to convert TSIG object to text: " +
  187. string(ex.what());
  188. PyErr_SetString(po_IscException, ex_what.c_str());
  189. } catch (...) {
  190. PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
  191. "converting TSIG object to text");
  192. }
  193. return (NULL);
  194. }
  195. PyObject*
  196. TSIG_str(PyObject* self) {
  197. // Simply call the to_text method we already defined
  198. return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
  199. const_cast<char*>("")));
  200. }
  201. PyObject*
  202. TSIG_toWire(const s_TSIG* const self, PyObject* args) {
  203. typedef any::TSIG TSIGRdata;
  204. return (toWireWrapper<s_TSIG, TSIGRdata, ToWireCallVoid<const TSIGRdata> >(
  205. self, args));
  206. }
  207. PyObject*
  208. TSIG_richcmp(const s_TSIG* const self,
  209. const s_TSIG* const other,
  210. const int op)
  211. {
  212. bool c = false;
  213. // Check for null and if the types match. If different type,
  214. // simply return False
  215. if (other == NULL || (self->ob_type != other->ob_type)) {
  216. Py_RETURN_FALSE;
  217. }
  218. // Only equals and not equals here, unorderable type
  219. const int cmp = self->cppobj->compare(*other->cppobj);
  220. switch (op) {
  221. case Py_EQ:
  222. c = (cmp == 0);
  223. break;
  224. case Py_NE:
  225. c = (cmp != 0);
  226. break;
  227. case Py_GT:
  228. c = (cmp > 0);
  229. break;
  230. case Py_GE:
  231. c = (cmp >= 0);
  232. break;
  233. case Py_LT:
  234. c = (cmp < 0);
  235. break;
  236. case Py_LE:
  237. c = (cmp <= 0);
  238. break;
  239. default:
  240. PyErr_SetString(PyExc_IndexError,
  241. "Unhandled rich comparison operator for TSIG");
  242. return (NULL);
  243. }
  244. if (c) {
  245. Py_RETURN_TRUE;
  246. } else {
  247. Py_RETURN_FALSE;
  248. }
  249. }
  250. } // end of unnamed namespace
  251. namespace isc {
  252. namespace dns {
  253. namespace python {
  254. // This defines the complete type for reflection in python and
  255. // parsing of PyObject* to s_TSIG
  256. // Most of the functions are not actually implemented and NULL here.
  257. PyTypeObject tsig_type = {
  258. PyVarObject_HEAD_INIT(NULL, 0)
  259. "pydnspp.TSIG",
  260. sizeof(s_TSIG), // tp_basicsize
  261. 0, // tp_itemsize
  262. reinterpret_cast<destructor>(TSIG_destroy), // tp_dealloc
  263. NULL, // tp_print
  264. NULL, // tp_getattr
  265. NULL, // tp_setattr
  266. NULL, // tp_reserved
  267. NULL, // tp_repr
  268. NULL, // tp_as_number
  269. NULL, // tp_as_sequence
  270. NULL, // tp_as_mapping
  271. NULL, // tp_hash
  272. NULL, // tp_call
  273. TSIG_str, // tp_str
  274. NULL, // tp_getattro
  275. NULL, // tp_setattro
  276. NULL, // tp_as_buffer
  277. Py_TPFLAGS_DEFAULT, // tp_flags
  278. "The TSIG class objects represents the TSIG RDATA as defined in RFC2845.",
  279. NULL, // tp_traverse
  280. NULL, // tp_clear
  281. reinterpret_cast<richcmpfunc>(TSIG_richcmp), // tp_richcompare
  282. 0, // tp_weaklistoffset
  283. NULL, // tp_iter
  284. NULL, // tp_iternext
  285. TSIG_methods, // tp_methods
  286. NULL, // tp_members
  287. NULL, // tp_getset
  288. // At the moment, we leave tp_base NULL as we won't use this class
  289. // in a polymorphic way for our immediate need.
  290. NULL, // tp_base
  291. NULL, // tp_dict
  292. NULL, // tp_descr_get
  293. NULL, // tp_descr_set
  294. 0, // tp_dictoffset
  295. reinterpret_cast<initproc>(TSIG_init), // tp_init
  296. NULL, // tp_alloc
  297. PyType_GenericNew, // tp_new
  298. NULL, // tp_free
  299. NULL, // tp_is_gc
  300. NULL, // tp_bases
  301. NULL, // tp_mro
  302. NULL, // tp_cache
  303. NULL, // tp_subclasses
  304. NULL, // tp_weaklist
  305. NULL, // tp_del
  306. 0 // tp_version_tag
  307. };
  308. // Module Initialization, all statics are initialized here
  309. bool
  310. initModulePart_TSIG(PyObject* mod) {
  311. // We initialize the static description object with PyType_Ready(),
  312. // then add it to the module. This is not just a check! (leaving
  313. // this out results in segmentation faults)
  314. if (PyType_Ready(&tsig_type) < 0) {
  315. return (false);
  316. }
  317. void* p = &tsig_type;
  318. if (PyModule_AddObject(mod, "TSIG", static_cast<PyObject*>(p)) < 0) {
  319. return (false);
  320. }
  321. Py_INCREF(&tsig_type);
  322. return (true);
  323. }
  324. PyObject*
  325. createTSIGObject(const any::TSIG& source) {
  326. TSIGContainer container = PyObject_New(s_TSIG, &tsig_type);
  327. container.set(new any::TSIG(source));
  328. return (container.release());
  329. }
  330. } // namespace python
  331. } // namespace dns
  332. } // namespace isc