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 } 414