2 * pythonmod.c: unbound module C wrapper
4 * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
5 * Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
7 * This software is open source.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * * Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
20 * * Neither the name of the organization nor the names of its
21 * contributors may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
38 * Python module for unbound. Calls python script.
41 /* ignore the varargs unused warning from SWIGs internal vararg support */
43 #pragma GCC diagnostic ignored "-Wunused-parameter"
45 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
50 #include "sldns/sbuffer.h"
52 #undef _POSIX_C_SOURCE
56 #include "pythonmod/pythonmod.h"
57 #include "util/module.h"
58 #include "util/config_file.h"
59 #include "pythonmod_utils.h"
62 typedef struct PyObject PyObject;
63 typedef struct PyThreadState PyThreadState;
64 typedef void* PyGILState_STATE;
68 * Global state for the module.
70 struct pythonmod_env {
72 /** Python script filename. */
75 /** Python main thread */
76 PyThreadState* mainthr;
80 /** Module init function */
82 /** Module deinit function */
83 PyObject* func_deinit;
84 /** Module operate function */
85 PyObject* func_operate;
86 /** Module super_inform function */
87 PyObject* func_inform;
89 /** Python dictionary. */
96 struct module_qstate* qstate;
100 * Per query state for the iterator module.
102 struct pythonmod_qstate {
104 /** Module per query data. */
110 #include "pythonmod/interface.h"
113 /** log python error */
118 const char* iomod = "cStringIO";
119 PyObject *modStringIO = NULL;
120 PyObject *modTB = NULL;
121 PyObject *obFuncStringIO = NULL;
122 PyObject *obStringIO = NULL;
123 PyObject *obFuncTB = NULL;
124 PyObject *argsTB = NULL;
125 PyObject *obResult = NULL;
126 PyObject *ascstr = NULL;
127 PyObject *exc_typ, *exc_val, *exc_tb;
129 /* Fetch the error state now before we cruch it */
130 /* exc val contains the error message
131 * exc tb contains stack traceback and other info. */
132 PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
133 PyErr_NormalizeException(&exc_typ, &exc_val, &exc_tb);
135 /* Import the modules we need - cStringIO and traceback */
136 modStringIO = PyImport_ImportModule("cStringIO");
137 if (modStringIO==NULL) {
138 /* python 1.4 and before */
139 modStringIO = PyImport_ImportModule("StringIO");
142 if (modStringIO==NULL) {
144 modStringIO = PyImport_ImportModule("io");
147 if (modStringIO==NULL) {
148 log_err("pythonmod: cannot print exception, "
149 "cannot ImportModule cStringIO or StringIO or io");
152 modTB = PyImport_ImportModule("traceback");
154 log_err("pythonmod: cannot print exception, "
155 "cannot ImportModule traceback");
159 /* Construct a cStringIO object */
160 obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
161 if (obFuncStringIO==NULL) {
162 log_err("pythonmod: cannot print exception, "
163 "cannot GetAttrString %s.StringIO", iomod);
166 obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
167 if (obStringIO==NULL) {
168 log_err("pythonmod: cannot print exception, "
169 "cannot call %s.StringIO()", iomod);
173 /* Get the traceback.print_exception function, and call it. */
174 obFuncTB = PyObject_GetAttrString(modTB, "print_exception");
175 if (obFuncTB==NULL) {
176 log_err("pythonmod: cannot print exception, "
177 "cannot GetAttrString traceback.print_exception");
180 argsTB = Py_BuildValue("OOOOO", (exc_typ ? exc_typ : Py_None),
181 (exc_val ? exc_val : Py_None), (exc_tb ? exc_tb : Py_None),
182 Py_None, obStringIO);
184 log_err("pythonmod: cannot print exception, "
185 "cannot BuildValue for print_exception");
189 obResult = PyObject_CallObject(obFuncTB, argsTB);
190 if (obResult==NULL) {
192 log_err("pythonmod: cannot print exception, "
193 "call traceback.print_exception() failed");
197 /* Now call the getvalue() method in the StringIO instance */
198 Py_DECREF(obFuncStringIO);
199 obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
200 if (obFuncStringIO==NULL) {
201 log_err("pythonmod: cannot print exception, "
202 "cannot GetAttrString StringIO.getvalue");
206 obResult = PyObject_CallObject(obFuncStringIO, NULL);
207 if (obResult==NULL) {
208 log_err("pythonmod: cannot print exception, "
209 "call StringIO.getvalue() failed");
213 /* And it should be a string all ready to go - duplicate it. */
214 if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
215 log_err("pythonmod: cannot print exception, "
216 "StringIO.getvalue() result did not String_Check"
217 " or Unicode_Check");
220 if(PyString_Check(obResult)) {
221 result = PyString_AsString(obResult);
223 ascstr = PyUnicode_AsASCIIString(obResult);
224 result = PyBytes_AsString(ascstr);
226 log_err("pythonmod: python error: %s", result);
229 Py_XDECREF(modStringIO);
231 Py_XDECREF(obFuncStringIO);
232 Py_XDECREF(obStringIO);
233 Py_XDECREF(obFuncTB);
235 Py_XDECREF(obResult);
238 /* clear the exception, by not restoring it */
239 /* Restore the exception state */
240 /* PyErr_Restore(exc_typ, exc_val, exc_tb); */
243 int pythonmod_init(struct module_env* env, int id)
245 /* Initialize module */
246 FILE* script_py = NULL;
247 PyObject* py_init_arg, *res;
248 PyGILState_STATE gil;
249 int init_standard = 1;
251 struct pythonmod_env* pe = (struct pythonmod_env*)calloc(1, sizeof(struct pythonmod_env));
254 log_err("pythonmod: malloc failure");
258 env->modinfo[id] = (void*) pe;
260 /* Initialize module */
261 pe->fname = env->cfg->python_script;
262 if(pe->fname==NULL || pe->fname[0]==0) {
263 log_err("pythonmod: no script given.");
267 /* Initialize Python libraries */
268 if (!Py_IsInitialized())
270 #if PY_MAJOR_VERSION >= 3
272 mbstowcs(progname, "unbound", 8);
274 char *progname = "unbound";
276 Py_SetProgramName(progname);
278 #if PY_MAJOR_VERSION >= 3
279 PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
282 PyEval_InitThreads();
284 pe->mainthr = PyEval_SaveThread();
287 gil = PyGILState_Ensure();
289 /* Initialize Python */
290 PyRun_SimpleString("import sys \n");
291 PyRun_SimpleString("sys.path.append('.') \n");
292 if(env->cfg->directory && env->cfg->directory[0]) {
294 snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
295 env->cfg->directory);
296 PyRun_SimpleString(wdir);
298 PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n");
299 PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n");
300 PyRun_SimpleString("import distutils.sysconfig \n");
301 PyRun_SimpleString("sys.path.append(distutils.sysconfig.get_python_lib(1,0)) \n");
302 if (PyRun_SimpleString("from unboundmodule import *\n") < 0)
304 log_err("pythonmod: cannot initialize core module: unboundmodule.py");
305 PyGILState_Release(gil);
309 /* Check Python file load */
310 if ((script_py = fopen(pe->fname, "r")) == NULL)
312 log_err("pythonmod: can't open file %s for reading", pe->fname);
313 PyGILState_Release(gil);
318 pe->module = PyImport_AddModule("__main__");
319 pe->dict = PyModule_GetDict(pe->module);
322 PyModule_AddObject(pe->module, "mod_env", pe->data);
324 /* TODO: deallocation of pe->... if an error occurs */
326 if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
327 log_err("pythonmod: can't parse Python script %s", pe->fname);
328 /* print the error to logs too, run it again */
329 fseek(script_py, 0, SEEK_SET);
330 /* we don't run the file, like this, because then side-effects
331 * s = PyRun_File(script_py, pe->fname, Py_file_input,
332 * PyModule_GetDict(PyImport_AddModule("__main__")), pe->dict);
333 * could happen (again). Instead we parse the file again to get
334 * the error string in the logs, for when the daemon has stderr
335 * removed. SimpleFile run already printed to stderr, for then
336 * this is called from unbound-checkconf or unbound -dd the user
337 * has a nice formatted error.
339 /* ignore the NULL return of _node, it is NULL due to the parse failure
340 * that we are expecting */
341 (void)PyParser_SimpleParseFile(script_py, pe->fname, Py_file_input);
343 PyGILState_Release(gil);
348 if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
351 if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
353 log_err("pythonmod: function init is missing in %s", pe->fname);
354 PyGILState_Release(gil);
358 if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
360 log_err("pythonmod: function deinit is missing in %s", pe->fname);
361 PyGILState_Release(gil);
364 if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL)
366 log_err("pythonmod: function operate is missing in %s", pe->fname);
367 PyGILState_Release(gil);
370 if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL)
372 log_err("pythonmod: function inform_super is missing in %s", pe->fname);
373 PyGILState_Release(gil);
379 py_init_arg = SWIG_NewPointerObj((void*) env, SWIGTYPE_p_module_env, 0);
383 py_init_arg = SWIG_NewPointerObj((void*) env->cfg,
384 SWIGTYPE_p_config_file, 0);
386 res = PyObject_CallFunction(pe->func_init, "iO", id, py_init_arg);
387 if (PyErr_Occurred())
389 log_err("pythonmod: Exception occurred in function init");
392 Py_XDECREF(py_init_arg);
393 PyGILState_Release(gil);
398 Py_XDECREF(py_init_arg);
399 PyGILState_Release(gil);
404 void pythonmod_deinit(struct module_env* env, int id)
406 struct pythonmod_env* pe = env->modinfo[id];
410 /* Free Python resources */
411 if(pe->module != NULL)
414 PyGILState_STATE gil = PyGILState_Ensure();
417 res = PyObject_CallFunction(pe->func_deinit, "i", id);
418 if (PyErr_Occurred()) {
419 log_err("pythonmod: Exception occurred in function deinit");
422 /* Free result if any */
424 /* Free shared data if any */
425 Py_XDECREF(pe->data);
426 PyGILState_Release(gil);
428 PyEval_RestoreThread(pe->mainthr);
435 /* Module is deallocated in Python */
436 env->modinfo[id] = NULL;
439 void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super)
441 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
442 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
443 PyObject* py_qstate, *py_sqstate, *res;
444 PyGILState_STATE gil = PyGILState_Ensure();
446 log_query_info(VERB_ALGO, "pythonmod: inform_super, sub is", &qstate->qinfo);
447 log_query_info(VERB_ALGO, "super is", &super->qinfo);
449 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
450 py_sqstate = SWIG_NewPointerObj((void*) super, SWIGTYPE_p_module_qstate, 0);
452 res = PyObject_CallFunction(pe->func_inform, "iOOO", id, py_qstate,
453 py_sqstate, pq->data);
455 if (PyErr_Occurred())
457 log_err("pythonmod: Exception occurred in function inform_super");
459 qstate->ext_state[id] = module_error;
461 else if ((res == NULL) || (!PyObject_IsTrue(res)))
463 log_err("pythonmod: python returned bad code in inform_super");
464 qstate->ext_state[id] = module_error;
468 Py_XDECREF(py_sqstate);
469 Py_XDECREF(py_qstate);
471 PyGILState_Release(gil);
474 void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
475 int id, struct outbound_entry* ATTR_UNUSED(outbound))
477 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
478 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
479 PyObject* py_qstate, *res;
480 PyGILState_STATE gil = PyGILState_Ensure();
485 pq = qstate->minfo[id] = malloc(sizeof(struct pythonmod_qstate));
487 /* Initialize per query data */
493 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
494 res = PyObject_CallFunction(pe->func_operate, "iiOO", id, (int) event,
495 py_qstate, pq->data);
496 if (PyErr_Occurred())
498 log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
500 qstate->ext_state[id] = module_error;
502 else if ((res == NULL) || (!PyObject_IsTrue(res)))
504 log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event));
505 qstate->ext_state[id] = module_error;
508 Py_XDECREF(py_qstate);
510 PyGILState_Release(gil);
513 void pythonmod_clear(struct module_qstate* qstate, int id)
515 struct pythonmod_qstate* pq;
519 pq = (struct pythonmod_qstate*)qstate->minfo[id];
520 verbose(VERB_ALGO, "pythonmod: clear, id: %d, pq:%lX", id,
521 (unsigned long int)pq);
524 PyGILState_STATE gil = PyGILState_Ensure();
526 PyGILState_Release(gil);
531 qstate->minfo[id] = NULL;
534 size_t pythonmod_get_mem(struct module_env* env, int id)
536 struct pythonmod_env* pe = (struct pythonmod_env*)env->modinfo[id];
537 verbose(VERB_ALGO, "pythonmod: get_mem, id: %d, pe:%lX", id,
538 (unsigned long int)pe);
545 * The module function block
547 static struct module_func_block pythonmod_block = {
549 &pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super,
550 &pythonmod_clear, &pythonmod_get_mem
553 struct module_func_block* pythonmod_get_funcblock(void)
555 return &pythonmod_block;