]> git.ipfire.org Git - thirdparty/unbound.git/blob - pythonmod/pythonmod.c
Py_NoSiteFlag is not needed since Python 3.8
[thirdparty/unbound.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 * counter for python module instances
69 * incremented by pythonmod_init(...)
70 */
71 int py_mod_count = 0;
72
73 /** Python main thread */
74 PyThreadState* mainthr;
75
76 /**
77 * Global state for the module.
78 */
79 struct pythonmod_env {
80
81 /** Python script filename. */
82 const char* fname;
83
84 /** Python module. */
85 PyObject* module;
86
87 /** Module init function */
88 PyObject* func_init;
89 /** Module deinit function */
90 PyObject* func_deinit;
91 /** Module operate function */
92 PyObject* func_operate;
93 /** Module super_inform function */
94 PyObject* func_inform;
95
96 /** Python dictionary. */
97 PyObject* dict;
98
99 /** Module data. */
100 PyObject* data;
101
102 /** Module qstate. */
103 struct module_qstate* qstate;
104 };
105
106 /**
107 * Per query state for the iterator module.
108 */
109 struct pythonmod_qstate {
110
111 /** Module per query data. */
112 PyObject* data;
113 };
114
115 /* The dict from __main__ could have remnants from a previous script
116 * invocation, in a multi python module setup. Usually this is fine since newer
117 * scripts will update their values. The obvious erroneous case is when mixing
118 * python scripts that make use of both 'init' and 'init_standard'. This
119 * results in 'init_standard' to persist on following scripts that don't use it
120 * (thus not replacing it). This is also problematic in case where a script
121 * does not define a required function but a previously loaded script did. The
122 * current solution is to make sure to clean offensive remnants that influence
123 * further parsing of the individual scripts.
124 */
125 static void
126 clean_python_function_objects(PyObject* dict) {
127 const char* function_names[] = {
128 "init",
129 "init_standard",
130 "deinit",
131 "operate",
132 "inform_super"
133 };
134 size_t i;
135
136 for(i=0; i<sizeof(function_names)/sizeof(function_names[0]); i++) {
137 if(PyDict_GetItemString(dict, function_names[i]) != NULL) {
138 PyDict_DelItemString(dict, function_names[i]);
139 }
140 }
141 };
142
143 /* Generated */
144 #ifndef S_SPLINT_S
145 #include "pythonmod/interface.h"
146 #endif
147
148 /** log python error */
149 static void
150 log_py_err(void)
151 {
152 char *result = NULL;
153 const char* iomod = "cStringIO";
154 PyObject *modStringIO = NULL;
155 PyObject *modTB = NULL;
156 PyObject *obFuncStringIO = NULL;
157 PyObject *obStringIO = NULL;
158 PyObject *obFuncTB = NULL;
159 PyObject *argsTB = NULL;
160 PyObject *obResult = NULL;
161 PyObject *ascstr = NULL;
162 PyObject *exc_typ, *exc_val, *exc_tb;
163
164 /* Fetch the error state now before we cruch it */
165 /* exc val contains the error message
166 * exc tb contains stack traceback and other info. */
167 PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
168 PyErr_NormalizeException(&exc_typ, &exc_val, &exc_tb);
169
170 /* Import the modules we need - cStringIO and traceback */
171 modStringIO = PyImport_ImportModule("cStringIO");
172 if (modStringIO==NULL) {
173 /* python 1.4 and before */
174 modStringIO = PyImport_ImportModule("StringIO");
175 iomod = "StringIO";
176 }
177 if (modStringIO==NULL) {
178 /* python 3 */
179 modStringIO = PyImport_ImportModule("io");
180 iomod = "io";
181 }
182 if (modStringIO==NULL) {
183 log_err("pythonmod: cannot print exception, "
184 "cannot ImportModule cStringIO or StringIO or io");
185 goto cleanup;
186 }
187 modTB = PyImport_ImportModule("traceback");
188 if (modTB==NULL) {
189 log_err("pythonmod: cannot print exception, "
190 "cannot ImportModule traceback");
191 goto cleanup;
192 }
193
194 /* Construct a cStringIO object */
195 obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
196 if (obFuncStringIO==NULL) {
197 log_err("pythonmod: cannot print exception, "
198 "cannot GetAttrString %s.StringIO", iomod);
199 goto cleanup;
200 }
201 obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
202 if (obStringIO==NULL) {
203 log_err("pythonmod: cannot print exception, "
204 "cannot call %s.StringIO()", iomod);
205 goto cleanup;
206 }
207
208 /* Get the traceback.print_exception function, and call it. */
209 obFuncTB = PyObject_GetAttrString(modTB, "print_exception");
210 if (obFuncTB==NULL) {
211 log_err("pythonmod: cannot print exception, "
212 "cannot GetAttrString traceback.print_exception");
213 goto cleanup;
214 }
215 argsTB = Py_BuildValue("OOOOO", (exc_typ ? exc_typ : Py_None),
216 (exc_val ? exc_val : Py_None), (exc_tb ? exc_tb : Py_None),
217 Py_None, obStringIO);
218 if (argsTB==NULL) {
219 log_err("pythonmod: cannot print exception, "
220 "cannot BuildValue for print_exception");
221 goto cleanup;
222 }
223
224 obResult = PyObject_CallObject(obFuncTB, argsTB);
225 if (obResult==NULL) {
226 PyErr_Print();
227 log_err("pythonmod: cannot print exception, "
228 "call traceback.print_exception() failed");
229 goto cleanup;
230 }
231
232 /* Now call the getvalue() method in the StringIO instance */
233 Py_DECREF(obFuncStringIO);
234 obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
235 if (obFuncStringIO==NULL) {
236 log_err("pythonmod: cannot print exception, "
237 "cannot GetAttrString StringIO.getvalue");
238 goto cleanup;
239 }
240 Py_DECREF(obResult);
241 obResult = PyObject_CallObject(obFuncStringIO, NULL);
242 if (obResult==NULL) {
243 log_err("pythonmod: cannot print exception, "
244 "call StringIO.getvalue() failed");
245 goto cleanup;
246 }
247
248 /* And it should be a string all ready to go - duplicate it. */
249 if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
250 log_err("pythonmod: cannot print exception, "
251 "StringIO.getvalue() result did not String_Check"
252 " or Unicode_Check");
253 goto cleanup;
254 }
255 if(PyString_Check(obResult)) {
256 result = PyString_AsString(obResult);
257 } else {
258 ascstr = PyUnicode_AsASCIIString(obResult);
259 result = PyBytes_AsString(ascstr);
260 }
261 log_err("pythonmod: python error: %s", result);
262
263 cleanup:
264 Py_XDECREF(modStringIO);
265 Py_XDECREF(modTB);
266 Py_XDECREF(obFuncStringIO);
267 Py_XDECREF(obStringIO);
268 Py_XDECREF(obFuncTB);
269 Py_XDECREF(argsTB);
270 Py_XDECREF(obResult);
271 Py_XDECREF(ascstr);
272
273 /* clear the exception, by not restoring it */
274 /* Restore the exception state */
275 /* PyErr_Restore(exc_typ, exc_val, exc_tb); */
276 /* when using PyErr_Restore there is no need to Py_XDECREF for
277 * these 3 pointers. */
278 Py_XDECREF(exc_typ);
279 Py_XDECREF(exc_val);
280 Py_XDECREF(exc_tb);
281 }
282
283 /* we only want to unwind Python once at exit */
284 static void
285 pythonmod_atexit(void)
286 {
287 log_assert(py_mod_count == 0);
288 log_assert(mainthr != NULL);
289
290 PyEval_RestoreThread(mainthr);
291 Py_Finalize();
292 }
293
294 int pythonmod_init(struct module_env* env, int id)
295 {
296 int py_mod_idx = py_mod_count++;
297
298 /* Initialize module */
299 FILE* script_py = NULL;
300 PyObject* py_init_arg = NULL, *res = NULL, *fname = NULL;
301 PyGILState_STATE gil;
302 int init_standard = 1, i = 0;
303 #if PY_MAJOR_VERSION < 3
304 PyObject* PyFileObject = NULL;
305 #endif
306 struct config_strlist* cfg_item = env->cfg->python_script;
307
308 struct pythonmod_env* pe = (struct pythonmod_env*)calloc(1, sizeof(struct pythonmod_env));
309 if (!pe)
310 {
311 log_err("pythonmod: malloc failure");
312 return 0;
313 }
314
315 env->modinfo[id] = (void*) pe;
316
317 /* Initialize module */
318 pe->fname=NULL; i = 0;
319 while (cfg_item!=NULL) {
320 if (py_mod_idx==i++) {
321 pe->fname=cfg_item->str;
322 break;
323 }
324 cfg_item = cfg_item->next;
325 }
326 if(pe->fname==NULL || pe->fname[0]==0) {
327 log_err("pythonmod[%d]: no script given.", py_mod_idx);
328 return 0;
329 }
330
331 /* Initialize Python libraries */
332 if (py_mod_count==1 && !Py_IsInitialized())
333 {
334 #if PY_VERSION_HEX >= 0x03080000
335 PyStatus status;
336 PyPreConfig preconfig;
337 PyConfig config;
338 #endif
339 #if PY_MAJOR_VERSION >= 3
340 wchar_t progname[8];
341 mbstowcs(progname, "unbound", 8);
342 #else
343 char *progname = "unbound";
344 #endif
345 #if PY_VERSION_HEX < 0x03080000
346 Py_SetProgramName(progname);
347 #else
348 /* Python must be preinitialized, before the PyImport_AppendInittab
349 * call. */
350 PyPreConfig_InitPythonConfig(&preconfig);
351 status = Py_PreInitialize(&preconfig);
352 if(PyStatus_Exception(status)) {
353 log_err("python exception in Py_PreInitialize: %s%s%s",
354 (status.func?status.func:""), (status.func?": ":""),
355 (status.err_msg?status.err_msg:""));
356 return 0;
357 }
358 #endif
359 #if PY_MAJOR_VERSION >= 3
360 PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
361 #endif
362 #if PY_VERSION_HEX < 0x03080000
363 Py_NoSiteFlag = 1;
364 Py_Initialize();
365 #else
366 PyConfig_InitPythonConfig(&config);
367 status = PyConfig_SetString(&config, &config.program_name, progname);
368 if(PyStatus_Exception(status)) {
369 log_err("python exception in PyConfig_SetString(.. program_name ..): %s%s%s",
370 (status.func?status.func:""), (status.func?": ":""),
371 (status.err_msg?status.err_msg:""));
372 PyConfig_Clear(&config);
373 return 0;
374 }
375 config.site_import = 0;
376 status = Py_InitializeFromConfig(&config);
377 if(PyStatus_Exception(status)) {
378 log_err("python exception in Py_InitializeFromConfig: %s%s%s",
379 (status.func?status.func:""), (status.func?": ":""),
380 (status.err_msg?status.err_msg:""));
381 PyConfig_Clear(&config);
382 return 0;
383 }
384 PyConfig_Clear(&config);
385 #endif
386 #if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION <= 6)
387 /* initthreads only for python 3.6 and older */
388 PyEval_InitThreads();
389 #endif
390 SWIG_init();
391 mainthr = PyEval_SaveThread();
392
393 /* register callback to unwind Python at exit */
394 atexit(pythonmod_atexit);
395 }
396
397 gil = PyGILState_Ensure();
398
399 if (py_mod_count==1) {
400 /* Initialize Python */
401 if(PyRun_SimpleString("import sys \n") < 0 ) {
402 log_err("pythonmod: cannot initialize core module: unboundmodule.py");
403 goto python_init_fail;
404 }
405 PyRun_SimpleString("sys.path.append('.') \n");
406 PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n");
407 PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n");
408 if(env->cfg->directory && env->cfg->directory[0]) {
409 char wdir[1524];
410 snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
411 env->cfg->directory);
412 PyRun_SimpleString(wdir);
413 }
414 if(PyRun_SimpleString("import site\n") < 0) {
415 log_err("pythonmod: cannot initialize core module: unboundmodule.py");
416 goto python_init_fail;
417 }
418 if(PyRun_SimpleString("sys.path.extend(site.getsitepackages())\n") < 0) {
419 log_err("pythonmod: cannot initialize core module: unboundmodule.py");
420 goto python_init_fail;
421 }
422 if(PyRun_SimpleString("from unboundmodule import *\n") < 0)
423 {
424 log_err("pythonmod: cannot initialize core module: unboundmodule.py");
425 goto python_init_fail;
426 }
427 }
428
429 /* Check Python file load */
430 /* uses python to open the file, this works on other platforms,
431 * eg. Windows, to open the file in the correct mode for python */
432 #if PY_MAJOR_VERSION < 3
433 PyFileObject = PyFile_FromString((char*)pe->fname, "r");
434 script_py = PyFile_AsFile(PyFileObject);
435 #else
436 script_py = fopen(pe->fname, "r");
437 #endif
438 if (script_py == NULL)
439 {
440 log_err("pythonmod: can't open file %s for reading", pe->fname);
441 goto python_init_fail;
442 }
443
444 /* Load file */
445 pe->module = PyImport_AddModule("__main__");
446 Py_XINCREF(pe->module);
447 pe->dict = PyModule_GetDict(pe->module);
448 Py_XINCREF(pe->dict);
449 clean_python_function_objects(pe->dict);
450
451 pe->data = PyDict_New();
452 /* add the script filename to the global "mod_env" for trivial access */
453 fname = PyString_FromString(pe->fname);
454 if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
455 log_err("pythonmod: could not add item to dictionary");
456 Py_XDECREF(fname);
457 goto python_init_fail;
458 }
459 Py_XDECREF(fname);
460 Py_XINCREF(pe->data); /* reference will be stolen below */
461 if(PyModule_AddObject(pe->module, "mod_env", pe->data) < 0) {
462 log_err("pythonmod: could not add mod_env object");
463 Py_XDECREF(pe->data); /* 2 times, here and on python_init_fail; */
464 /* on failure the reference is not stolen */
465 goto python_init_fail;
466 }
467
468 if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
469 #if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
470 /* for python before 3.9 */
471 log_err("pythonmod: can't parse Python script %s", pe->fname);
472 /* print the error to logs too, run it again */
473 fseek(script_py, 0, SEEK_SET);
474 /* we don't run the file, like this, because then side-effects
475 * s = PyRun_File(script_py, pe->fname, Py_file_input,
476 * PyModule_GetDict(PyImport_AddModule("__main__")), pe->dict);
477 * could happen (again). Instead we parse the file again to get
478 * the error string in the logs, for when the daemon has stderr
479 * removed. SimpleFile run already printed to stderr, for then
480 * this is called from unbound-checkconf or unbound -dd the user
481 * has a nice formatted error.
482 */
483 /* ignore the NULL return of _node, it is NULL due to the parse failure
484 * that we are expecting */
485 (void)PyParser_SimpleParseFile(script_py, pe->fname, Py_file_input);
486 #else
487 /* for python 3.9 and newer */
488 char* fstr = NULL;
489 size_t flen = 0;
490 log_err("pythonmod: can't parse Python script %s", pe->fname);
491 /* print the error to logs too, run it again */
492 fseek(script_py, 0, SEEK_END);
493 flen = (size_t)ftell(script_py);
494 fstr = malloc(flen+1);
495 if(!fstr) {
496 log_err("malloc failure to print parse error");
497
498 /* close the file */
499 #if PY_MAJOR_VERSION < 3
500 Py_XDECREF(PyFileObject);
501 #else
502 fclose(script_py);
503 #endif
504
505 goto python_init_fail;
506 }
507 fseek(script_py, 0, SEEK_SET);
508 if(fread(fstr, flen, 1, script_py) < 1) {
509 log_err("file read failed to print parse error: %s: %s",
510 pe->fname, strerror(errno));
511 free(fstr);
512
513 /* close the file */
514 #if PY_MAJOR_VERSION < 3
515 Py_XDECREF(PyFileObject);
516 #else
517 fclose(script_py);
518 #endif
519
520 goto python_init_fail;
521 }
522 fstr[flen] = 0;
523 /* we compile the string, but do not run it, to stop side-effects */
524 /* ignore the NULL return of _node, it is NULL due to the parse failure
525 * that we are expecting */
526 (void)Py_CompileString(fstr, pe->fname, Py_file_input);
527 #endif
528
529 log_py_err();
530
531 /* close the file */
532 #if PY_MAJOR_VERSION < 3
533 Py_XDECREF(PyFileObject);
534 #else
535 fclose(script_py);
536 #endif
537
538 #if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
539 /* no cleanup needed for python before 3.9 */
540 #else
541 /* cleanup for python 3.9 and newer */
542 free(fstr);
543 #endif
544 goto python_init_fail;
545 }
546
547 /* close the file */
548 #if PY_MAJOR_VERSION < 3
549 Py_XDECREF(PyFileObject);
550 #else
551 fclose(script_py);
552 #endif
553
554 if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
555 {
556 init_standard = 0;
557 if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
558 {
559 log_err("pythonmod: function init is missing in %s", pe->fname);
560 goto python_init_fail;
561 }
562 }
563 Py_XINCREF(pe->func_init);
564 if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
565 {
566 log_err("pythonmod: function deinit is missing in %s", pe->fname);
567 goto python_init_fail;
568 }
569 Py_XINCREF(pe->func_deinit);
570 if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL)
571 {
572 log_err("pythonmod: function operate is missing in %s", pe->fname);
573 goto python_init_fail;
574 }
575 Py_XINCREF(pe->func_operate);
576 if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL)
577 {
578 log_err("pythonmod: function inform_super is missing in %s", pe->fname);
579 goto python_init_fail;
580 }
581 Py_XINCREF(pe->func_inform);
582
583 if (init_standard)
584 {
585 py_init_arg = SWIG_NewPointerObj((void*) env, SWIGTYPE_p_module_env, 0);
586 }
587 else
588 {
589 py_init_arg = SWIG_NewPointerObj((void*) env->cfg,
590 SWIGTYPE_p_config_file, 0);
591 }
592 res = PyObject_CallFunction(pe->func_init, "iO", id, py_init_arg);
593 if (PyErr_Occurred())
594 {
595 log_err("pythonmod: Exception occurred in function init");
596 log_py_err();
597 goto python_init_fail;
598 }
599
600 Py_XDECREF(res);
601 Py_XDECREF(py_init_arg);
602 PyGILState_Release(gil);
603 return 1;
604
605 python_init_fail:
606 Py_XDECREF(pe->module);
607 Py_XDECREF(pe->dict);
608 Py_XDECREF(pe->data);
609 Py_XDECREF(pe->func_init);
610 Py_XDECREF(pe->func_deinit);
611 Py_XDECREF(pe->func_operate);
612 Py_XDECREF(pe->func_inform);
613 Py_XDECREF(res);
614 Py_XDECREF(py_init_arg);
615 PyGILState_Release(gil);
616 return 0;
617 }
618
619 void pythonmod_deinit(struct module_env* env, int id)
620 {
621 int cbtype;
622 struct pythonmod_env* pe = env->modinfo[id];
623 if(pe == NULL)
624 return;
625
626 /* Free Python resources */
627 if(pe->module != NULL)
628 {
629 PyObject* res;
630 PyGILState_STATE gil = PyGILState_Ensure();
631
632 /* Deinit module */
633 res = PyObject_CallFunction(pe->func_deinit, "i", id);
634 if (PyErr_Occurred()) {
635 log_err("pythonmod: Exception occurred in function deinit");
636 log_py_err();
637 }
638 /* Free result if any */
639 Py_XDECREF(res);
640 /* Free shared data if any */
641 Py_XDECREF(pe->module);
642 Py_XDECREF(pe->dict);
643 Py_XDECREF(pe->data);
644 Py_XDECREF(pe->func_init);
645 Py_XDECREF(pe->func_deinit);
646 Py_XDECREF(pe->func_inform);
647 Py_XDECREF(pe->func_operate);
648 PyGILState_Release(gil);
649
650 py_mod_count--;
651 }
652 pe->fname = NULL;
653 free(pe);
654
655 /* iterate over all possible callback types and clean up each in turn */
656 for (cbtype = 0; cbtype < inplace_cb_types_total; cbtype++)
657 inplace_cb_delete(env, cbtype, id);
658
659 /* Module is deallocated in Python */
660 env->modinfo[id] = NULL;
661 }
662
663 void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super)
664 {
665 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
666 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
667 PyObject* py_qstate, *py_sqstate, *res;
668 PyGILState_STATE gil = PyGILState_Ensure();
669
670 log_query_info(VERB_ALGO, "pythonmod: inform_super, sub is", &qstate->qinfo);
671 log_query_info(VERB_ALGO, "super is", &super->qinfo);
672
673 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
674 py_sqstate = SWIG_NewPointerObj((void*) super, SWIGTYPE_p_module_qstate, 0);
675
676 res = PyObject_CallFunction(pe->func_inform, "iOOO", id, py_qstate,
677 py_sqstate, pq->data);
678
679 if (PyErr_Occurred())
680 {
681 log_err("pythonmod: Exception occurred in function inform_super");
682 log_py_err();
683 qstate->ext_state[id] = module_error;
684 }
685 else if ((res == NULL) || (!PyObject_IsTrue(res)))
686 {
687 log_err("pythonmod: python returned bad code in inform_super");
688 qstate->ext_state[id] = module_error;
689 }
690
691 Py_XDECREF(res);
692 Py_XDECREF(py_sqstate);
693 Py_XDECREF(py_qstate);
694
695 PyGILState_Release(gil);
696 }
697
698 void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
699 int id, struct outbound_entry* ATTR_UNUSED(outbound))
700 {
701 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
702 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
703 PyObject* py_qstate, *res;
704 PyGILState_STATE gil = PyGILState_Ensure();
705
706 if ( pq == NULL)
707 {
708 /* create qstate */
709 pq = qstate->minfo[id] = malloc(sizeof(struct pythonmod_qstate));
710 if(!pq) {
711 log_err("pythonmod_operate: malloc failure for qstate");
712 PyGILState_Release(gil);
713 return;
714 }
715
716 /* Initialize per query data */
717 pq->data = PyDict_New();
718 if(!pq->data) {
719 log_err("pythonmod_operate: malloc failure for query data dict");
720 PyGILState_Release(gil);
721 return;
722 }
723 }
724
725 /* Call operate */
726 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
727 res = PyObject_CallFunction(pe->func_operate, "iiOO", id, (int) event,
728 py_qstate, pq->data);
729 if (PyErr_Occurred())
730 {
731 log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
732 log_py_err();
733 qstate->ext_state[id] = module_error;
734 }
735 else if ((res == NULL) || (!PyObject_IsTrue(res)))
736 {
737 log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event));
738 qstate->ext_state[id] = module_error;
739 }
740 Py_XDECREF(res);
741 Py_XDECREF(py_qstate);
742
743 PyGILState_Release(gil);
744 }
745
746 void pythonmod_clear(struct module_qstate* qstate, int id)
747 {
748 struct pythonmod_qstate* pq;
749 if (qstate == NULL)
750 return;
751
752 pq = (struct pythonmod_qstate*)qstate->minfo[id];
753 verbose(VERB_ALGO, "pythonmod: clear, id: %d, pq:%p", id, pq);
754 if(pq != NULL)
755 {
756 PyGILState_STATE gil = PyGILState_Ensure();
757 Py_DECREF(pq->data);
758 PyGILState_Release(gil);
759 /* Free qstate */
760 free(pq);
761 }
762
763 qstate->minfo[id] = NULL;
764 }
765
766 size_t pythonmod_get_mem(struct module_env* env, int id)
767 {
768 struct pythonmod_env* pe = (struct pythonmod_env*)env->modinfo[id];
769 verbose(VERB_ALGO, "pythonmod: get_mem, id: %d, pe:%p", id, pe);
770 if(!pe)
771 return 0;
772 return sizeof(*pe);
773 }
774
775 /**
776 * The module function block
777 */
778 static struct module_func_block pythonmod_block = {
779 "python",
780 &pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super,
781 &pythonmod_clear, &pythonmod_get_mem
782 };
783
784 struct module_func_block* pythonmod_get_funcblock(void)
785 {
786 return &pythonmod_block;
787 }