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"
44 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
48 #include "sldns/sbuffer.h"
50 #undef _POSIX_C_SOURCE
54 #include "pythonmod/pythonmod.h"
55 #include "util/module.h"
56 #include "util/config_file.h"
57 #include "pythonmod_utils.h"
60 typedef struct PyObject PyObject;
61 typedef struct PyThreadState PyThreadState;
62 typedef void* PyGILState_STATE;
66 * Global state for the module.
68 struct pythonmod_env {
70 /** Python script filename. */
73 /** Python main thread */
74 PyThreadState* mainthr;
78 /** Module init function */
80 /** Module deinit function */
81 PyObject* func_deinit;
82 /** Module operate function */
83 PyObject* func_operate;
84 /** Module super_inform function */
85 PyObject* func_inform;
87 /** Python dictionary. */
94 struct module_qstate* qstate;
98 * Per query state for the iterator module.
100 struct pythonmod_qstate {
102 /** Module per query data. */
108 #include "pythonmod/interface.h"
111 int pythonmod_init(struct module_env* env, int id)
113 /* Initialize module */
114 FILE* script_py = NULL;
115 PyObject* py_init_arg, *res;
116 PyGILState_STATE gil;
117 int init_standard = 1;
119 struct pythonmod_env* pe = (struct pythonmod_env*)calloc(1, sizeof(struct pythonmod_env));
122 log_err("pythonmod: malloc failure");
126 env->modinfo[id] = (void*) pe;
128 /* Initialize module */
129 pe->fname = env->cfg->python_script;
130 if(pe->fname==NULL || pe->fname[0]==0) {
131 log_err("pythonmod: no script given.");
135 /* Initialize Python libraries */
136 if (!Py_IsInitialized())
138 #if PY_MAJOR_VERSION >= 3
140 mbstowcs(progname, "unbound", 8);
142 char *progname = "unbound";
144 Py_SetProgramName(progname);
146 #if PY_MAJOR_VERSION >= 3
147 PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
150 PyEval_InitThreads();
152 pe->mainthr = PyEval_SaveThread();
155 gil = PyGILState_Ensure();
157 /* Initialize Python */
158 PyRun_SimpleString("import sys \n");
159 PyRun_SimpleString("sys.path.append('.') \n");
160 if(env->cfg->directory && env->cfg->directory[0]) {
162 snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
163 env->cfg->directory);
164 PyRun_SimpleString(wdir);
166 PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n");
167 PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n");
168 PyRun_SimpleString("import distutils.sysconfig \n");
169 PyRun_SimpleString("sys.path.append(distutils.sysconfig.get_python_lib(1,0)) \n");
170 if (PyRun_SimpleString("from unboundmodule import *\n") < 0)
172 log_err("pythonmod: cannot initialize core module: unboundmodule.py");
173 PyGILState_Release(gil);
177 /* Check Python file load */
178 if ((script_py = fopen(pe->fname, "r")) == NULL)
180 log_err("pythonmod: can't open file %s for reading", pe->fname);
181 PyGILState_Release(gil);
186 pe->module = PyImport_AddModule("__main__");
187 pe->dict = PyModule_GetDict(pe->module);
190 PyModule_AddObject(pe->module, "mod_env", pe->data);
192 /* TODO: deallocation of pe->... if an error occurs */
194 if (PyRun_SimpleFile(script_py, pe->fname) < 0)
196 log_err("pythonmod: can't parse Python script %s", pe->fname);
197 PyGILState_Release(gil);
203 if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
206 if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
208 log_err("pythonmod: function init is missing in %s", pe->fname);
209 PyGILState_Release(gil);
213 if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
215 log_err("pythonmod: function deinit is missing in %s", pe->fname);
216 PyGILState_Release(gil);
219 if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL)
221 log_err("pythonmod: function operate is missing in %s", pe->fname);
222 PyGILState_Release(gil);
225 if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL)
227 log_err("pythonmod: function inform_super is missing in %s", pe->fname);
228 PyGILState_Release(gil);
234 py_init_arg = SWIG_NewPointerObj((void*) env, SWIGTYPE_p_module_env, 0);
238 py_init_arg = SWIG_NewPointerObj((void*) env->cfg,
239 SWIGTYPE_p_config_file, 0);
241 res = PyObject_CallFunction(pe->func_init, "iO", id, py_init_arg);
242 if (PyErr_Occurred())
244 log_err("pythonmod: Exception occurred in function init");
247 Py_XDECREF(py_init_arg);
248 PyGILState_Release(gil);
253 Py_XDECREF(py_init_arg);
254 PyGILState_Release(gil);
259 void pythonmod_deinit(struct module_env* env, int id)
261 struct pythonmod_env* pe = env->modinfo[id];
265 /* Free Python resources */
266 if(pe->module != NULL)
269 PyGILState_STATE gil = PyGILState_Ensure();
272 res = PyObject_CallFunction(pe->func_deinit, "i", id);
273 if (PyErr_Occurred()) {
274 log_err("pythonmod: Exception occurred in function deinit");
277 /* Free result if any */
279 /* Free shared data if any */
280 Py_XDECREF(pe->data);
281 PyGILState_Release(gil);
283 PyEval_RestoreThread(pe->mainthr);
290 /* Module is deallocated in Python */
291 env->modinfo[id] = NULL;
294 void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super)
296 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
297 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
298 PyObject* py_qstate, *py_sqstate, *res;
299 PyGILState_STATE gil = PyGILState_Ensure();
301 log_query_info(VERB_ALGO, "pythonmod: inform_super, sub is", &qstate->qinfo);
302 log_query_info(VERB_ALGO, "super is", &super->qinfo);
304 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
305 py_sqstate = SWIG_NewPointerObj((void*) super, SWIGTYPE_p_module_qstate, 0);
307 res = PyObject_CallFunction(pe->func_inform, "iOOO", id, py_qstate,
308 py_sqstate, pq->data);
310 if (PyErr_Occurred())
312 log_err("pythonmod: Exception occurred in function inform_super");
314 qstate->ext_state[id] = module_error;
316 else if ((res == NULL) || (!PyObject_IsTrue(res)))
318 log_err("pythonmod: python returned bad code in inform_super");
319 qstate->ext_state[id] = module_error;
323 Py_XDECREF(py_sqstate);
324 Py_XDECREF(py_qstate);
326 PyGILState_Release(gil);
329 void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
330 int id, struct outbound_entry* ATTR_UNUSED(outbound))
332 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
333 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
334 PyObject* py_qstate, *res;
335 PyGILState_STATE gil = PyGILState_Ensure();
340 pq = qstate->minfo[id] = malloc(sizeof(struct pythonmod_qstate));
342 /* Initialize per query data */
348 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
349 res = PyObject_CallFunction(pe->func_operate, "iiOO", id, (int) event,
350 py_qstate, pq->data);
351 if (PyErr_Occurred())
353 log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
355 qstate->ext_state[id] = module_error;
357 else if ((res == NULL) || (!PyObject_IsTrue(res)))
359 log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event));
360 qstate->ext_state[id] = module_error;
363 Py_XDECREF(py_qstate);
365 PyGILState_Release(gil);
368 void pythonmod_clear(struct module_qstate* qstate, int id)
370 struct pythonmod_qstate* pq;
374 pq = (struct pythonmod_qstate*)qstate->minfo[id];
375 verbose(VERB_ALGO, "pythonmod: clear, id: %d, pq:%lX", id,
376 (unsigned long int)pq);
379 PyGILState_STATE gil = PyGILState_Ensure();
381 PyGILState_Release(gil);
386 qstate->minfo[id] = NULL;
389 size_t pythonmod_get_mem(struct module_env* env, int id)
391 struct pythonmod_env* pe = (struct pythonmod_env*)env->modinfo[id];
392 verbose(VERB_ALGO, "pythonmod: get_mem, id: %d, pe:%lX", id,
393 (unsigned long int)pe);
400 * The module function block
402 static struct module_func_block pythonmod_block = {
404 &pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super,
405 &pythonmod_clear, &pythonmod_get_mem
408 struct module_func_block* pythonmod_get_funcblock(void)
410 return &pythonmod_block;