瀏覽代碼

app_python: the initial foundation to use Python for kemi config interpreter

- to allow writing kamailio routing logic in Python
Daniel-Constantin Mierla 9 年之前
父節點
當前提交
aaf7977ac1

+ 7 - 7
modules/app_python/app_python_mod.c

@@ -50,7 +50,7 @@ static int mod_init(void);
 static int child_init(int rank);
 static void mod_destroy(void);
 
-PyObject *handler_obj;
+PyObject *_sr_apy_handler_obj;
 
 char *dname = NULL, *bname = NULL;
 
@@ -239,12 +239,12 @@ static int mod_init(void)
 		return -1;
 	}
 
-	handler_obj = PyObject_CallObject(pFunc, pArgs);
+	_sr_apy_handler_obj = PyObject_CallObject(pFunc, pArgs);
 
 	Py_XDECREF(pFunc);
 	Py_XDECREF(pArgs);
 
-	if (handler_obj == Py_None) {
+	if (_sr_apy_handler_obj == Py_None) {
 		if (!PyErr_Occurred())
 			PyErr_Format(PyExc_TypeError, "Function '%s' of module '%s' has returned None. Should be a class instance.", mod_init_fname.s, bname);
 		python_handle_exception("mod_init");
@@ -255,13 +255,13 @@ static int mod_init(void)
 
 	if (PyErr_Occurred()) {
 		python_handle_exception("mod_init");
-		Py_XDECREF(handler_obj);
+		Py_XDECREF(_sr_apy_handler_obj);
 		Py_DECREF(format_exc_obj);
 		PyEval_ReleaseLock();
 		return -1;
 	}
 
-	if (handler_obj == NULL) {
+	if (_sr_apy_handler_obj == NULL) {
 		LM_ERR("PyObject_CallObject() returned NULL but no exception!\n");
 		if (!PyErr_Occurred())
 			PyErr_Format(PyExc_TypeError, "Function '%s' of module '%s' has returned not returned object. Should be a class instance.", mod_init_fname.s, bname);
@@ -290,7 +290,7 @@ static int child_init(int rank)
 	PyThreadState_Swap(myThreadState);
 
 	// get instance class name
-	classname = get_instance_class_name(handler_obj);
+	classname = get_instance_class_name(_sr_apy_handler_obj);
 	if (classname == NULL)
 	{
 		if (!PyErr_Occurred())
@@ -302,7 +302,7 @@ static int child_init(int rank)
 		return -1;
 	}
 
-	pFunc = PyObject_GetAttrString(handler_obj, child_init_mname.s);
+	pFunc = PyObject_GetAttrString(_sr_apy_handler_obj, child_init_mname.s);
 
 	if (pFunc == NULL) {
 		python_handle_exception("child_init");

+ 1 - 1
modules/app_python/app_python_mod.h

@@ -24,7 +24,7 @@
 
 #include <Python.h>
 
-extern PyObject *handler_obj;
+extern PyObject *_sr_apy_handler_obj;
 extern PyObject *format_exc_obj;
 extern PyThreadState *myThreadState;
 

+ 126 - 0
modules/app_python/apy_kemi.c

@@ -22,9 +22,12 @@
 #include <unistd.h>
 #include <stdlib.h>
 
+#include <Python.h>
+
 #include "../../dprint.h"
 #include "../../route.h"
 #include "../../kemi.h"
+#include "../../mem/pkg.h"
 
 #include "python_exec.h"
 #include "apy_kemi.h"
@@ -84,10 +87,133 @@ int sr_kemi_config_engine_python(sip_msg_t *msg, int rtype, str *rname)
 	return 1;
 }
 
+/**
+ *
+ */
+static PyObject *sr_apy_kemi_exec_func(PyObject *self, PyObject *args)
+{
+	str mname = str_init("");
+	int midx = 0;
+	str fname = str_init("");
+	int i;
+	PyTypeObject *pto;
+	sr_kemi_t *ket = NULL;
+	sr_kemi_val_t vps[SR_KEMI_PARAMS_MAX];
+	sr_apy_env_t *env_P;
+
+	env_P = sr_apy_env_get();
+
+	if(env_P==NULL || env_P->msg==NULL) {
+		LM_ERR("invalid Python environment attributes\n");
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	if(self!=NULL) {
+		pto = Py_TYPE(self);
+		if(pto==NULL) {
+			Py_INCREF(Py_None);
+			return Py_None;
+		}
+		LM_DBG("execution of method: %s\n", pto->tp_name);
+		fname.s = (char*)pto->tp_name;
+		fname.len = strlen(fname.s);
+	} else {
+		fname.s = "[test]";
+		fname.len = strlen(fname.s);
+		LM_DBG("execution of method: %.*s\n", fname.len, fname.s);
+	}
+
+	ket = sr_kemi_lookup(&mname, midx, &fname);
+	if(ket==NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	memset(vps, 0, SR_KEMI_PARAMS_MAX*sizeof(sr_kemi_val_t));
+	for(i=0; i<SR_KEMI_PARAMS_MAX; i++) {
+		if(ket->ptypes[i]==SR_KEMIP_NONE) {
+			break;
+		} else if(ket->ptypes[i]==SR_KEMIP_STR) {
+			if(!PyArg_ParseTuple(args, "s:kemi-param", &vps[i].s.s)) {
+				LM_ERR("unable to retrieve str param %d\n", i);
+				Py_INCREF(Py_None);
+				return Py_None;
+			}
+			vps[i].s.len = strlen(vps[i].s.s);
+			LM_DBG("param[%d] for: %.*s is str: %.*s\n", i,
+				fname.len, fname.s, vps[i].s.len, vps[i].s.s);
+		} else if(ket->ptypes[i]==SR_KEMIP_INT) {
+			if(!PyArg_ParseTuple(args, "i:kemi-param", &vps[i].n)) {
+				LM_ERR("unable to retrieve int param %d\n", i);
+				Py_INCREF(Py_None);
+				return Py_None;
+			}
+			LM_DBG("param[%d] for: %.*s is int: %d\n", i,
+				fname.len, fname.s, vps[i].n);
+		} else {
+			LM_ERR("unknown parameter type %d (%d)\n", ket->ptypes[i], i);
+			Py_INCREF(Py_None);
+			return Py_None;
+		}
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+/**
+ *
+ */
+PyObject *_sr_apy_ksr_module = NULL;
+PyObject *_sr_apy_ksr_module_dict = NULL;
+
+PyMethodDef *_sr_KSRMethods = NULL;
+#define SR_APY_KSR_METHOS_SIZE	256
+
 /**
  *
  */
 int sr_apy_init_ksr(void)
 {
+	_sr_KSRMethods = pkg_malloc(SR_APY_KSR_METHOS_SIZE * sizeof(PyMethodDef));
+	if(_sr_KSRMethods==NULL) {
+		LM_ERR("no more pkg memory\n");
+		return -1;
+	}
+	memset(_sr_KSRMethods, 0, SR_APY_KSR_METHOS_SIZE * sizeof(PyMethodDef));
+
+	_sr_KSRMethods[0].ml_name = "test";
+	_sr_KSRMethods[0].ml_meth = (PyCFunction)sr_apy_kemi_exec_func;
+	_sr_KSRMethods[0].ml_flags = METH_VARARGS;
+	_sr_KSRMethods[0].ml_doc = "Kamailio function";
+
+	_sr_apy_ksr_module = Py_InitModule("KSR", _sr_KSRMethods);
+	_sr_apy_ksr_module_dict = PyModule_GetDict(_sr_apy_ksr_module);
+
+	Py_INCREF(_sr_apy_ksr_module);
+
+	LM_DBG("module 'KSR' has been initialized\n");
 	return 0;
 }
+
+/**
+ *
+ */
+void sr_apy_destroy_ksr(void)
+{
+	if(_sr_apy_ksr_module!=NULL) {
+		Py_XDECREF(_sr_apy_ksr_module);
+		_sr_apy_ksr_module = NULL;
+	}
+	if(_sr_apy_ksr_module_dict!=NULL) {
+		Py_XDECREF(_sr_apy_ksr_module_dict);
+		_sr_apy_ksr_module_dict = NULL;
+	}
+	if(_sr_KSRMethods!=NULL) {
+		pkg_free(_sr_KSRMethods);
+		_sr_KSRMethods = NULL;
+	}
+
+	LM_DBG("module 'KSR' has been destroyed\n");
+}

+ 2 - 0
modules/app_python/apy_kemi.h

@@ -24,6 +24,8 @@
 
 #include "../../parser/msg_parser.h"
 
+int sr_apy_init_ksr(void);
+void sr_apy_destroy_ksr(void);
 int sr_kemi_config_engine_python(sip_msg_t *msg, int rtype, str *rname);
 
 #endif

+ 30 - 10
modules/app_python/python_exec.c

@@ -35,17 +35,30 @@
 #include "python_msgobj.h"
 #include "python_support.h"
 
+static sr_apy_env_t _sr_apy_env = {0};
 
+/**
+ *
+ */
+sr_apy_env_t *sr_apy_env_get()
+{
+	return &_sr_apy_env;
+}
+
+/**
+ *
+ */
 int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode)
 {
 	PyObject *pFunc, *pArgs, *pValue, *pResult;
-	PyObject *msg;
+	PyObject *pmsg;
 	int rval;
 
+	_sr_apy_env.msg = _msg;
 	PyEval_AcquireLock();
 	PyThreadState_Swap(myThreadState);
 
-	pFunc = PyObject_GetAttrString(handler_obj, fname);
+	pFunc = PyObject_GetAttrString(_sr_apy_handler_obj, fname);
 	if (pFunc == NULL || !PyCallable_Check(pFunc)) {
 		if(emode==1) {
 			LM_ERR("%s not found or is not callable\n", fname);
@@ -55,6 +68,7 @@ int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode)
 		Py_XDECREF(pFunc);
 		PyThreadState_Swap(NULL);
 		PyEval_ReleaseLock();
+		_sr_apy_env.msg = NULL;
 		if(emode==1) {
 			return -1;
 		} else {
@@ -62,37 +76,40 @@ int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode)
 		}
 	}
 
-	msg = newmsgobject(_msg);
-	if (msg == NULL) {
+	pmsg = newmsgobject(_msg);
+	if (pmsg == NULL) {
 		LM_ERR("can't create MSGtype instance\n");
 		Py_DECREF(pFunc);
 		PyThreadState_Swap(NULL);
 		PyEval_ReleaseLock();
+		_sr_apy_env.msg = NULL;
 		return -1;
 	}
 
 	pArgs = PyTuple_New(fparam == NULL ? 1 : 2);
 	if (pArgs == NULL) {
 		LM_ERR("PyTuple_New() has failed\n");
-		msg_invalidate(msg);
-		Py_DECREF(msg);
+		msg_invalidate(pmsg);
+		Py_DECREF(pmsg);
 		Py_DECREF(pFunc);
 		PyThreadState_Swap(NULL);
 		PyEval_ReleaseLock();
+		_sr_apy_env.msg = NULL;
 		return -1;
 	}
-	PyTuple_SetItem(pArgs, 0, msg);
-	/* Tuple steals msg */
+	PyTuple_SetItem(pArgs, 0, pmsg);
+	/* Tuple steals pmsg */
 
 	if (fparam != NULL) {
 		pValue = PyString_FromString(fparam);
 		if (pValue == NULL) {
 			LM_ERR("PyString_FromString(%s) has failed\n", fparam);
-			msg_invalidate(msg);
+			msg_invalidate(pmsg);
 			Py_DECREF(pArgs);
 			Py_DECREF(pFunc);
 			PyThreadState_Swap(NULL);
 			PyEval_ReleaseLock();
+			_sr_apy_env.msg = NULL;
 			return -1;
 		}
 		PyTuple_SetItem(pArgs, 1, pValue);
@@ -100,7 +117,7 @@ int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode)
 	}
 
 	pResult = PyObject_CallObject(pFunc, pArgs);
-	msg_invalidate(msg);
+	msg_invalidate(pmsg);
 	Py_DECREF(pArgs);
 	Py_DECREF(pFunc);
 	if (PyErr_Occurred()) {
@@ -108,6 +125,7 @@ int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode)
 		python_handle_exception("python_exec2");
 		PyThreadState_Swap(NULL);
 		PyEval_ReleaseLock();
+		_sr_apy_env.msg = NULL;
 		return -1;
 	}
 
@@ -115,6 +133,7 @@ int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode)
 		LM_ERR("PyObject_CallObject() returned NULL\n");
 		PyThreadState_Swap(NULL);
 		PyEval_ReleaseLock();
+		_sr_apy_env.msg = NULL;
 		return -1;
 	}
 
@@ -122,6 +141,7 @@ int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode)
 	Py_DECREF(pResult);
 	PyThreadState_Swap(NULL);
 	PyEval_ReleaseLock();
+	_sr_apy_env.msg = NULL;
 	return rval;
 }
 

+ 6 - 0
modules/app_python/python_exec.h

@@ -24,6 +24,12 @@
 
 #include "../../parser/msg_parser.h"
 
+typedef struct sr_apy_env {
+	sip_msg_t *msg;
+} sr_apy_env_t;
+
+sr_apy_env_t *sr_apy_env_get();
+
 int apy_exec(sip_msg_t *_msg, char *fname, char *fparam, int emode);
 int python_exec1(sip_msg_t *, char *, char *);
 int python_exec2(sip_msg_t *, char *, char *);

+ 3 - 0
modules/app_python/python_iface.c

@@ -35,6 +35,8 @@
 #include "mod_Ranks.h"
 #include "mod_Logger.h"
 
+#include "apy_kemi.h"
+
 
 int ap_init_modules(void)
 {
@@ -42,6 +44,7 @@ int ap_init_modules(void)
 	init_mod_Core();
 	init_mod_Ranks();
 	init_mod_Logger();
+	if(sr_apy_init_ksr()<0) return -1;
 
 	return 0;
 }