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 <util/python/pycppwrapper_util.h>
24 : :
25 : : #include <datasrc/client.h>
26 : : #include <datasrc/database.h>
27 : : #include <datasrc/data_source.h>
28 : : #include <datasrc/sqlite3_accessor.h>
29 : : #include <datasrc/iterator.h>
30 : : #include <datasrc/zone.h>
31 : :
32 : : #include <dns/python/name_python.h>
33 : : #include <dns/python/rrset_python.h>
34 : : #include <dns/python/rrclass_python.h>
35 : : #include <dns/python/rrtype_python.h>
36 : : #include <dns/python/pydnspp_common.h>
37 : :
38 : : #include "datasrc.h"
39 : : #include "finder_python.h"
40 : : #include "finder_inc.cc"
41 : :
42 : : using namespace std;
43 : : using namespace isc::util::python;
44 : : using namespace isc::dns::python;
45 : : using namespace isc::datasrc;
46 : : using namespace isc::datasrc::python;
47 : :
48 : : namespace {
49 : : ZoneFinder::FindResultFlags
50 : : getFindResultFlags(const ZoneFinder::Context& context) {
51 : 254 : ZoneFinder::FindResultFlags result_flags = ZoneFinder::RESULT_DEFAULT;
52 [ - + ][ + + ]: 254 : if (context.isWildcard()) {
53 : 2 : result_flags = result_flags | ZoneFinder::RESULT_WILDCARD;
54 : : }
55 [ - + ][ - + ]: 254 : if (context.isNSECSigned()) {
56 : 0 : result_flags = result_flags | ZoneFinder::RESULT_NSEC_SIGNED;
57 : : }
58 [ - + ][ - + ]: 254 : if (context.isNSEC3Signed()) {
59 : 0 : result_flags = result_flags | ZoneFinder::RESULT_NSEC3_SIGNED;
60 : : }
61 : : return (result_flags);
62 : : }
63 : : }
64 : :
65 : : namespace isc_datasrc_internal {
66 : : // This is the shared code for the find() call in the finder and the updater
67 : : // Is is intentionally not available through any header, nor at our standard
68 : : // namespace, as it is not supposed to be called anywhere but from finder and
69 : : // updater
70 : 252 : PyObject* ZoneFinder_helper(ZoneFinder* finder, PyObject* args) {
71 [ - + ]: 252 : if (finder == NULL) {
72 : : PyErr_SetString(getDataSourceException("Error"),
73 : : "Internal error in find() wrapper; "
74 : 0 : "finder object NULL");
75 : 0 : return (NULL);
76 : : }
77 : : PyObject* name;
78 : : PyObject* rrtype;
79 : 252 : unsigned int options_int = ZoneFinder::FIND_DEFAULT;
80 [ + + ]: 252 : if (PyArg_ParseTuple(args, "O!O!|I", &name_type, &name,
81 : : &rrtype_type, &rrtype,
82 : 252 : &options_int)) {
83 : : try {
84 : : ZoneFinder::FindOptions options =
85 : 249 : static_cast<ZoneFinder::FindOptions>(options_int);
86 : : ConstZoneFinderContextPtr find_ctx(
87 [ + - ][ + - ]: 249 : finder->find(PyName_ToName(name), PyRRType_ToRRType(rrtype),
88 [ + + ]: 249 : options));
89 : 248 : const ZoneFinder::Result r = find_ctx->code;
90 : 248 : isc::dns::ConstRRsetPtr rrsp = find_ctx->rrset;
91 : : ZoneFinder::FindResultFlags result_flags =
92 : 744 : getFindResultFlags(*find_ctx);
93 [ + + ]: 248 : if (rrsp) {
94 : : // Use N instead of O so the refcount isn't increased twice
95 : 204 : return (Py_BuildValue("INI", r, createRRsetObject(*rrsp),
96 [ + - ][ + - ]: 204 : result_flags));
97 : : } else {
98 [ + - ]: 44 : return (Py_BuildValue("IOI", r, Py_None, result_flags));
99 : : }
100 : 2 : } catch (const OutOfZone& ooz) {
101 [ - + ][ - + ]: 1 : PyErr_SetString(getDataSourceException("OutOfZone"), ooz.what());
102 : : return (NULL);
103 : 0 : } catch (const DataSourceError& dse) {
104 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), dse.what());
105 : : return (NULL);
106 : 0 : } catch (const std::exception& exc) {
107 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), exc.what());
108 : : return (NULL);
109 [ + - - - ]: 1 : } catch (...) {
110 : : PyErr_SetString(getDataSourceException("Error"),
111 [ # # ][ # # ]: 0 : "Unexpected exception");
112 : : return (NULL);
113 : : }
114 : : } else {
115 : : return (NULL);
116 : : }
117 : : }
118 : :
119 : 6 : PyObject* ZoneFinder_helper_all(ZoneFinder* finder, PyObject* args) {
120 [ - + ]: 6 : if (finder == NULL) {
121 : : PyErr_SetString(getDataSourceException("Error"),
122 : : "Internal error in find_all() wrapper; "
123 : 0 : "finder object NULL");
124 : 0 : return (NULL);
125 : : }
126 : : PyObject* name;
127 : 6 : const unsigned int options_int = ZoneFinder::FIND_DEFAULT;
128 [ + - ]: 6 : if (PyArg_ParseTuple(args, "O!|I", &name_type, &name, &options_int)) {
129 : : try {
130 : : ZoneFinder::FindOptions options =
131 : 6 : static_cast<ZoneFinder::FindOptions>(options_int);
132 [ + - ]: 6 : std::vector<isc::dns::ConstRRsetPtr> target;
133 : : ConstZoneFinderContextPtr find_ctx(
134 [ + - ][ + - ]: 6 : finder->findAll(PyName_ToName(name), target, options));
135 : 6 : const ZoneFinder::Result r = find_ctx->code;
136 : 6 : isc::dns::ConstRRsetPtr rrsp = find_ctx->rrset;
137 : : ZoneFinder::FindResultFlags result_flags =
138 : 18 : getFindResultFlags(*find_ctx);
139 [ + + ]: 6 : if (r == ZoneFinder::SUCCESS) {
140 : : // Copy all the RRsets to the result list
141 [ + - ][ + - ]: 2 : PyObjectContainer list_container(PyList_New(target.size()));
142 [ + + ]: 6 : for (size_t i(0); i < target.size(); ++i) {
143 [ + - ]: 4 : PyList_SET_ITEM(list_container.get(), i,
144 : 4 : createRRsetObject(*target[i]));
145 : : }
146 : : // Construct the result with the list. The Py_BuildValue
147 : : // increases the refcount and the container decreases it
148 : : // later. This way, it feels safer in case the build function
149 : : // would fail.
150 [ + - ]: 2 : return (Py_BuildValue("IO", r, list_container.get()));
151 : : } else {
152 [ + + ]: 4 : if (rrsp) {
153 : : // Use N instead of O so the refcount isn't increased twice
154 : 2 : return (Py_BuildValue("INI", r, createRRsetObject(*rrsp),
155 [ + - ][ + - ]: 2 : result_flags));
156 : : } else {
157 [ + - ]: 2 : return (Py_BuildValue("IOI", r, Py_None, result_flags));
158 : : }
159 : : }
160 : 0 : } catch (const DataSourceError& dse) {
161 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), dse.what());
162 : : return (NULL);
163 : 0 : } catch (const std::exception& exc) {
164 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), exc.what());
165 : : return (NULL);
166 [ # # # ]: 0 : } catch (...) {
167 : : PyErr_SetString(getDataSourceException("Error"),
168 [ # # ][ # # ]: 0 : "Unexpected exception");
169 : : return (NULL);
170 : : }
171 : : } else {
172 : : return (NULL);
173 : : }
174 : : }
175 : :
176 : : } // end namespace internal
177 : :
178 : : namespace {
179 : : // The s_* Class simply covers one instantiation of the object
180 : : class s_ZoneFinder : public PyObject {
181 : : public:
182 : : s_ZoneFinder() : cppobj(ZoneFinderPtr()), base_obj(NULL) {};
183 : : ZoneFinderPtr cppobj;
184 : : // This is a reference to a base object; if the object of this class
185 : : // depends on another object to be in scope during its lifetime,
186 : : // we use INCREF the base object upon creation, and DECREF it at
187 : : // the end of the destructor
188 : : // This is an optional argument to createXXX(). If NULL, it is ignored.
189 : : PyObject* base_obj;
190 : : };
191 : :
192 : : // Shortcut type which would be convenient for adding class variables safely.
193 : : typedef CPPPyObjectContainer<s_ZoneFinder, ZoneFinder> ZoneFinderContainer;
194 : :
195 : : // General creation and destruction
196 : : int
197 : 1 : ZoneFinder_init(PyObject*, PyObject*, PyObject*) {
198 : : // can't be called directly
199 : : PyErr_SetString(PyExc_TypeError,
200 : 1 : "ZoneFinder cannot be constructed directly");
201 : :
202 : 1 : return (-1);
203 : : }
204 : :
205 : : void
206 : 176 : ZoneFinder_destroy(PyObject* po_self) {
207 : 176 : s_ZoneFinder* self = static_cast<s_ZoneFinder*>(po_self);
208 : : // cppobj is a shared ptr, but to make sure things are not destroyed in
209 : : // the wrong order, we reset it here.
210 : 176 : self->cppobj.reset();
211 [ + + ]: 176 : if (self->base_obj != NULL) {
212 [ + + ]: 175 : Py_DECREF(self->base_obj);
213 : : }
214 : 176 : Py_TYPE(self)->tp_free(self);
215 : 176 : }
216 : :
217 : : PyObject*
218 : 5 : ZoneFinder_getClass(PyObject* po_self, PyObject*) {
219 : 5 : s_ZoneFinder* self = static_cast<s_ZoneFinder*>(po_self);
220 : : try {
221 [ + - ][ + - ]: 5 : return (createRRClassObject(self->cppobj->getClass()));
222 [ # # ]: 0 : } catch (const std::exception& exc) {
223 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), exc.what());
224 : : return (NULL);
225 : : }
226 : : }
227 : :
228 : : PyObject*
229 : 5 : ZoneFinder_getOrigin(PyObject* po_self, PyObject*) {
230 : 5 : s_ZoneFinder* self = static_cast<s_ZoneFinder*>(po_self);
231 : : try {
232 [ + - ][ + - ]: 5 : return (createNameObject(self->cppobj->getOrigin()));
233 : 0 : } catch (const std::exception& exc) {
234 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), exc.what());
235 : : return (NULL);
236 [ # # ]: 0 : } catch (...) {
237 : : PyErr_SetString(getDataSourceException("Error"),
238 [ # # ][ # # ]: 0 : "Unexpected exception");
239 : : return (NULL);
240 : : }
241 : : }
242 : :
243 : : PyObject*
244 : 248 : ZoneFinder_find(PyObject* po_self, PyObject* args) {
245 : 248 : s_ZoneFinder* const self = static_cast<s_ZoneFinder*>(po_self);
246 : 248 : return (isc_datasrc_internal::ZoneFinder_helper(self->cppobj.get(), args));
247 : : }
248 : :
249 : : PyObject*
250 : 3 : ZoneFinder_find_all(PyObject* po_self, PyObject* args) {
251 : 3 : s_ZoneFinder* const self = static_cast<s_ZoneFinder*>(po_self);
252 : : return (isc_datasrc_internal::ZoneFinder_helper_all(self->cppobj.get(),
253 : 3 : args));
254 : : }
255 : :
256 : : PyObject*
257 : 4 : ZoneFinder_findPreviousName(PyObject* po_self, PyObject* args) {
258 : 4 : s_ZoneFinder* const self = static_cast<s_ZoneFinder*>(po_self);
259 : : PyObject* name_obj;
260 [ + - ]: 4 : if (PyArg_ParseTuple(args, "O!", &name_type, &name_obj)) {
261 : : try {
262 : : return (createNameObject(
263 [ + - ][ + + ]: 5 : self->cppobj->findPreviousName(PyName_ToName(name_obj))));
[ + - ]
264 : 2 : } catch (const isc::NotImplemented& nie) {
265 : : PyErr_SetString(getDataSourceException("NotImplemented"),
266 [ - + ][ - + ]: 1 : nie.what());
267 : : return (NULL);
268 : 0 : } catch (const std::exception& exc) {
269 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), exc.what());
270 : : return (NULL);
271 [ + - - ]: 1 : } catch (...) {
272 : : PyErr_SetString(getDataSourceException("Error"),
273 [ # # ][ # # ]: 0 : "Unexpected exception");
274 : : return (NULL);
275 : : }
276 : : } else {
277 : : return (NULL);
278 : : }
279 : : }
280 : :
281 : : // This list contains the actual set of functions we have in
282 : : // python. Each entry has
283 : : // 1. Python method name
284 : : // 2. Our static function here
285 : : // 3. Argument type
286 : : // 4. Documentation
287 : : PyMethodDef ZoneFinder_methods[] = {
288 : : { "get_origin", ZoneFinder_getOrigin, METH_NOARGS,
289 : : ZoneFinder_getOrigin_doc },
290 : : { "get_class", ZoneFinder_getClass, METH_NOARGS, ZoneFinder_getClass_doc },
291 : : { "find", ZoneFinder_find, METH_VARARGS, ZoneFinder_find_doc },
292 : : { "find_all", ZoneFinder_find_all, METH_VARARGS, ZoneFinder_findAll_doc },
293 : : { "find_previous_name", ZoneFinder_findPreviousName, METH_VARARGS,
294 : : ZoneFinder_find_previous_name_doc },
295 : : { NULL, NULL, 0, NULL }
296 : : };
297 : :
298 : : } // end of unnamed namespace
299 : :
300 : : namespace isc {
301 : : namespace datasrc {
302 : : namespace python {
303 : :
304 : : PyTypeObject zonefinder_type = {
305 : : PyVarObject_HEAD_INIT(NULL, 0)
306 : : "datasrc.ZoneFinder",
307 : : sizeof(s_ZoneFinder), // tp_basicsize
308 : : 0, // tp_itemsize
309 : : ZoneFinder_destroy, // tp_dealloc
310 : : NULL, // tp_print
311 : : NULL, // tp_getattr
312 : : NULL, // tp_setattr
313 : : NULL, // tp_reserved
314 : : NULL, // tp_repr
315 : : NULL, // tp_as_number
316 : : NULL, // tp_as_sequence
317 : : NULL, // tp_as_mapping
318 : : NULL, // tp_hash
319 : : NULL, // tp_call
320 : : NULL, // tp_str
321 : : NULL, // tp_getattro
322 : : NULL, // tp_setattro
323 : : NULL, // tp_as_buffer
324 : : Py_TPFLAGS_DEFAULT, // tp_flags
325 : : ZoneFinder_doc,
326 : : NULL, // tp_traverse
327 : : NULL, // tp_clear
328 : : NULL, // tp_richcompare
329 : : 0, // tp_weaklistoffset
330 : : NULL, // tp_iter
331 : : NULL, // tp_iternext
332 : : ZoneFinder_methods, // tp_methods
333 : : NULL, // tp_members
334 : : NULL, // tp_getset
335 : : NULL, // tp_base
336 : : NULL, // tp_dict
337 : : NULL, // tp_descr_get
338 : : NULL, // tp_descr_set
339 : : 0, // tp_dictoffset
340 : : ZoneFinder_init, // tp_init
341 : : NULL, // tp_alloc
342 : : PyType_GenericNew, // tp_new
343 : : NULL, // tp_free
344 : : NULL, // tp_is_gc
345 : : NULL, // tp_bases
346 : : NULL, // tp_mro
347 : : NULL, // tp_cache
348 : : NULL, // tp_subclasses
349 : : NULL, // tp_weaklist
350 : : NULL, // tp_del
351 : : 0 // tp_version_tag
352 : : };
353 : :
354 : : PyObject*
355 : 175 : createZoneFinderObject(isc::datasrc::ZoneFinderPtr source, PyObject* base_obj) {
356 : : s_ZoneFinder* py_zf = static_cast<s_ZoneFinder*>(
357 : 175 : zonefinder_type.tp_alloc(&zonefinder_type, 0));
358 [ + - ]: 175 : if (py_zf != NULL) {
359 : 175 : py_zf->cppobj = source;
360 : 175 : py_zf->base_obj = base_obj;
361 [ + - ]: 175 : if (base_obj != NULL) {
362 : 175 : Py_INCREF(base_obj);
363 : : }
364 : : }
365 : 175 : return (py_zf);
366 : : }
367 : :
368 : : } // namespace python
369 : : } // namespace datasrc
370 : 104 : } // namespace isc
371 : :
|