summaryrefslogtreecommitdiff
path: root/pythonmod/pythonmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'pythonmod/pythonmod.c')
-rw-r--r--pythonmod/pythonmod.c383
1 files changed, 383 insertions, 0 deletions
diff --git a/pythonmod/pythonmod.c b/pythonmod/pythonmod.c
new file mode 100644
index 000000000000..9860d001d0e2
--- /dev/null
+++ b/pythonmod/pythonmod.c
@@ -0,0 +1,383 @@
+/*
+ * pythonmod.c: unbound module C wrapper
+ *
+ * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ * Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the organization nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * \file
+ * Python module for unbound. Calls python script.
+ */
+
+/* ignore the varargs unused warning from SWIGs internal vararg support */
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+#include "config.h"
+#include <ldns/ldns.h>
+
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+#include <Python.h>
+
+#include "pythonmod/pythonmod.h"
+#include "util/module.h"
+#include "util/config_file.h"
+#include "pythonmod_utils.h"
+
+#ifdef S_SPLINT_S
+typedef struct PyObject PyObject;
+typedef struct PyThreadState PyThreadState;
+typedef void* PyGILState_STATE;
+#endif
+
+/**
+ * Global state for the module.
+ */
+struct pythonmod_env {
+
+ /** Python script filename. */
+ const char* fname;
+
+ /** Python main thread */
+ PyThreadState* mainthr;
+ /** Python module. */
+ PyObject* module;
+
+ /** Module init function */
+ PyObject* func_init;
+ /** Module deinit function */
+ PyObject* func_deinit;
+ /** Module operate function */
+ PyObject* func_operate;
+ /** Module super_inform function */
+ PyObject* func_inform;
+
+ /** Python dictionary. */
+ PyObject* dict;
+
+ /** Module data. */
+ PyObject* data;
+
+ /** Module qstate. */
+ struct module_qstate* qstate;
+};
+
+/**
+ * Per query state for the iterator module.
+ */
+struct pythonmod_qstate {
+
+ /** Module per query data. */
+ PyObject* data;
+};
+
+/* Generated */
+#ifndef S_SPLINT_S
+#include "pythonmod/interface.h"
+#endif
+
+int pythonmod_init(struct module_env* env, int id)
+{
+ /* Initialize module */
+ FILE* script_py = NULL;
+ PyObject* py_cfg, *res;
+ PyGILState_STATE gil;
+ struct pythonmod_env* pe = (struct pythonmod_env*)calloc(1, sizeof(struct pythonmod_env));
+ if (!pe)
+ {
+ log_err("pythonmod: malloc failure");
+ return 0;
+ }
+
+ env->modinfo[id] = (void*) pe;
+
+ /* Initialize module */
+ pe->fname = env->cfg->python_script;
+ if(pe->fname==NULL || pe->fname[0]==0) {
+ log_err("pythonmod: no script given.");
+ return 0;
+ }
+
+ /* Initialize Python libraries */
+ if (!Py_IsInitialized())
+ {
+ Py_SetProgramName("unbound");
+ Py_NoSiteFlag = 1;
+ Py_Initialize();
+ PyEval_InitThreads();
+ SWIG_init();
+ pe->mainthr = PyEval_SaveThread();
+ }
+
+ gil = PyGILState_Ensure();
+
+ /* Initialize Python */
+ PyRun_SimpleString("import sys \n");
+ PyRun_SimpleString("sys.path.append('.') \n");
+ if(env->cfg->directory && env->cfg->directory[0]) {
+ char wdir[1524];
+ snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
+ env->cfg->directory);
+ PyRun_SimpleString(wdir);
+ }
+ PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n");
+ PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n");
+ PyRun_SimpleString("import distutils.sysconfig \n");
+ PyRun_SimpleString("sys.path.append(distutils.sysconfig.get_python_lib(1,0)) \n");
+ if (PyRun_SimpleString("from unboundmodule import *\n") < 0)
+ {
+ log_err("pythonmod: cannot initialize core module: unboundmodule.py");
+ PyGILState_Release(gil);
+ return 0;
+ }
+
+ /* Check Python file load */
+ if ((script_py = fopen(pe->fname, "r")) == NULL)
+ {
+ log_err("pythonmod: can't open file %s for reading", pe->fname);
+ PyGILState_Release(gil);
+ return 0;
+ }
+
+ /* Load file */
+ pe->module = PyImport_AddModule("__main__");
+ pe->dict = PyModule_GetDict(pe->module);
+ pe->data = Py_None;
+ Py_INCREF(pe->data);
+ PyModule_AddObject(pe->module, "mod_env", pe->data);
+
+ /* TODO: deallocation of pe->... if an error occurs */
+
+ if (PyRun_SimpleFile(script_py, pe->fname) < 0)
+ {
+ log_err("pythonmod: can't parse Python script %s", pe->fname);
+ PyGILState_Release(gil);
+ return 0;
+ }
+
+ fclose(script_py);
+
+ if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
+ {
+ log_err("pythonmod: function init is missing in %s", pe->fname);
+ PyGILState_Release(gil);
+ return 0;
+ }
+ if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
+ {
+ log_err("pythonmod: function deinit is missing in %s", pe->fname);
+ PyGILState_Release(gil);
+ return 0;
+ }
+ if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL)
+ {
+ log_err("pythonmod: function operate is missing in %s", pe->fname);
+ PyGILState_Release(gil);
+ return 0;
+ }
+ if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL)
+ {
+ log_err("pythonmod: function inform_super is missing in %s", pe->fname);
+ PyGILState_Release(gil);
+ return 0;
+ }
+
+ py_cfg = SWIG_NewPointerObj((void*) env->cfg, SWIGTYPE_p_config_file, 0);
+ res = PyObject_CallFunction(pe->func_init, "iO", id, py_cfg);
+ if (PyErr_Occurred())
+ {
+ log_err("pythonmod: Exception occurred in function init");
+ PyErr_Print();
+ }
+
+ Py_XDECREF(res);
+ Py_XDECREF(py_cfg);
+ PyGILState_Release(gil);
+
+ return 1;
+}
+
+void pythonmod_deinit(struct module_env* env, int id)
+{
+ struct pythonmod_env* pe = env->modinfo[id];
+ if(pe == NULL)
+ return;
+
+ /* Free Python resources */
+ if(pe->module != NULL)
+ {
+ PyObject* res;
+ PyGILState_STATE gil = PyGILState_Ensure();
+
+ /* Deinit module */
+ res = PyObject_CallFunction(pe->func_deinit, "i", id);
+ if (PyErr_Occurred()) {
+ log_err("pythonmod: Exception occurred in function deinit");
+ PyErr_Print();
+ }
+ /* Free result if any */
+ Py_XDECREF(res);
+ /* Free shared data if any */
+ Py_XDECREF(pe->data);
+ PyGILState_Release(gil);
+
+ PyEval_RestoreThread(pe->mainthr);
+ Py_Finalize();
+ pe->mainthr = NULL;
+ }
+ pe->fname = NULL;
+ free(pe);
+
+ /* Module is deallocated in Python */
+ env->modinfo[id] = NULL;
+}
+
+void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super)
+{
+ struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
+ struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
+ PyObject* py_qstate, *py_sqstate, *res;
+ PyGILState_STATE gil = PyGILState_Ensure();
+
+ log_query_info(VERB_ALGO, "pythonmod: inform_super, sub is", &qstate->qinfo);
+ log_query_info(VERB_ALGO, "super is", &super->qinfo);
+
+ py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
+ py_sqstate = SWIG_NewPointerObj((void*) super, SWIGTYPE_p_module_qstate, 0);
+
+ res = PyObject_CallFunction(pe->func_inform, "iOOO", id, py_qstate,
+ py_sqstate, pq->data);
+
+ if (PyErr_Occurred())
+ {
+ log_err("pythonmod: Exception occurred in function inform_super");
+ PyErr_Print();
+ qstate->ext_state[id] = module_error;
+ }
+ else if ((res == NULL) || (!PyObject_IsTrue(res)))
+ {
+ log_err("pythonmod: python returned bad code in inform_super");
+ qstate->ext_state[id] = module_error;
+ }
+
+ Py_XDECREF(res);
+ Py_XDECREF(py_sqstate);
+ Py_XDECREF(py_qstate);
+
+ PyGILState_Release(gil);
+}
+
+void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
+ int id, struct outbound_entry* ATTR_UNUSED(outbound))
+{
+ struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
+ struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
+ PyObject* py_qstate, *res;
+ PyGILState_STATE gil = PyGILState_Ensure();
+
+ if ( pq == NULL)
+ {
+ /* create qstate */
+ pq = qstate->minfo[id] = malloc(sizeof(struct pythonmod_qstate));
+
+ /* Initialize per query data */
+ pq->data = Py_None;
+ Py_INCREF(pq->data);
+ }
+
+ /* Call operate */
+ py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
+ res = PyObject_CallFunction(pe->func_operate, "iiOO", id, (int) event,
+ py_qstate, pq->data);
+ if (PyErr_Occurred())
+ {
+ log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
+ PyErr_Print();
+ qstate->ext_state[id] = module_error;
+ }
+ else if ((res == NULL) || (!PyObject_IsTrue(res)))
+ {
+ log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event));
+ qstate->ext_state[id] = module_error;
+ }
+ Py_XDECREF(res);
+ Py_XDECREF(py_qstate);
+
+ PyGILState_Release(gil);
+}
+
+void pythonmod_clear(struct module_qstate* qstate, int id)
+{
+ struct pythonmod_qstate* pq;
+ if (qstate == NULL)
+ return;
+
+ pq = (struct pythonmod_qstate*)qstate->minfo[id];
+ verbose(VERB_ALGO, "pythonmod: clear, id: %d, pq:%lX", id,
+ (unsigned long int)pq);
+ if(pq != NULL)
+ {
+ PyGILState_STATE gil = PyGILState_Ensure();
+ Py_DECREF(pq->data);
+ PyGILState_Release(gil);
+ /* Free qstate */
+ free(pq);
+ }
+
+ qstate->minfo[id] = NULL;
+}
+
+size_t pythonmod_get_mem(struct module_env* env, int id)
+{
+ struct pythonmod_env* pe = (struct pythonmod_env*)env->modinfo[id];
+ verbose(VERB_ALGO, "pythonmod: get_mem, id: %d, pe:%lX", id,
+ (unsigned long int)pe);
+ if(!pe)
+ return 0;
+ return sizeof(*pe);
+}
+
+/**
+ * The module function block
+ */
+static struct module_func_block pythonmod_block = {
+ "python",
+ &pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super,
+ &pythonmod_clear, &pythonmod_get_mem
+};
+
+struct module_func_block* pythonmod_get_funcblock(void)
+{
+ return &pythonmod_block;
+}