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