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 "sldns/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 #if PY_MAJOR_VERSION >= 3 137 wchar_t progname[8]; 138 mbstowcs(progname, "unbound", 8); 139 #else 140 char *progname = "unbound"; 141 #endif 142 Py_SetProgramName(progname); 143 Py_NoSiteFlag = 1; 144 #if PY_MAJOR_VERSION >= 3 145 PyImport_AppendInittab(SWIG_name, (void*)SWIG_init); 146 #endif 147 Py_Initialize(); 148 PyEval_InitThreads(); 149 SWIG_init(); 150 pe->mainthr = PyEval_SaveThread(); 151 } 152 153 gil = PyGILState_Ensure(); 154 155 /* Initialize Python */ 156 PyRun_SimpleString("import sys \n"); 157 PyRun_SimpleString("sys.path.append('.') \n"); 158 if(env->cfg->directory && env->cfg->directory[0]) { 159 char wdir[1524]; 160 snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n", 161 env->cfg->directory); 162 PyRun_SimpleString(wdir); 163 } 164 PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n"); 165 PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n"); 166 PyRun_SimpleString("import distutils.sysconfig \n"); 167 PyRun_SimpleString("sys.path.append(distutils.sysconfig.get_python_lib(1,0)) \n"); 168 if (PyRun_SimpleString("from unboundmodule import *\n") < 0) 169 { 170 log_err("pythonmod: cannot initialize core module: unboundmodule.py"); 171 PyGILState_Release(gil); 172 return 0; 173 } 174 175 /* Check Python file load */ 176 if ((script_py = fopen(pe->fname, "r")) == NULL) 177 { 178 log_err("pythonmod: can't open file %s for reading", pe->fname); 179 PyGILState_Release(gil); 180 return 0; 181 } 182 183 /* Load file */ 184 pe->module = PyImport_AddModule("__main__"); 185 pe->dict = PyModule_GetDict(pe->module); 186 pe->data = Py_None; 187 Py_INCREF(pe->data); 188 PyModule_AddObject(pe->module, "mod_env", pe->data); 189 190 /* TODO: deallocation of pe->... if an error occurs */ 191 192 if (PyRun_SimpleFile(script_py, pe->fname) < 0) 193 { 194 log_err("pythonmod: can't parse Python script %s", pe->fname); 195 PyGILState_Release(gil); 196 return 0; 197 } 198 199 fclose(script_py); 200 201 if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL) 202 { 203 log_err("pythonmod: function init is missing in %s", pe->fname); 204 PyGILState_Release(gil); 205 return 0; 206 } 207 if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL) 208 { 209 log_err("pythonmod: function deinit is missing in %s", pe->fname); 210 PyGILState_Release(gil); 211 return 0; 212 } 213 if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL) 214 { 215 log_err("pythonmod: function operate is missing in %s", pe->fname); 216 PyGILState_Release(gil); 217 return 0; 218 } 219 if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL) 220 { 221 log_err("pythonmod: function inform_super is missing in %s", pe->fname); 222 PyGILState_Release(gil); 223 return 0; 224 } 225 226 py_cfg = SWIG_NewPointerObj((void*) env->cfg, SWIGTYPE_p_config_file, 0); 227 res = PyObject_CallFunction(pe->func_init, "iO", id, py_cfg); 228 if (PyErr_Occurred()) 229 { 230 log_err("pythonmod: Exception occurred in function init"); 231 PyErr_Print(); 232 } 233 234 Py_XDECREF(res); 235 Py_XDECREF(py_cfg); 236 PyGILState_Release(gil); 237 238 return 1; 239 } 240 241 void pythonmod_deinit(struct module_env* env, int id) 242 { 243 struct pythonmod_env* pe = env->modinfo[id]; 244 if(pe == NULL) 245 return; 246 247 /* Free Python resources */ 248 if(pe->module != NULL) 249 { 250 PyObject* res; 251 PyGILState_STATE gil = PyGILState_Ensure(); 252 253 /* Deinit module */ 254 res = PyObject_CallFunction(pe->func_deinit, "i", id); 255 if (PyErr_Occurred()) { 256 log_err("pythonmod: Exception occurred in function deinit"); 257 PyErr_Print(); 258 } 259 /* Free result if any */ 260 Py_XDECREF(res); 261 /* Free shared data if any */ 262 Py_XDECREF(pe->data); 263 PyGILState_Release(gil); 264 265 PyEval_RestoreThread(pe->mainthr); 266 Py_Finalize(); 267 pe->mainthr = NULL; 268 } 269 pe->fname = NULL; 270 free(pe); 271 272 /* Module is deallocated in Python */ 273 env->modinfo[id] = NULL; 274 } 275 276 void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super) 277 { 278 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id]; 279 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id]; 280 PyObject* py_qstate, *py_sqstate, *res; 281 PyGILState_STATE gil = PyGILState_Ensure(); 282 283 log_query_info(VERB_ALGO, "pythonmod: inform_super, sub is", &qstate->qinfo); 284 log_query_info(VERB_ALGO, "super is", &super->qinfo); 285 286 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0); 287 py_sqstate = SWIG_NewPointerObj((void*) super, SWIGTYPE_p_module_qstate, 0); 288 289 res = PyObject_CallFunction(pe->func_inform, "iOOO", id, py_qstate, 290 py_sqstate, pq->data); 291 292 if (PyErr_Occurred()) 293 { 294 log_err("pythonmod: Exception occurred in function inform_super"); 295 PyErr_Print(); 296 qstate->ext_state[id] = module_error; 297 } 298 else if ((res == NULL) || (!PyObject_IsTrue(res))) 299 { 300 log_err("pythonmod: python returned bad code in inform_super"); 301 qstate->ext_state[id] = module_error; 302 } 303 304 Py_XDECREF(res); 305 Py_XDECREF(py_sqstate); 306 Py_XDECREF(py_qstate); 307 308 PyGILState_Release(gil); 309 } 310 311 void pythonmod_operate(struct module_qstate* qstate, enum module_ev event, 312 int id, struct outbound_entry* ATTR_UNUSED(outbound)) 313 { 314 struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id]; 315 struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id]; 316 PyObject* py_qstate, *res; 317 PyGILState_STATE gil = PyGILState_Ensure(); 318 319 if ( pq == NULL) 320 { 321 /* create qstate */ 322 pq = qstate->minfo[id] = malloc(sizeof(struct pythonmod_qstate)); 323 324 /* Initialize per query data */ 325 pq->data = Py_None; 326 Py_INCREF(pq->data); 327 } 328 329 /* Call operate */ 330 py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0); 331 res = PyObject_CallFunction(pe->func_operate, "iiOO", id, (int) event, 332 py_qstate, pq->data); 333 if (PyErr_Occurred()) 334 { 335 log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event)); 336 PyErr_Print(); 337 qstate->ext_state[id] = module_error; 338 } 339 else if ((res == NULL) || (!PyObject_IsTrue(res))) 340 { 341 log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event)); 342 qstate->ext_state[id] = module_error; 343 } 344 Py_XDECREF(res); 345 Py_XDECREF(py_qstate); 346 347 PyGILState_Release(gil); 348 } 349 350 void pythonmod_clear(struct module_qstate* qstate, int id) 351 { 352 struct pythonmod_qstate* pq; 353 if (qstate == NULL) 354 return; 355 356 pq = (struct pythonmod_qstate*)qstate->minfo[id]; 357 verbose(VERB_ALGO, "pythonmod: clear, id: %d, pq:%lX", id, 358 (unsigned long int)pq); 359 if(pq != NULL) 360 { 361 PyGILState_STATE gil = PyGILState_Ensure(); 362 Py_DECREF(pq->data); 363 PyGILState_Release(gil); 364 /* Free qstate */ 365 free(pq); 366 } 367 368 qstate->minfo[id] = NULL; 369 } 370 371 size_t pythonmod_get_mem(struct module_env* env, int id) 372 { 373 struct pythonmod_env* pe = (struct pythonmod_env*)env->modinfo[id]; 374 verbose(VERB_ALGO, "pythonmod: get_mem, id: %d, pe:%lX", id, 375 (unsigned long int)pe); 376 if(!pe) 377 return 0; 378 return sizeof(*pe); 379 } 380 381 /** 382 * The module function block 383 */ 384 static struct module_func_block pythonmod_block = { 385 "python", 386 &pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super, 387 &pythonmod_clear, &pythonmod_get_mem 388 }; 389 390 struct module_func_block* pythonmod_get_funcblock(void) 391 { 392 return &pythonmod_block; 393 } 394