xref: /netbsd-src/external/bsd/unbound/dist/pythonmod/pythonmod.c (revision f31867506b3d03104824848de4007d9c967e81b2)
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       Py_NoSiteFlag = 1;
360 #if PY_MAJOR_VERSION >= 3
361       PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
362 #endif
363 #if PY_VERSION_HEX < 0x03080000
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 }
788