]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - pythonmod/pythonmod.c
Vendor import of Unbound 1.6.4.
[FreeBSD/FreeBSD.git] / pythonmod / pythonmod.c
1 /*
2  * pythonmod.c: unbound module C wrapper
3  *
4  * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
5  *                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)
6  *
7  * This software is open source.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *    * Redistributions of source code must retain the above copyright notice,
14  *      this list of conditions and the following disclaimer.
15  *
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.
19  *
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.
23  *
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.
35  */
36 /**
37  * \file
38  * Python module for unbound.  Calls python script.
39  */
40
41 /* ignore the varargs unused warning from SWIGs internal vararg support */
42 #ifdef __GNUC__
43 #pragma GCC diagnostic ignored "-Wunused-parameter"
44 #ifndef __clang__
45 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
46 #endif
47 #endif
48
49 #include "config.h"
50 #include "sldns/sbuffer.h"
51
52 #undef _POSIX_C_SOURCE
53 #undef _XOPEN_SOURCE
54 #include <Python.h>
55
56 #include "pythonmod/pythonmod.h"
57 #include "util/module.h"
58 #include "util/config_file.h"
59 #include "pythonmod_utils.h"
60
61 #ifdef S_SPLINT_S
62 typedef struct PyObject PyObject;
63 typedef struct PyThreadState PyThreadState;
64 typedef void* PyGILState_STATE;
65 #endif
66
67 /**
68  * Global state for the module.
69  */
70 struct pythonmod_env {
71
72         /** Python script filename. */
73         const char* fname;
74
75         /** Python main thread */
76         PyThreadState* mainthr;
77         /** Python module. */
78         PyObject* module;
79
80         /** Module init function */
81         PyObject* func_init;
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;
88
89         /** Python dictionary. */
90         PyObject* dict;
91
92         /** Module data. */
93         PyObject* data;
94
95         /** Module qstate. */
96         struct module_qstate* qstate;
97 };
98
99 /**
100  * Per query state for the iterator module.
101  */
102 struct pythonmod_qstate {
103
104         /** Module per query data. */
105         PyObject* data;
106 };
107
108 /* Generated */
109 #ifndef S_SPLINT_S
110 #include "pythonmod/interface.h"
111 #endif
112
113 int pythonmod_init(struct module_env* env, int id)
114 {
115    /* Initialize module */
116    FILE* script_py = NULL;
117    PyObject* py_init_arg, *res;
118    PyGILState_STATE gil;
119    int init_standard = 1;
120
121    struct pythonmod_env* pe = (struct pythonmod_env*)calloc(1, sizeof(struct pythonmod_env));
122    if (!pe)
123    {
124       log_err("pythonmod: malloc failure");
125       return 0;
126    }
127
128    env->modinfo[id] = (void*) pe;
129
130    /* Initialize module */
131    pe->fname = env->cfg->python_script;
132    if(pe->fname==NULL || pe->fname[0]==0) {
133       log_err("pythonmod: no script given.");
134       return 0;
135    }
136
137    /* Initialize Python libraries */
138    if (!Py_IsInitialized())
139    {
140 #if PY_MAJOR_VERSION >= 3
141       wchar_t progname[8];
142       mbstowcs(progname, "unbound", 8);
143 #else
144       char *progname = "unbound";
145 #endif
146       Py_SetProgramName(progname);
147       Py_NoSiteFlag = 1;
148 #if PY_MAJOR_VERSION >= 3
149       PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
150 #endif
151       Py_Initialize();
152       PyEval_InitThreads();
153       SWIG_init();
154       pe->mainthr = PyEval_SaveThread();
155    }
156
157    gil = PyGILState_Ensure();
158
159    /* Initialize Python */
160    PyRun_SimpleString("import sys \n");
161    PyRun_SimpleString("sys.path.append('.') \n");
162    if(env->cfg->directory && env->cfg->directory[0]) {
163       char wdir[1524];
164       snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
165       env->cfg->directory);
166       PyRun_SimpleString(wdir);
167    }
168    PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n");
169    PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n");
170    PyRun_SimpleString("import distutils.sysconfig \n");
171    PyRun_SimpleString("sys.path.append(distutils.sysconfig.get_python_lib(1,0)) \n");
172    if (PyRun_SimpleString("from unboundmodule import *\n") < 0)
173    {
174       log_err("pythonmod: cannot initialize core module: unboundmodule.py");
175       PyGILState_Release(gil);
176       return 0;
177    }
178
179    /* Check Python file load */
180    if ((script_py = fopen(pe->fname, "r")) == NULL)
181    {
182       log_err("pythonmod: can't open file %s for reading", pe->fname);
183       PyGILState_Release(gil);
184       return 0;
185    }
186
187    /* Load file */
188    pe->module = PyImport_AddModule("__main__");
189    pe->dict = PyModule_GetDict(pe->module);
190    pe->data = Py_None;
191    Py_INCREF(pe->data);
192    PyModule_AddObject(pe->module, "mod_env", pe->data);
193
194    /* TODO: deallocation of pe->... if an error occurs */
195
196    if (PyRun_SimpleFile(script_py, pe->fname) < 0)
197    {
198       log_err("pythonmod: can't parse Python script %s", pe->fname);
199       PyGILState_Release(gil);
200       return 0;
201    }
202
203    fclose(script_py);
204
205    if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
206    {
207       init_standard = 0;
208       if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
209       {
210          log_err("pythonmod: function init is missing in %s", pe->fname);
211          PyGILState_Release(gil);
212          return 0;
213       }
214    }
215    if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
216    {
217       log_err("pythonmod: function deinit is missing in %s", pe->fname);
218       PyGILState_Release(gil);
219       return 0;
220    }
221    if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL)
222    {
223       log_err("pythonmod: function operate is missing in %s", pe->fname);
224       PyGILState_Release(gil);
225       return 0;
226    }
227    if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL)
228    {
229       log_err("pythonmod: function inform_super is missing in %s", pe->fname);
230       PyGILState_Release(gil);
231       return 0;
232    }
233
234    if (init_standard)
235    {
236       py_init_arg = SWIG_NewPointerObj((void*) env, SWIGTYPE_p_module_env, 0);
237    }
238    else
239    {
240       py_init_arg = SWIG_NewPointerObj((void*) env->cfg,
241         SWIGTYPE_p_config_file, 0);
242    }
243    res = PyObject_CallFunction(pe->func_init, "iO", id, py_init_arg);
244    if (PyErr_Occurred())
245    {
246       log_err("pythonmod: Exception occurred in function init");
247       PyErr_Print();
248       Py_XDECREF(res);
249       Py_XDECREF(py_init_arg);
250       PyGILState_Release(gil);
251       return 0;
252    }
253
254    Py_XDECREF(res);
255    Py_XDECREF(py_init_arg);
256    PyGILState_Release(gil);
257
258    return 1;
259 }
260
261 void pythonmod_deinit(struct module_env* env, int id)
262 {
263    struct pythonmod_env* pe = env->modinfo[id];
264    if(pe == NULL)
265       return;
266
267    /* Free Python resources */
268    if(pe->module != NULL)
269    {
270       PyObject* res;
271       PyGILState_STATE gil = PyGILState_Ensure();
272
273       /* Deinit module */
274       res = PyObject_CallFunction(pe->func_deinit, "i", id);
275       if (PyErr_Occurred()) {
276          log_err("pythonmod: Exception occurred in function deinit");
277          PyErr_Print();
278       }
279       /* Free result if any */
280       Py_XDECREF(res);
281       /* Free shared data if any */
282       Py_XDECREF(pe->data);
283       PyGILState_Release(gil);
284
285       PyEval_RestoreThread(pe->mainthr);
286       Py_Finalize();
287       pe->mainthr = NULL;
288    }
289    pe->fname = NULL;
290    free(pe);
291
292    /* Module is deallocated in Python */
293    env->modinfo[id] = NULL;
294 }
295
296 void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super)
297 {
298    struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
299    struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
300    PyObject* py_qstate, *py_sqstate, *res;
301    PyGILState_STATE gil = PyGILState_Ensure();
302
303    log_query_info(VERB_ALGO, "pythonmod: inform_super, sub is", &qstate->qinfo);
304    log_query_info(VERB_ALGO, "super is", &super->qinfo);
305
306    py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
307    py_sqstate = SWIG_NewPointerObj((void*) super, SWIGTYPE_p_module_qstate, 0);
308
309    res = PyObject_CallFunction(pe->func_inform, "iOOO", id, py_qstate,
310         py_sqstate, pq->data);
311
312    if (PyErr_Occurred())
313    {
314       log_err("pythonmod: Exception occurred in function inform_super");
315       PyErr_Print();
316       qstate->ext_state[id] = module_error;
317    }
318    else if ((res == NULL)  || (!PyObject_IsTrue(res)))
319    {
320       log_err("pythonmod: python returned bad code in inform_super");
321       qstate->ext_state[id] = module_error;
322    }
323
324    Py_XDECREF(res);
325    Py_XDECREF(py_sqstate);
326    Py_XDECREF(py_qstate);
327
328    PyGILState_Release(gil);
329 }
330
331 void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
332         int id, struct outbound_entry* ATTR_UNUSED(outbound))
333 {
334    struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
335    struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
336    PyObject* py_qstate, *res;
337    PyGILState_STATE gil = PyGILState_Ensure();
338
339    if ( pq == NULL)
340    {
341       /* create qstate */
342       pq = qstate->minfo[id] = malloc(sizeof(struct pythonmod_qstate));
343
344       /* Initialize per query data */
345       pq->data = Py_None;
346       Py_INCREF(pq->data);
347    }
348
349    /* Call operate */
350    py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
351    res = PyObject_CallFunction(pe->func_operate, "iiOO", id, (int) event,
352         py_qstate, pq->data);
353    if (PyErr_Occurred())
354    {
355       log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
356       PyErr_Print();
357       qstate->ext_state[id] = module_error;
358    }
359    else if ((res == NULL)  || (!PyObject_IsTrue(res)))
360    {
361       log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event));
362       qstate->ext_state[id] = module_error;
363    }
364    Py_XDECREF(res);
365    Py_XDECREF(py_qstate);
366
367    PyGILState_Release(gil);
368 }
369
370 void pythonmod_clear(struct module_qstate* qstate, int id)
371 {
372    struct pythonmod_qstate* pq;
373    if (qstate == NULL)
374       return;
375
376    pq = (struct pythonmod_qstate*)qstate->minfo[id];
377    verbose(VERB_ALGO, "pythonmod: clear, id: %d, pq:%lX", id,
378         (unsigned long int)pq);
379    if(pq != NULL)
380    {
381       PyGILState_STATE gil = PyGILState_Ensure();
382       Py_DECREF(pq->data);
383       PyGILState_Release(gil);
384       /* Free qstate */
385       free(pq);
386    }
387
388    qstate->minfo[id] = NULL;
389 }
390
391 size_t pythonmod_get_mem(struct module_env* env, int id)
392 {
393    struct pythonmod_env* pe = (struct pythonmod_env*)env->modinfo[id];
394    verbose(VERB_ALGO, "pythonmod: get_mem, id: %d, pe:%lX", id,
395         (unsigned long int)pe);
396    if(!pe)
397       return 0;
398    return sizeof(*pe);
399 }
400
401 /**
402  * The module function block
403  */
404 static struct module_func_block pythonmod_block = {
405    "python",
406    &pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super,
407    &pythonmod_clear, &pythonmod_get_mem
408 };
409
410 struct module_func_block* pythonmod_get_funcblock(void)
411 {
412    return &pythonmod_block;
413 }