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