2 * pythonmod.c: unbound module C wrapper
4 * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
5 * Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
7 * This software is open source.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * * Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
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.
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.
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.
38 * Python module for unbound. Calls python script.
41 /* ignore the varargs unused warning from SWIGs internal vararg support */
43 #pragma GCC diagnostic ignored "-Wunused-parameter"
44 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
48 #include "ldns/sbuffer.h"
50 #undef _POSIX_C_SOURCE
54 #include "pythonmod/pythonmod.h"
55 #include "util/module.h"
56 #include "util/config_file.h"
57 #include "pythonmod_utils.h"
60 typedef struct PyObject PyObject
;
61 typedef struct PyThreadState PyThreadState
;
62 typedef void* PyGILState_STATE
;
66 * Global state for the module.
68 struct pythonmod_env
{
70 /** Python script filename. */
73 /** Python main thread */
74 PyThreadState
* mainthr
;
78 /** Module init function */
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
;
87 /** Python dictionary. */
94 struct module_qstate
* qstate
;
98 * Per query state for the iterator module.
100 struct pythonmod_qstate
{
102 /** Module per query data. */
108 #include "pythonmod/interface.h"
111 int pythonmod_init(struct module_env
* env
, int id
)
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
));
120 log_err("pythonmod: malloc failure");
124 env
->modinfo
[id
] = (void*) pe
;
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.");
133 /* Initialize Python libraries */
134 if (!Py_IsInitialized())
136 Py_SetProgramName("unbound");
139 PyEval_InitThreads();
141 pe
->mainthr
= PyEval_SaveThread();
144 gil
= PyGILState_Ensure();
146 /* Initialize Python */
147 PyRun_SimpleString("import sys \n");
148 PyRun_SimpleString("sys.path.append('.') \n");
149 if(env
->cfg
->directory
&& env
->cfg
->directory
[0]) {
151 snprintf(wdir
, sizeof(wdir
), "sys.path.append('%s') \n",
152 env
->cfg
->directory
);
153 PyRun_SimpleString(wdir
);
155 PyRun_SimpleString("sys.path.append('"RUN_DIR
"') \n");
156 PyRun_SimpleString("sys.path.append('"SHARE_DIR
"') \n");
157 PyRun_SimpleString("import distutils.sysconfig \n");
158 PyRun_SimpleString("sys.path.append(distutils.sysconfig.get_python_lib(1,0)) \n");
159 if (PyRun_SimpleString("from unboundmodule import *\n") < 0)
161 log_err("pythonmod: cannot initialize core module: unboundmodule.py");
162 PyGILState_Release(gil
);
166 /* Check Python file load */
167 if ((script_py
= fopen(pe
->fname
, "r")) == NULL
)
169 log_err("pythonmod: can't open file %s for reading", pe
->fname
);
170 PyGILState_Release(gil
);
175 pe
->module = PyImport_AddModule("__main__");
176 pe
->dict
= PyModule_GetDict(pe
->module);
179 PyModule_AddObject(pe
->module, "mod_env", pe
->data
);
181 /* TODO: deallocation of pe->... if an error occurs */
183 if (PyRun_SimpleFile(script_py
, pe
->fname
) < 0)
185 log_err("pythonmod: can't parse Python script %s", pe
->fname
);
186 PyGILState_Release(gil
);
192 if ((pe
->func_init
= PyDict_GetItemString(pe
->dict
, "init")) == NULL
)
194 log_err("pythonmod: function init is missing in %s", pe
->fname
);
195 PyGILState_Release(gil
);
198 if ((pe
->func_deinit
= PyDict_GetItemString(pe
->dict
, "deinit")) == NULL
)
200 log_err("pythonmod: function deinit is missing in %s", pe
->fname
);
201 PyGILState_Release(gil
);
204 if ((pe
->func_operate
= PyDict_GetItemString(pe
->dict
, "operate")) == NULL
)
206 log_err("pythonmod: function operate is missing in %s", pe
->fname
);
207 PyGILState_Release(gil
);
210 if ((pe
->func_inform
= PyDict_GetItemString(pe
->dict
, "inform_super")) == NULL
)
212 log_err("pythonmod: function inform_super is missing in %s", pe
->fname
);
213 PyGILState_Release(gil
);
217 py_cfg
= SWIG_NewPointerObj((void*) env
->cfg
, SWIGTYPE_p_config_file
, 0);
218 res
= PyObject_CallFunction(pe
->func_init
, "iO", id
, py_cfg
);
219 if (PyErr_Occurred())
221 log_err("pythonmod: Exception occurred in function init");
227 PyGILState_Release(gil
);
232 void pythonmod_deinit(struct module_env
* env
, int id
)
234 struct pythonmod_env
* pe
= env
->modinfo
[id
];
238 /* Free Python resources */
239 if(pe
->module != NULL
)
242 PyGILState_STATE gil
= PyGILState_Ensure();
245 res
= PyObject_CallFunction(pe
->func_deinit
, "i", id
);
246 if (PyErr_Occurred()) {
247 log_err("pythonmod: Exception occurred in function deinit");
250 /* Free result if any */
252 /* Free shared data if any */
253 Py_XDECREF(pe
->data
);
254 PyGILState_Release(gil
);
256 PyEval_RestoreThread(pe
->mainthr
);
263 /* Module is deallocated in Python */
264 env
->modinfo
[id
] = NULL
;
267 void pythonmod_inform_super(struct module_qstate
* qstate
, int id
, struct module_qstate
* super
)
269 struct pythonmod_env
* pe
= (struct pythonmod_env
*)qstate
->env
->modinfo
[id
];
270 struct pythonmod_qstate
* pq
= (struct pythonmod_qstate
*)qstate
->minfo
[id
];
271 PyObject
* py_qstate
, *py_sqstate
, *res
;
272 PyGILState_STATE gil
= PyGILState_Ensure();
274 log_query_info(VERB_ALGO
, "pythonmod: inform_super, sub is", &qstate
->qinfo
);
275 log_query_info(VERB_ALGO
, "super is", &super
->qinfo
);
277 py_qstate
= SWIG_NewPointerObj((void*) qstate
, SWIGTYPE_p_module_qstate
, 0);
278 py_sqstate
= SWIG_NewPointerObj((void*) super
, SWIGTYPE_p_module_qstate
, 0);
280 res
= PyObject_CallFunction(pe
->func_inform
, "iOOO", id
, py_qstate
,
281 py_sqstate
, pq
->data
);
283 if (PyErr_Occurred())
285 log_err("pythonmod: Exception occurred in function inform_super");
287 qstate
->ext_state
[id
] = module_error
;
289 else if ((res
== NULL
) || (!PyObject_IsTrue(res
)))
291 log_err("pythonmod: python returned bad code in inform_super");
292 qstate
->ext_state
[id
] = module_error
;
296 Py_XDECREF(py_sqstate
);
297 Py_XDECREF(py_qstate
);
299 PyGILState_Release(gil
);
302 void pythonmod_operate(struct module_qstate
* qstate
, enum module_ev event
,
303 int id
, struct outbound_entry
* ATTR_UNUSED(outbound
))
305 struct pythonmod_env
* pe
= (struct pythonmod_env
*)qstate
->env
->modinfo
[id
];
306 struct pythonmod_qstate
* pq
= (struct pythonmod_qstate
*)qstate
->minfo
[id
];
307 PyObject
* py_qstate
, *res
;
308 PyGILState_STATE gil
= PyGILState_Ensure();
313 pq
= qstate
->minfo
[id
] = malloc(sizeof(struct pythonmod_qstate
));
315 /* Initialize per query data */
321 py_qstate
= SWIG_NewPointerObj((void*) qstate
, SWIGTYPE_p_module_qstate
, 0);
322 res
= PyObject_CallFunction(pe
->func_operate
, "iiOO", id
, (int) event
,
323 py_qstate
, pq
->data
);
324 if (PyErr_Occurred())
326 log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event
));
328 qstate
->ext_state
[id
] = module_error
;
330 else if ((res
== NULL
) || (!PyObject_IsTrue(res
)))
332 log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event
));
333 qstate
->ext_state
[id
] = module_error
;
336 Py_XDECREF(py_qstate
);
338 PyGILState_Release(gil
);
341 void pythonmod_clear(struct module_qstate
* qstate
, int id
)
343 struct pythonmod_qstate
* pq
;
347 pq
= (struct pythonmod_qstate
*)qstate
->minfo
[id
];
348 verbose(VERB_ALGO
, "pythonmod: clear, id: %d, pq:%lX", id
,
349 (unsigned long int)pq
);
352 PyGILState_STATE gil
= PyGILState_Ensure();
354 PyGILState_Release(gil
);
359 qstate
->minfo
[id
] = NULL
;
362 size_t pythonmod_get_mem(struct module_env
* env
, int id
)
364 struct pythonmod_env
* pe
= (struct pythonmod_env
*)env
->modinfo
[id
];
365 verbose(VERB_ALGO
, "pythonmod: get_mem, id: %d, pe:%lX", id
,
366 (unsigned long int)pe
);
373 * The module function block
375 static struct module_func_block pythonmod_block
= {
377 &pythonmod_init
, &pythonmod_deinit
, &pythonmod_operate
, &pythonmod_inform_super
,
378 &pythonmod_clear
, &pythonmod_get_mem
381 struct module_func_block
* pythonmod_get_funcblock(void)
383 return &pythonmod_block
;