messagerenderer_python.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. #include <Python.h>
  15. #include <util/buffer.h>
  16. #include <dns/messagerenderer.h>
  17. #include <util/python/pycppwrapper_util.h>
  18. #include "pydnspp_common.h"
  19. #include "messagerenderer_python.h"
  20. using namespace isc::dns;
  21. using namespace isc::dns::python;
  22. using namespace isc::util;
  23. using namespace isc::util::python;
  24. namespace {
  25. // The s_* Class simply covers one instantiation of the object.
  26. //
  27. // since we don't use *Buffer in the python version (but work with
  28. // the already existing bytearray type where we use these custom buffers
  29. // in C++, we need to keep track of one here.
  30. class s_MessageRenderer : public PyObject {
  31. public:
  32. s_MessageRenderer();
  33. isc::util::OutputBuffer* outputbuffer;
  34. MessageRenderer* cppobj;
  35. };
  36. int MessageRenderer_init(s_MessageRenderer* self);
  37. void MessageRenderer_destroy(s_MessageRenderer* self);
  38. PyObject* MessageRenderer_getData(s_MessageRenderer* self);
  39. PyObject* MessageRenderer_getLength(s_MessageRenderer* self);
  40. PyObject* MessageRenderer_isTruncated(s_MessageRenderer* self);
  41. PyObject* MessageRenderer_getLengthLimit(s_MessageRenderer* self);
  42. PyObject* MessageRenderer_getCompressMode(s_MessageRenderer* self);
  43. PyObject* MessageRenderer_setTruncated(s_MessageRenderer* self);
  44. PyObject* MessageRenderer_setLengthLimit(s_MessageRenderer* self, PyObject* args);
  45. PyObject* MessageRenderer_setCompressMode(s_MessageRenderer* self, PyObject* args);
  46. PyObject* MessageRenderer_clear(s_MessageRenderer* self);
  47. PyMethodDef MessageRenderer_methods[] = {
  48. { "get_data", reinterpret_cast<PyCFunction>(MessageRenderer_getData), METH_NOARGS,
  49. "Returns the data as a bytes() object" },
  50. { "get_length", reinterpret_cast<PyCFunction>(MessageRenderer_getLength), METH_NOARGS,
  51. "Returns the length of the data" },
  52. { "is_truncated", reinterpret_cast<PyCFunction>(MessageRenderer_isTruncated), METH_NOARGS,
  53. "Returns True if the data is truncated" },
  54. { "get_length_limit", reinterpret_cast<PyCFunction>(MessageRenderer_getLengthLimit), METH_NOARGS,
  55. "Returns the length limit of the data" },
  56. { "get_compress_mode", reinterpret_cast<PyCFunction>(MessageRenderer_getCompressMode), METH_NOARGS,
  57. "Returns the current compression mode" },
  58. { "set_truncated", reinterpret_cast<PyCFunction>(MessageRenderer_setTruncated), METH_NOARGS,
  59. "Sets truncated to true" },
  60. { "set_length_limit", reinterpret_cast<PyCFunction>(MessageRenderer_setLengthLimit), METH_VARARGS,
  61. "Sets the length limit of the data to the given number" },
  62. { "set_compress_mode", reinterpret_cast<PyCFunction>(MessageRenderer_setCompressMode), METH_VARARGS,
  63. "Sets the compression mode of the MessageRenderer" },
  64. { "clear", reinterpret_cast<PyCFunction>(MessageRenderer_clear),
  65. METH_NOARGS,
  66. "Clear the internal buffer and other internal resources." },
  67. { NULL, NULL, 0, NULL }
  68. };
  69. int
  70. MessageRenderer_init(s_MessageRenderer* self) {
  71. self->outputbuffer = new OutputBuffer(4096);
  72. self->cppobj = new MessageRenderer(*self->outputbuffer);
  73. return (0);
  74. }
  75. void
  76. MessageRenderer_destroy(s_MessageRenderer* self) {
  77. delete self->cppobj;
  78. delete self->outputbuffer;
  79. self->cppobj = NULL;
  80. self->outputbuffer = NULL;
  81. Py_TYPE(self)->tp_free(self);
  82. }
  83. PyObject*
  84. MessageRenderer_getData(s_MessageRenderer* self) {
  85. return (Py_BuildValue("y#",
  86. self->cppobj->getData(),
  87. self->cppobj->getLength()));
  88. }
  89. PyObject*
  90. MessageRenderer_getLength(s_MessageRenderer* self) {
  91. return (Py_BuildValue("I", self->cppobj->getLength()));
  92. }
  93. PyObject*
  94. MessageRenderer_isTruncated(s_MessageRenderer* self) {
  95. if (self->cppobj->isTruncated()) {
  96. Py_RETURN_TRUE;
  97. } else {
  98. Py_RETURN_FALSE;
  99. }
  100. }
  101. PyObject*
  102. MessageRenderer_getLengthLimit(s_MessageRenderer* self) {
  103. return (Py_BuildValue("I", self->cppobj->getLengthLimit()));
  104. }
  105. PyObject*
  106. MessageRenderer_getCompressMode(s_MessageRenderer* self) {
  107. return (Py_BuildValue("I", self->cppobj->getCompressMode()));
  108. }
  109. PyObject*
  110. MessageRenderer_setTruncated(s_MessageRenderer* self) {
  111. self->cppobj->setTruncated();
  112. Py_RETURN_NONE;
  113. }
  114. PyObject*
  115. MessageRenderer_setLengthLimit(s_MessageRenderer* self,
  116. PyObject* args)
  117. {
  118. long lengthlimit;
  119. if (!PyArg_ParseTuple(args, "l", &lengthlimit)) {
  120. PyErr_Clear();
  121. PyErr_SetString(PyExc_TypeError,
  122. "No valid type in set_length_limit argument");
  123. return (NULL);
  124. }
  125. if (lengthlimit < 0) {
  126. PyErr_SetString(PyExc_ValueError,
  127. "MessageRenderer length limit out of range");
  128. return (NULL);
  129. }
  130. self->cppobj->setLengthLimit(lengthlimit);
  131. Py_RETURN_NONE;
  132. }
  133. PyObject*
  134. MessageRenderer_setCompressMode(s_MessageRenderer* self,
  135. PyObject* args)
  136. {
  137. int mode;
  138. if (!PyArg_ParseTuple(args, "i", &mode)) {
  139. return (NULL);
  140. }
  141. if (mode == MessageRenderer::CASE_INSENSITIVE) {
  142. self->cppobj->setCompressMode(MessageRenderer::CASE_INSENSITIVE);
  143. // If we return NULL it is seen as an error, so use this for
  144. // None returns, it also applies to CASE_SENSITIVE.
  145. Py_RETURN_NONE;
  146. } else if (mode == MessageRenderer::CASE_SENSITIVE) {
  147. self->cppobj->setCompressMode(MessageRenderer::CASE_SENSITIVE);
  148. Py_RETURN_NONE;
  149. } else {
  150. PyErr_SetString(PyExc_TypeError,
  151. "MessageRenderer compress mode must be MessageRenderer.CASE_INSENSITIVE"
  152. "or MessageRenderer.CASE_SENSITIVE");
  153. return (NULL);
  154. }
  155. }
  156. PyObject*
  157. MessageRenderer_clear(s_MessageRenderer* self) {
  158. self->cppobj->clear();
  159. Py_RETURN_NONE;
  160. }
  161. } // end of unnamed namespace
  162. namespace isc {
  163. namespace dns {
  164. namespace python {
  165. PyTypeObject messagerenderer_type = {
  166. PyVarObject_HEAD_INIT(NULL, 0)
  167. "pydnspp.MessageRenderer",
  168. sizeof(s_MessageRenderer), // tp_basicsize
  169. 0, // tp_itemsize
  170. (destructor)MessageRenderer_destroy,// tp_dealloc
  171. NULL, // tp_print
  172. NULL, // tp_getattr
  173. NULL, // tp_setattr
  174. NULL, // tp_reserved
  175. NULL, // tp_repr
  176. NULL, // tp_as_number
  177. NULL, // tp_as_sequence
  178. NULL, // tp_as_mapping
  179. NULL, // tp_hash
  180. NULL, // tp_call
  181. NULL, // tp_str
  182. NULL, // tp_getattro
  183. NULL, // tp_setattro
  184. NULL, // tp_as_buffer
  185. Py_TPFLAGS_DEFAULT, // tp_flags
  186. "The MessageRenderer class encapsulates implementation details "
  187. "of rendering a DNS message into a buffer in wire format. "
  188. "In effect, it's simply responsible for name compression at least in the "
  189. "current implementation. A MessageRenderer class object manages the "
  190. "positions of names rendered in a buffer and uses that information to render "
  191. "subsequent names with compression.",
  192. NULL, // tp_traverse
  193. NULL, // tp_clear
  194. NULL, // tp_richcompare
  195. 0, // tp_weaklistoffset
  196. NULL, // tp_iter
  197. NULL, // tp_iternext
  198. MessageRenderer_methods, // tp_methods
  199. NULL, // tp_members
  200. NULL, // tp_getset
  201. NULL, // tp_base
  202. NULL, // tp_dict
  203. NULL, // tp_descr_get
  204. NULL, // tp_descr_set
  205. 0, // tp_dictoffset
  206. (initproc)MessageRenderer_init, // tp_init
  207. NULL, // tp_alloc
  208. PyType_GenericNew, // tp_new
  209. NULL, // tp_free
  210. NULL, // tp_is_gc
  211. NULL, // tp_bases
  212. NULL, // tp_mro
  213. NULL, // tp_cache
  214. NULL, // tp_subclasses
  215. NULL, // tp_weaklist
  216. NULL, // tp_del
  217. 0 // tp_version_tag
  218. };
  219. // If we need a createMessageRendererObject(), should we copy? can we?
  220. // copy the existing buffer into a new one, then create a new renderer with
  221. // that buffer?
  222. bool
  223. PyMessageRenderer_Check(PyObject* obj) {
  224. if (obj == NULL) {
  225. isc_throw(PyCPPWrapperException, "obj argument NULL in typecheck");
  226. }
  227. return (PyObject_TypeCheck(obj, &messagerenderer_type));
  228. }
  229. MessageRenderer&
  230. PyMessageRenderer_ToMessageRenderer(PyObject* messagerenderer_obj) {
  231. if (messagerenderer_obj == NULL) {
  232. isc_throw(PyCPPWrapperException,
  233. "obj argument NULL in MessageRenderer PyObject conversion");
  234. }
  235. s_MessageRenderer* messagerenderer = static_cast<s_MessageRenderer*>(messagerenderer_obj);
  236. return (*messagerenderer->cppobj);
  237. }
  238. } // namespace python
  239. } // namespace dns
  240. } // namespace isc