Browse code

app_python3: first release

- use same symbols names as app_python so these two modules cannot be used together
- use GIL for thread management

AnthonyA authored on 16/02/2018 13:37:33 • Daniel-Constantin Mierla committed on 20/02/2018 09:11:48
Showing 33 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,29 @@
1
+# 
2
+# WARNING: do not run this directly, it should be run by the master Makefile
3
+
4
+include ../../Makefile.defs
5
+auto_gen=
6
+NAME=app_python3.so
7
+
8
+# If you have multiple Python versions installed make sure to modify the
9
+# the following to point to the correct instance. Module has been tested
10
+# to work with 2.6 and 2.5. Python 2.4 has been only confirmed to compile,
11
+# but no testing has been done with that.
12
+PYTHON3?=python3
13
+
14
+PYTHON3_VERSION=${shell ${PYTHON3} -c "import distutils.sysconfig;print(distutils.sysconfig.get_config_var('VERSION'))"}
15
+PYTHON3_LIBDIR=${shell ${PYTHON3} -c "import distutils.sysconfig;print(distutils.sysconfig.get_config_var('LIBDIR'))"}
16
+PYTHON3_LDFLAGS=${shell ${PYTHON3} -c "import distutils.sysconfig;print(distutils.sysconfig.get_config_var('LINKFORSHARED'))"}
17
+PYTHON3_INCDIR=${shell ${PYTHON3} -c "import distutils.sysconfig;print(distutils.sysconfig.get_python_inc())"}
18
+
19
+LIBS=${shell ${PYTHON3}-config --libs}
20
+
21
+ifeq ($(OS), freebsd)
22
+LIBS+=-pthread
23
+endif
24
+
25
+DEFS+=-I${PYTHON3_INCDIR}
26
+DEFS+=-DKAMAILIO_MOD_INTERFACE
27
+
28
+include ../../Makefile.modules
29
+
0 30
new file mode 100644
... ...
@@ -0,0 +1,196 @@
1
+app_python Module
2
+
3
+Maxim Sobolev
4
+
5
+Edited by
6
+
7
+Maxim Sobolev
8
+
9
+   Copyright © 2010 Maxim Sobolev
10
+     __________________________________________________________________
11
+
12
+   Table of Contents
13
+
14
+   1. Admin Guide
15
+
16
+        1. Overview
17
+        2. Dependencies
18
+
19
+              2.1. Kamailio Modules
20
+              2.2. External Libraries or Applications
21
+
22
+        3. Parameters
23
+
24
+              3.1. load (string)
25
+              3.2. script_name (string)
26
+              3.3. mod_init_function (string)
27
+              3.4. child_init_method (string)
28
+
29
+        4. Functions
30
+
31
+              4.1. python_exec(method [, args])
32
+
33
+        5. RPC Commands
34
+
35
+              5.1. app_python.reload
36
+              5.2. app_python.api_list
37
+
38
+   List of Examples
39
+
40
+   1.1. Set load parameter
41
+   1.2. Set mod_init_function parameter
42
+   1.3. Set child_init_method parameter
43
+   1.4. python_exec usage
44
+
45
+Chapter 1. Admin Guide
46
+
47
+   Table of Contents
48
+
49
+   1. Overview
50
+   2. Dependencies
51
+
52
+        2.1. Kamailio Modules
53
+        2.2. External Libraries or Applications
54
+
55
+   3. Parameters
56
+
57
+        3.1. load (string)
58
+        3.2. script_name (string)
59
+        3.3. mod_init_function (string)
60
+        3.4. child_init_method (string)
61
+
62
+   4. Functions
63
+
64
+        4.1. python_exec(method [, args])
65
+
66
+   5. RPC Commands
67
+
68
+        5.1. app_python.reload
69
+        5.2. app_python.api_list
70
+
71
+1. Overview
72
+
73
+   This module allows executing Python scripts from config file, exporting
74
+   functions to access the SIP message from Python.
75
+
76
+   For some basic examples of Python scripts that can be used with this
77
+   module, look at the files inside source tree located at
78
+   'modules/app_python/python_examples/'.
79
+
80
+2. Dependencies
81
+
82
+   2.1. Kamailio Modules
83
+   2.2. External Libraries or Applications
84
+
85
+2.1. Kamailio Modules
86
+
87
+   The following modules must be loaded before this module:
88
+     * none.
89
+
90
+2.2. External Libraries or Applications
91
+
92
+   The following libraries or applications must be installed before
93
+   running Kamailio with this module loaded:
94
+     * python-dev - Python devel library.
95
+
96
+3. Parameters
97
+
98
+   3.1. load (string)
99
+   3.2. script_name (string)
100
+   3.3. mod_init_function (string)
101
+   3.4. child_init_method (string)
102
+
103
+3.1. load (string)
104
+
105
+   The path to the file with Python code to be executed from configuration
106
+   file.
107
+
108
+   Default value is “/usr/local/etc/kamailio/handler.py”.
109
+
110
+   Example 1.1. Set load parameter
111
+...
112
+modparam("app_python", "load", "/usr/local/etc/kamailio/myscript.py")
113
+...
114
+
115
+3.2. script_name (string)
116
+
117
+   This is same as "load" parameter, kept for backward compatibility with
118
+   the older versions of the module.
119
+
120
+3.3. mod_init_function (string)
121
+
122
+   The Python function to be executed by this module when it is initialied
123
+   by Kamailio.
124
+
125
+   Default value is “mod_init”.
126
+
127
+   Example 1.2. Set mod_init_function parameter
128
+...
129
+modparam("app_python", "mod_init_function", "my_mod_init")
130
+...
131
+
132
+3.4. child_init_method (string)
133
+
134
+   The Python function to be executed by this module when a new worker
135
+   process (child) is initialied by Kamailio.
136
+
137
+   Default value is “child_init”.
138
+
139
+   Example 1.3. Set child_init_method parameter
140
+...
141
+modparam("app_python", "child_init_method", "my_child_init")
142
+...
143
+
144
+4. Functions
145
+
146
+   4.1. python_exec(method [, args])
147
+
148
+4.1.  python_exec(method [, args])
149
+
150
+   Execute the Python function with the name given by the parameter
151
+   'method'. Optionally can be provided a second string with parameters to
152
+   be passed to the Python function.
153
+
154
+   Both parameters can contain pseudo-variables.
155
+
156
+   Example 1.4. python_exec usage
157
+...
158
+python_exec("my_python_function");
159
+python_exec("my_python_function", "my_params");
160
+python_exec("my_python_function", "$rU");
161
+...
162
+
163
+5. RPC Commands
164
+
165
+   5.1. app_python.reload
166
+   5.2. app_python.api_list
167
+
168
+5.1.  app_python.reload
169
+
170
+   IMPORTANT: not functional yet (can crash a running instance, use it
171
+   only for testing).
172
+
173
+   Marks the need to reload the js script. The actual reload is done by
174
+   every working process when the next call to KEMI config is executed.
175
+
176
+   Name: app_python.reload
177
+
178
+   Parameters: none
179
+
180
+   Example:
181
+...
182
+kamcmd app_python.reload
183
+...
184
+
185
+5.2.  app_python.api_list
186
+
187
+   List the functions available via Kemi framework.
188
+
189
+   Name: app_python.api_list
190
+
191
+   Parameters: none
192
+
193
+   Example:
194
+...
195
+kamcmd app_python.api_list
196
+...
0 197
new file mode 100644
... ...
@@ -0,0 +1,16 @@
1
+
2
+Example of using loggers in Python:
3
+
4
+loadmodule "app_python.so"
5
+modparam("app_python", "script_name", "/path/to/Loggers.py")
6
+modparam("app_python", "mod_init_function", "mod_init")
7
+modparam("app_python", "child_init_method", "child_init")
8
+
9
+...
10
+
11
+route
12
+{
13
+    python_exec("TestLoggers", "Test Message\n");
14
+    ...
15
+}
16
+
0 17
new file mode 100644
... ...
@@ -0,0 +1,544 @@
1
+/*
2
+ * Copyright (C) 2009 Sippy Software, Inc., http://www.sippysoft.com
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
+ *
20
+ */
21
+
22
+#include <Python.h>
23
+#include <libgen.h>
24
+
25
+#include "../../core/str.h"
26
+#include "../../core/sr_module.h"
27
+#include "../../core/mod_fix.h"
28
+#include "../../core/kemi.h"
29
+
30
+#include "python_exec.h"
31
+#include "python_iface.h"
32
+#include "python_msgobj.h"
33
+#include "python_support.h"
34
+#include "app_python_mod.h"
35
+
36
+#include "mod_Router.h"
37
+#include "mod_Core.h"
38
+#include "mod_Ranks.h"
39
+#include "mod_Logger.h"
40
+
41
+#include "apy_kemi.h"
42
+
43
+MODULE_VERSION
44
+
45
+
46
+str _sr_python_load_file = str_init("/usr/local/etc/" NAME "/handler.py");
47
+static str mod_init_fname = str_init("mod_init");
48
+static str child_init_mname = str_init("child_init");
49
+
50
+static int mod_init(void);
51
+static int child_init(int rank);
52
+static void mod_destroy(void);
53
+
54
+PyObject *_sr_apy_handler_obj;
55
+
56
+char *dname = NULL, *bname = NULL;
57
+
58
+int _apy_process_rank = 0;
59
+
60
+PyThreadState *myThreadState;
61
+
62
+/** module parameters */
63
+static param_export_t params[]={
64
+	{"script_name",        PARAM_STR, &_sr_python_load_file },
65
+	{"load",               PARAM_STR, &_sr_python_load_file },
66
+	{"mod_init_function",  PARAM_STR, &mod_init_fname },
67
+	{"child_init_method",  PARAM_STR, &child_init_mname },
68
+	{0,0,0}
69
+};
70
+
71
+/*
72
+ * Exported functions
73
+ */
74
+static cmd_export_t cmds[] = {
75
+	{ "python_exec", (cmd_function)python_exec1, 1,  fixup_spve_null,
76
+		0,	ANY_ROUTE },
77
+	{ "python_exec", (cmd_function)python_exec2, 2,  fixup_spve_spve,
78
+		0,	ANY_ROUTE },
79
+	{ 0, 0, 0, 0, 0, 0 }
80
+};
81
+
82
+/** module exports */
83
+struct module_exports exports = {
84
+	"app_python3",                   /* module name */
85
+	RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
86
+	cmds,                           /* exported functions */
87
+	params,                         /* exported parameters */
88
+	0,                              /* exported statistics */
89
+	0,                              /* exported MI functions */
90
+	0,                              /* exported pseudo-variables */
91
+	0,                              /* extra processes */
92
+	mod_init,                       /* module initialization function */
93
+	(response_function) NULL,       /* response handling function */
94
+	(destroy_function) mod_destroy, /* destroy function */
95
+	child_init                      /* per-child init function */
96
+};
97
+
98
+
99
+/**
100
+ *
101
+ */
102
+static int mod_init(void)
103
+{
104
+	char *dname_src, *bname_src;
105
+	int i;
106
+
107
+	if(apy_sr_init_mod()<0) {
108
+		LM_ERR("failed to init the sr mod\n");
109
+		return -1;
110
+	}
111
+	if(app_python_init_rpc()<0) {
112
+		LM_ERR("failed to register RPC commands\n");
113
+		return -1;
114
+	}
115
+
116
+	dname_src = as_asciiz(&_sr_python_load_file);
117
+	bname_src = as_asciiz(&_sr_python_load_file);
118
+
119
+	if(dname_src==NULL || bname_src==NULL)
120
+	{
121
+		LM_ERR("no more pkg memory\n");
122
+		if(dname_src) pkg_free(dname_src);
123
+		if(bname_src) pkg_free(bname_src);
124
+		return -1;
125
+	}
126
+
127
+	dname = strdup(dirname(dname_src));
128
+	if(dname==NULL) {
129
+		LM_ERR("no more system memory\n");
130
+		pkg_free(dname_src);
131
+		pkg_free(bname_src);
132
+		return -1;
133
+	}
134
+	if (strlen(dname) == 0) {
135
+		free(dname);
136
+		dname = malloc(2);
137
+		if(dname==NULL) {
138
+			LM_ERR("no more system memory\n");
139
+			pkg_free(dname_src);
140
+			pkg_free(bname_src);
141
+			return -1;
142
+		}
143
+		dname[0] = '.';
144
+		dname[1] = '\0';
145
+	}
146
+	bname = strdup(basename(bname_src));
147
+	i = strlen(bname);
148
+	if (bname[i - 1] == 'c' || bname[i - 1] == 'o')
149
+		i -= 1;
150
+	if (bname[i - 3] == '.' && bname[i - 2] == 'p' && bname[i - 1] == 'y') {
151
+		bname[i - 3] = '\0';
152
+	} else {
153
+		LM_ERR("%s: script_name doesn't look like a python script\n",
154
+				_sr_python_load_file.s);
155
+		pkg_free(dname_src);
156
+		pkg_free(bname_src);
157
+		return -1;
158
+	}
159
+
160
+	if(apy_load_script()<0) {
161
+		pkg_free(dname_src);
162
+		pkg_free(bname_src);
163
+		LM_ERR("failed to load python script\n");
164
+		return -1;
165
+	}
166
+
167
+	pkg_free(dname_src);
168
+	pkg_free(bname_src);
169
+	return 0;
170
+}
171
+
172
+/**
173
+ *
174
+ */
175
+static int child_init(int rank)
176
+{
177
+	_apy_process_rank = rank;
178
+	return apy_init_script(rank);
179
+}
180
+
181
+/**
182
+ *
183
+ */
184
+static void mod_destroy(void)
185
+{
186
+	if (dname)
187
+		free(dname);	// dname was strdup'ed
188
+	if (bname)
189
+		free(bname);	// bname was strdup'ed
190
+
191
+	destroy_mod_Core();
192
+	destroy_mod_Ranks();
193
+	destroy_mod_Logger();
194
+	destroy_mod_Router();
195
+}
196
+
197
+
198
+#define PY_GIL_ENSURE gstate = PyGILState_Ensure();
199
+#define PY_GIL_RELEASE PyGILState_Release(gstate);
200
+
201
+// #define PY_THREADSTATE_SWAP_IN PyThreadState_Swap(myThreadState);
202
+// #define PY_THREADSTATE_SWAP_NULL PyThreadState_Swap(NULL);
203
+#define PY_THREADSTATE_SWAP_IN
204
+#define PY_THREADSTATE_SWAP_NULL
205
+
206
+int apy_load_script(void)
207
+{
208
+	PyObject *sys_path, *pDir, *pModule, *pFunc, *pArgs;
209
+	PyThreadState *mainThreadState;
210
+	PyGILState_STATE gstate;
211
+	
212
+	if (ap_init_modules() != 0) {
213
+		return -1;
214
+	}
215
+
216
+	Py_Initialize();
217
+	PyEval_InitThreads();
218
+	myThreadState = PyThreadState_Get();
219
+
220
+	PY_GIL_ENSURE
221
+	format_exc_obj = InitTracebackModule();
222
+
223
+	if (format_exc_obj == NULL || !PyCallable_Check(format_exc_obj))
224
+	{
225
+		Py_XDECREF(format_exc_obj);
226
+		PY_GIL_RELEASE
227
+		return -1;
228
+	}
229
+
230
+	sys_path = PySys_GetObject("path");
231
+	/* PySys_GetObject doesn't pass reference! No need to DEREF */
232
+	if (sys_path == NULL) {
233
+		if (!PyErr_Occurred())
234
+			PyErr_Format(PyExc_AttributeError,
235
+					"'module' object 'sys' has no attribute 'path'");
236
+		python_handle_exception("mod_init");
237
+		Py_DECREF(format_exc_obj);
238
+		PY_GIL_RELEASE
239
+		return -1;
240
+	}
241
+
242
+	pDir = PyUnicode_FromString(dname);
243
+	if (pDir == NULL) {
244
+		if (!PyErr_Occurred())
245
+			PyErr_Format(PyExc_AttributeError,
246
+					"PyUnicode_FromString() has failed");
247
+		python_handle_exception("mod_init");
248
+		Py_DECREF(format_exc_obj);
249
+		PY_GIL_RELEASE
250
+		return -1;
251
+	}
252
+
253
+	PyList_Insert(sys_path, 0, pDir);
254
+	Py_DECREF(pDir);
255
+
256
+	if (python_msgobj_init() != 0) {
257
+		if (!PyErr_Occurred())
258
+			PyErr_SetString(PyExc_AttributeError,
259
+					"python_msgobj_init() has failed");
260
+		python_handle_exception("mod_init");
261
+		Py_DECREF(format_exc_obj);
262
+		PY_GIL_RELEASE
263
+		return -1;
264
+	}
265
+
266
+	pModule = PyImport_ImportModule(bname);
267
+	if (pModule == NULL) {
268
+                PyErr_PrintEx(0);
269
+		if (!PyErr_Occurred())
270
+			PyErr_Format(PyExc_ImportError, "No module named '%s'", bname);
271
+		python_handle_exception("mod_init");
272
+		Py_DECREF(format_exc_obj);
273
+		PY_GIL_RELEASE
274
+
275
+		return -1;
276
+	}
277
+
278
+	pFunc = PyObject_GetAttrString(pModule, mod_init_fname.s);
279
+	Py_DECREF(pModule);
280
+
281
+	/* pFunc is a new reference */
282
+
283
+	if (pFunc == NULL) {
284
+		if (!PyErr_Occurred())
285
+			PyErr_Format(PyExc_AttributeError,
286
+					"'module' object '%s' has no attribute '%s'",
287
+					bname, mod_init_fname.s);
288
+		python_handle_exception("mod_init");
289
+		Py_DECREF(format_exc_obj);
290
+		Py_XDECREF(pFunc);
291
+		PY_GIL_RELEASE
292
+		return -1;
293
+	}
294
+
295
+	if (!PyCallable_Check(pFunc)) {
296
+		if (!PyErr_Occurred())
297
+			PyErr_Format(PyExc_AttributeError,
298
+					"module object '%s' has is not callable attribute '%s'",
299
+					bname, mod_init_fname.s);
300
+		python_handle_exception("mod_init");
301
+		Py_DECREF(format_exc_obj);
302
+		Py_XDECREF(pFunc);
303
+		PY_GIL_RELEASE
304
+		return -1;
305
+	}
306
+
307
+
308
+	pArgs = PyTuple_New(0);
309
+	if (pArgs == NULL) {
310
+		python_handle_exception("mod_init");
311
+		Py_DECREF(format_exc_obj);
312
+		Py_DECREF(pFunc);
313
+		PY_GIL_RELEASE
314
+		return -1;
315
+	}
316
+
317
+	_sr_apy_handler_obj = PyObject_CallObject(pFunc, pArgs);
318
+
319
+	Py_XDECREF(pFunc);
320
+	Py_XDECREF(pArgs);
321
+
322
+	if (_sr_apy_handler_obj == Py_None) {
323
+		if (!PyErr_Occurred())
324
+			PyErr_Format(PyExc_TypeError,
325
+					"Function '%s' of module '%s' has returned None."
326
+					" Should be a class instance.", mod_init_fname.s, bname);
327
+		python_handle_exception("mod_init");
328
+		Py_DECREF(format_exc_obj);
329
+		PY_GIL_RELEASE
330
+		return -1;
331
+	}
332
+
333
+	if (PyErr_Occurred()) {
334
+		python_handle_exception("mod_init");
335
+		Py_XDECREF(_sr_apy_handler_obj);
336
+		Py_DECREF(format_exc_obj);
337
+		PY_GIL_RELEASE
338
+		return -1;
339
+	}
340
+
341
+	if (_sr_apy_handler_obj == NULL) {
342
+		LM_ERR("PyObject_CallObject() returned NULL but no exception!\n");
343
+		if (!PyErr_Occurred())
344
+			PyErr_Format(PyExc_TypeError,
345
+					"Function '%s' of module '%s' has returned not returned"
346
+					" object. Should be a class instance.",
347
+					mod_init_fname.s, bname);
348
+		python_handle_exception("mod_init");
349
+		Py_DECREF(format_exc_obj);
350
+		PY_GIL_RELEASE
351
+		return -1;
352
+	}
353
+
354
+	//myThreadState = PyThreadState_New(mainThreadState->interp);
355
+	PY_GIL_RELEASE
356
+	return 0;
357
+}
358
+
359
+int apy_init_script(int rank)
360
+{
361
+	PyObject *pFunc, *pArgs, *pValue, *pResult;
362
+	int rval;
363
+	char *classname;
364
+	PyGILState_STATE gstate;
365
+
366
+
367
+	PY_GIL_ENSURE
368
+	PY_THREADSTATE_SWAP_IN
369
+
370
+	// get instance class name
371
+	classname = get_instance_class_name(_sr_apy_handler_obj);
372
+	if (classname == NULL)
373
+	{
374
+		if (!PyErr_Occurred())
375
+			PyErr_Format(PyExc_AttributeError,
376
+					"'module' instance has no class name");
377
+		python_handle_exception("child_init");
378
+		Py_DECREF(format_exc_obj);
379
+		PY_THREADSTATE_SWAP_NULL
380
+		PY_GIL_RELEASE
381
+		return -1;
382
+	}
383
+
384
+	pFunc = PyObject_GetAttrString(_sr_apy_handler_obj, child_init_mname.s);
385
+
386
+	if (pFunc == NULL) {
387
+		python_handle_exception("child_init");
388
+		Py_XDECREF(pFunc);
389
+		Py_DECREF(format_exc_obj);
390
+		PY_THREADSTATE_SWAP_NULL
391
+		PY_GIL_RELEASE
392
+		return -1;
393
+	}
394
+
395
+	if (!PyCallable_Check(pFunc)) {
396
+		if (!PyErr_Occurred())
397
+			PyErr_Format(PyExc_AttributeError,
398
+					"class object '%s' has is not callable attribute '%s'",
399
+					classname, mod_init_fname.s);
400
+		python_handle_exception("child_init");
401
+		Py_DECREF(format_exc_obj);
402
+		Py_XDECREF(pFunc);
403
+		PY_THREADSTATE_SWAP_NULL
404
+		PY_GIL_RELEASE
405
+		return -1;
406
+	}
407
+
408
+	pArgs = PyTuple_New(1);
409
+	if (pArgs == NULL) {
410
+		python_handle_exception("child_init");
411
+		Py_DECREF(format_exc_obj);
412
+		Py_DECREF(pFunc);
413
+		PY_THREADSTATE_SWAP_NULL
414
+		PY_GIL_RELEASE
415
+		return -1;
416
+	}
417
+
418
+	pValue = PyLong_FromLong((long)rank);
419
+	if (pValue == NULL) {
420
+		python_handle_exception("child_init");
421
+		Py_DECREF(format_exc_obj);
422
+		Py_DECREF(pArgs);
423
+		Py_DECREF(pFunc);
424
+		PY_THREADSTATE_SWAP_NULL
425
+		PY_GIL_RELEASE
426
+		return -1;
427
+	}
428
+	PyTuple_SetItem(pArgs, 0, pValue);
429
+	/* pValue has been stolen */
430
+
431
+	pResult = PyObject_CallObject(pFunc, pArgs);
432
+	Py_DECREF(pFunc);
433
+	Py_DECREF(pArgs);
434
+
435
+	if (PyErr_Occurred()) {
436
+		python_handle_exception("child_init");
437
+		Py_DECREF(format_exc_obj);
438
+		Py_XDECREF(pResult);
439
+		PY_THREADSTATE_SWAP_NULL
440
+		PY_GIL_RELEASE
441
+		return -1;
442
+	}
443
+
444
+	if (pResult == NULL) {
445
+		LM_ERR("PyObject_CallObject() returned NULL but no exception!\n");
446
+		PY_THREADSTATE_SWAP_NULL
447
+		PY_GIL_RELEASE
448
+		return -1;
449
+	}
450
+
451
+	if (!PyLong_Check(pResult))
452
+	{
453
+		if (!PyErr_Occurred())
454
+			PyErr_Format(PyExc_TypeError,
455
+					"method '%s' of class '%s' should return 'int' type",
456
+					child_init_mname.s, classname);
457
+		python_handle_exception("child_init");
458
+		Py_DECREF(format_exc_obj);
459
+		Py_XDECREF(pResult);
460
+		PY_THREADSTATE_SWAP_NULL
461
+		PY_GIL_RELEASE
462
+		return -1;
463
+	}
464
+
465
+	rval = PyLong_AsLong(pResult);
466
+	Py_DECREF(pResult);
467
+	PY_THREADSTATE_SWAP_NULL
468
+	PY_GIL_RELEASE
469
+
470
+	return rval;
471
+}
472
+/**
473
+ *
474
+ */
475
+static int ki_app_python_exec(sip_msg_t *msg, str *method)
476
+{
477
+	if(method==NULL || method->s==NULL || method->len<=0) {
478
+		LM_ERR("invalid method name\n");
479
+		return -1;
480
+	}
481
+	if(method->s[method->len]!='\0') {
482
+		LM_ERR("invalid terminated method name\n");
483
+		return -1;
484
+	}
485
+	return apy_exec(msg, method->s, NULL, 1);
486
+}
487
+
488
+/**
489
+ *
490
+ */
491
+static int ki_app_python_exec_p1(sip_msg_t *msg, str *method, str *p1)
492
+{
493
+	if(method==NULL || method->s==NULL || method->len<=0) {
494
+		LM_ERR("invalid method name\n");
495
+		return -1;
496
+	}
497
+	if(method->s[method->len]!='\0') {
498
+		LM_ERR("invalid terminated method name\n");
499
+		return -1;
500
+	}
501
+	if(p1==NULL || p1->s==NULL || p1->len<0) {
502
+		LM_ERR("invalid p1 value\n");
503
+		return -1;
504
+	}
505
+	if(p1->s[p1->len]!='\0') {
506
+		LM_ERR("invalid terminated p1 value\n");
507
+		return -1;
508
+	}
509
+
510
+	return apy_exec(msg, method->s, p1->s, 1);
511
+}
512
+
513
+/**
514
+ *
515
+ */
516
+/* clang-format off */
517
+static sr_kemi_t sr_kemi_app_python_exports[] = {
518
+	{ str_init("app_python3"), str_init("exec"),
519
+		SR_KEMIP_INT, ki_app_python_exec,
520
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
521
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
522
+	},
523
+	{ str_init("app_python3"), str_init("exec_p1"),
524
+		SR_KEMIP_INT, ki_app_python_exec_p1,
525
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
526
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
527
+	},
528
+
529
+	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
530
+};
531
+/* clang-format on */
532
+
533
+/**
534
+ *
535
+ */
536
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
537
+{
538
+	str ename = str_init("python");
539
+
540
+	sr_kemi_eng_register(&ename, sr_kemi_config_engine_python);
541
+	sr_kemi_modules_add(sr_kemi_app_python_exports);
542
+
543
+	return 0;
544
+}
0 545
new file mode 100644
... ...
@@ -0,0 +1,31 @@
1
+/* 
2
+ * Copyright (C) 2009 Sippy Software, Inc., http://www.sippysoft.com
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
+ *
20
+*/
21
+
22
+#ifndef _PYTHON_MOD_H
23
+#define  _PYTHON_MOD_H
24
+
25
+#include <Python.h>
26
+
27
+extern PyObject *_sr_apy_handler_obj;
28
+extern PyObject *format_exc_obj;
29
+extern PyThreadState *myThreadState;
30
+
31
+#endif
0 32
new file mode 100644
... ...
@@ -0,0 +1,1292 @@
1
+/**
2
+ * Copyright (C) 2016 Daniel-Constantin Mierla (asipto.com)
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
+ *
20
+ */
21
+#include <stdio.h>
22
+#include <unistd.h>
23
+#include <stdlib.h>
24
+
25
+#include <Python.h>
26
+
27
+#include "../../core/dprint.h"
28
+#include "../../core/route.h"
29
+#include "../../core/fmsg.h"
30
+#include "../../core/kemi.h"
31
+#include "../../core/pvar.h"
32
+#include "../../core/mem/pkg.h"
33
+#include "../../core/mem/shm.h"
34
+#include "../../core/rpc.h"
35
+#include "../../core/rpc_lookup.h"
36
+
37
+#include "msgobj_struct.h"
38
+#include "python_exec.h"
39
+#include "apy_kemi_export.h"
40
+#include "apy_kemi.h"
41
+
42
+static int *_sr_python_reload_version = NULL;
43
+static int _sr_python_local_version = 0;
44
+extern str _sr_python_load_file;
45
+extern int _apy_process_rank;
46
+
47
+/**
48
+ *
49
+ */
50
+
51
+int apy_reload_script(void)
52
+{
53
+	if(_sr_python_reload_version == NULL) {
54
+		return 0;
55
+	}
56
+	if(*_sr_python_reload_version == _sr_python_local_version) {
57
+		return 0;
58
+	}
59
+	if(apy_load_script()<0) {
60
+		LM_ERR("failed to load script file\n");
61
+		return -1;
62
+	}
63
+	if(apy_init_script(_apy_process_rank)<0) {
64
+		LM_ERR("failed to init script\n");
65
+		return -1;
66
+	}
67
+	_sr_python_local_version = *_sr_python_reload_version;
68
+	return 0;
69
+}
70
+/**
71
+ *
72
+ */
73
+int sr_kemi_config_engine_python(sip_msg_t *msg, int rtype, str *rname,
74
+		str *rparam)
75
+{
76
+	int ret;
77
+
78
+	ret = -1;
79
+	if(rtype==REQUEST_ROUTE) {
80
+		if(rname!=NULL && rname->s!=NULL) {
81
+			ret = apy_exec(msg, rname->s,
82
+					(rparam && rparam->s)?rparam->s:NULL, 0);
83
+		} else {
84
+			ret = apy_exec(msg, "ksr_request_route", NULL, 1);
85
+		}
86
+	} else if(rtype==CORE_ONREPLY_ROUTE) {
87
+		ret = apy_exec(msg, "ksr_reply_route", NULL, 0);
88
+	} else if(rtype==BRANCH_ROUTE) {
89
+		if(rname!=NULL && rname->s!=NULL) {
90
+			ret = apy_exec(msg, rname->s, NULL, 0);
91
+		}
92
+	} else if(rtype==FAILURE_ROUTE) {
93
+		if(rname!=NULL && rname->s!=NULL) {
94
+			ret = apy_exec(msg, rname->s, NULL, 0);
95
+		}
96
+	} else if(rtype==BRANCH_FAILURE_ROUTE) {
97
+		if(rname!=NULL && rname->s!=NULL) {
98
+			ret = apy_exec(msg, rname->s, NULL, 0);
99
+		}
100
+	} else if(rtype==TM_ONREPLY_ROUTE) {
101
+		if(rname!=NULL && rname->s!=NULL) {
102
+			ret = apy_exec(msg, rname->s, NULL, 0);
103
+		}
104
+	} else if(rtype==ONSEND_ROUTE) {
105
+		ret = apy_exec(msg, "ksr_onsend_route", NULL, 0);
106
+	} else if(rtype==EVENT_ROUTE) {
107
+		if(rname!=NULL && rname->s!=NULL) {
108
+			ret = apy_exec(msg, rname->s,
109
+					(rparam && rparam->s)?rparam->s:NULL, 0);
110
+		}
111
+	} else {
112
+		if(rname!=NULL) {
113
+			LM_ERR("route type %d with name [%.*s] not implemented\n",
114
+				rtype, rname->len, rname->s);
115
+		} else {
116
+			LM_ERR("route type %d with no name not implemented\n",
117
+				rtype);
118
+		}
119
+	}
120
+
121
+	if(rname!=NULL) {
122
+		LM_DBG("execution of route type %d with name [%.*s] returned %d\n",
123
+				rtype, rname->len, rname->s, ret);
124
+	} else {
125
+		LM_DBG("execution of route type %d with no name returned %d\n",
126
+			rtype, ret);
127
+	}
128
+
129
+	return 1;
130
+}
131
+
132
+/**
133
+ *
134
+ */
135
+PyObject *sr_kemi_apy_return_true(void)
136
+{
137
+	Py_INCREF(Py_True);
138
+	return Py_True;
139
+}
140
+
141
+/**
142
+ *
143
+ */
144
+PyObject *sr_kemi_apy_return_false(void)
145
+{
146
+	Py_INCREF(Py_False);
147
+	return Py_False;
148
+}
149
+
150
+/**
151
+ *
152
+ */
153
+PyObject *sr_apy_kemi_return_none(void)
154
+{
155
+	Py_INCREF(Py_None);
156
+	return Py_None;
157
+}
158
+
159
+/**
160
+ *
161
+ */
162
+PyObject *sr_kemi_apy_return_int(sr_kemi_t *ket, int rval)
163
+{
164
+	if(ket!=NULL && ket->rtype==SR_KEMIP_BOOL) {
165
+		if(rval==SR_KEMI_TRUE) {
166
+			return sr_kemi_apy_return_true();
167
+		} else {
168
+			return sr_kemi_apy_return_false();
169
+		}
170
+	}
171
+	return PyLong_FromLong((long)rval);
172
+}
173
+
174
+/**
175
+ *
176
+ */
177
+PyObject *sr_apy_kemi_return_str(sr_kemi_t *ket, char *sval, int slen)
178
+{
179
+	return PyUnicode_FromStringAndSize(sval, slen);
180
+}
181
+/**
182
+ *
183
+ */
184
+PyObject *sr_apy_kemi_exec_func(PyObject *self, PyObject *args, int idx)
185
+{
186
+	str fname;
187
+	int i;
188
+	int ret;
189
+	sr_kemi_t *ket = NULL;
190
+	sr_kemi_val_t vps[SR_KEMI_PARAMS_MAX];
191
+	sr_apy_env_t *env_P;
192
+	sip_msg_t *lmsg = NULL;
193
+
194
+	env_P = sr_apy_env_get();
195
+
196
+	if(env_P==NULL) {
197
+		LM_ERR("invalid Python environment attributes\n");
198
+		return sr_kemi_apy_return_false();
199
+	}
200
+	if(env_P->msg==NULL) {
201
+		lmsg = faked_msg_next();
202
+	} else {
203
+		lmsg = env_P->msg;
204
+	}
205
+
206
+	ket = sr_apy_kemi_export_get(idx);
207
+	if(ket==NULL) {
208
+		return sr_kemi_apy_return_false();
209
+	}
210
+	if(ket->mname.len>0) {
211
+		LM_DBG("execution of method: %.*s\n", ket->fname.len, ket->fname.s);
212
+	} else {
213
+		LM_DBG("execution of method: %.*s.%.*s\n",
214
+				ket->mname.len, ket->mname.s,
215
+				ket->fname.len, ket->fname.s);
216
+	}
217
+	fname = ket->fname;
218
+
219
+	if(ket->ptypes[0]==SR_KEMIP_NONE) {
220
+		ret = ((sr_kemi_fm_f)(ket->func))(lmsg);
221
+		return sr_kemi_apy_return_int(ket, ret);
222
+	}
223
+
224
+	memset(vps, 0, SR_KEMI_PARAMS_MAX*sizeof(sr_kemi_val_t));
225
+	if(ket->ptypes[1]==SR_KEMIP_NONE) {
226
+		i = 1;
227
+		if(ket->ptypes[0]==SR_KEMIP_INT) {
228
+			if(!PyArg_ParseTuple(args, "i:kemi-param-n", &vps[0].n)) {
229
+				LM_ERR("unable to retrieve int param %d\n", 0);
230
+				return sr_kemi_apy_return_false();
231
+			}
232
+			LM_DBG("param[%d] for: %.*s is int: %d\n", i,
233
+				fname.len, fname.s, vps[0].n);
234
+		} else {
235
+			if(!PyArg_ParseTuple(args, "s:kemi-param-s", &vps[0].s.s)) {
236
+				LM_ERR("unable to retrieve str param %d\n", 0);
237
+				return sr_kemi_apy_return_false();
238
+			}
239
+			vps[0].s.len = strlen(vps[0].s.s);
240
+			LM_DBG("param[%d] for: %.*s is str: %.*s\n", i,
241
+				fname.len, fname.s, vps[0].s.len, vps[0].s.s);
242
+		}
243
+	} else if(ket->ptypes[2]==SR_KEMIP_NONE) {
244
+		i = 2;
245
+		if(ket->ptypes[0]==SR_KEMIP_INT && ket->ptypes[1]==SR_KEMIP_INT) {
246
+			if(!PyArg_ParseTuple(args, "ii:kemi-param-nn", &vps[0].n, &vps[1].n)) {
247
+				LM_ERR("unable to retrieve int-int params %d\n", i);
248
+				return sr_kemi_apy_return_false();
249
+			}
250
+			LM_DBG("params[%d] for: %.*s are int-int: [%d] [%d]\n", i,
251
+				fname.len, fname.s, vps[0].n, vps[1].n);
252
+		} else if(ket->ptypes[0]==SR_KEMIP_INT && ket->ptypes[1]==SR_KEMIP_STR) {
253
+			if(!PyArg_ParseTuple(args, "is:kemi-param-ns", &vps[0].n, &vps[1].s.s)) {
254
+				LM_ERR("unable to retrieve int-str params %d\n", i);
255
+				return sr_kemi_apy_return_false();
256
+			}
257
+			vps[1].s.len = strlen(vps[1].s.s);
258
+			LM_DBG("params[%d] for: %.*s are int-str: [%d] [%.*s]\n", i,
259
+				fname.len, fname.s, vps[0].n, vps[1].s.len, vps[1].s.s);
260
+		} else if(ket->ptypes[0]==SR_KEMIP_STR && ket->ptypes[1]==SR_KEMIP_INT) {
261
+			if(!PyArg_ParseTuple(args, "si:kemi-param-sn", &vps[0].s.s, &vps[1].n)) {
262
+				LM_ERR("unable to retrieve str-int params %d\n", i);
263
+				return sr_kemi_apy_return_false();
264
+			}
265
+			vps[0].s.len = strlen(vps[0].s.s);
266
+			LM_DBG("params[%d] for: %.*s are str-int: [%.*s] [%d]\n", i,
267
+				fname.len, fname.s, vps[0].s.len, vps[0].s.s, vps[1].n);
268
+		} else {
269
+			if(!PyArg_ParseTuple(args, "ss:kemi-param-ss", &vps[0].s.s, &vps[1].s.s)) {
270
+				LM_ERR("unable to retrieve str-str param %d\n", i);
271
+				return sr_kemi_apy_return_false();
272
+			}
273
+			vps[0].s.len = strlen(vps[0].s.s);
274
+			vps[1].s.len = strlen(vps[1].s.s);
275
+			LM_DBG("params[%d] for: %.*s are str: [%.*s] [%.*s]\n", i,
276
+				fname.len, fname.s, vps[0].s.len, vps[0].s.s,
277
+				vps[1].s.len, vps[1].s.s);
278
+		}
279
+
280
+	} else if(ket->ptypes[3]==SR_KEMIP_NONE) {
281
+		i = 3;
282
+		if(ket->ptypes[0]==SR_KEMIP_INT && ket->ptypes[1]==SR_KEMIP_INT
283
+				&& ket->ptypes[2]==SR_KEMIP_INT) {
284
+			if(!PyArg_ParseTuple(args, "iii:kemi-param-nnn", &vps[0].n,
285
+						&vps[1].n, &vps[2].n)) {
286
+				LM_ERR("unable to retrieve int-int-int params %d\n", i);
287
+				return sr_kemi_apy_return_false();
288
+			}
289
+			LM_DBG("params[%d] for: %.*s are int-int-int: [%d] [%d] [%d]\n",
290
+					i, fname.len, fname.s, vps[0].n, vps[1].n, vps[2].n);
291
+		} else if(ket->ptypes[0]==SR_KEMIP_INT && ket->ptypes[1]==SR_KEMIP_STR
292
+				&& ket->ptypes[2]==SR_KEMIP_INT) {
293
+			if(!PyArg_ParseTuple(args, "isi:kemi-param-nsn", &vps[0].n,
294
+						&vps[1].s.s, &vps[2].n)) {
295
+				LM_ERR("unable to retrieve int-str-int params %d\n", i);
296
+				return sr_kemi_apy_return_false();
297
+			}
298
+			vps[1].s.len = strlen(vps[1].s.s);
299
+			LM_DBG("params[%d] for: %.*s are int-str-int: [%d] [%.*s] [%d]\n", i,
300
+				fname.len, fname.s, vps[0].n, vps[1].s.len, vps[1].s.s, vps[2].n);
301
+		} else if(ket->ptypes[0]==SR_KEMIP_STR && ket->ptypes[1]==SR_KEMIP_INT
302
+				&& ket->ptypes[2]==SR_KEMIP_INT) {
303
+			if(!PyArg_ParseTuple(args, "sii:kemi-param-snn", &vps[0].s.s,
304
+						&vps[1].n, &vps[2].n)) {
305
+				LM_ERR("unable to retrieve str-int-int params %d\n", i);
306
+				return sr_kemi_apy_return_false();
307
+			}
308
+			vps[0].s.len = strlen(vps[0].s.s);
309
+			LM_DBG("params[%d] for: %.*s are str-int: [%.*s] [%d] [%d]\n", i,
310
+					fname.len, fname.s, vps[0].s.len, vps[0].s.s, vps[1].n,
311
+					vps[2].n);
312
+		} else if(ket->ptypes[0]==SR_KEMIP_STR && ket->ptypes[1]==SR_KEMIP_STR
313
+				&& ket->ptypes[2]==SR_KEMIP_INT) {
314
+			if(!PyArg_ParseTuple(args, "ssi:kemi-param-ssn", &vps[0].s.s,
315
+						&vps[1].s.s, &vps[2].n)) {
316
+				LM_ERR("unable to retrieve str-str-int param %d\n", i);
317
+				return sr_kemi_apy_return_false();
318
+			}
319
+			vps[0].s.len = strlen(vps[0].s.s);
320
+			vps[1].s.len = strlen(vps[1].s.s);
321
+			LM_DBG("params[%d] for: %.*s are str-str-int: [%.*s] [%.*s]"
322
+					" [%d]\n", i, fname.len, fname.s,
323
+					vps[0].s.len, vps[0].s.s,
324
+					vps[1].s.len, vps[1].s.s, vps[2].n);
325
+		} else if(ket->ptypes[0]==SR_KEMIP_STR && ket->ptypes[1]==SR_KEMIP_STR
326
+				&& ket->ptypes[2]==SR_KEMIP_STR) {
327
+			if(!PyArg_ParseTuple(args, "sss:kemi-param-sss", &vps[0].s.s,
328
+						&vps[1].s.s, &vps[2].s.s)) {
329
+				LM_ERR("unable to retrieve str-str-str param %d\n", i);
330
+				return sr_kemi_apy_return_false();
331
+			}
332
+			vps[0].s.len = strlen(vps[0].s.s);
333
+			vps[1].s.len = strlen(vps[1].s.s);
334
+			vps[2].s.len = strlen(vps[2].s.s);
335
+			LM_DBG("params[%d] for: %.*s are str-str-int: [%.*s] [%.*s]"
336
+					" [%.*s]\n", i, fname.len, fname.s,
337
+					vps[0].s.len, vps[0].s.s,
338
+					vps[1].s.len, vps[1].s.s, vps[2].s.len, vps[2].s.s);
339
+		} else {
340
+			LM_ERR("not implemented yet\n");
341
+			return sr_kemi_apy_return_false();
342
+		}
343
+	} else if(ket->ptypes[4]==SR_KEMIP_NONE) {
344
+		i = 4;
345
+		if(ket->ptypes[0]==SR_KEMIP_STR
346
+				|| ket->ptypes[1]==SR_KEMIP_STR
347
+				|| ket->ptypes[2]==SR_KEMIP_STR
348
+				|| ket->ptypes[3]==SR_KEMIP_STR) {
349
+			if(!PyArg_ParseTuple(args, "ssss:kemi-param-ssss",
350
+						&vps[0].s.s, &vps[1].s.s, &vps[2].s.s, &vps[3].s.s)) {
351
+				LM_ERR("unable to retrieve str-str-str-str params %d\n", i);
352
+				return sr_kemi_apy_return_false();
353
+			}
354
+			vps[0].s.len = strlen(vps[0].s.s);
355
+			vps[1].s.len = strlen(vps[1].s.s);
356
+			vps[2].s.len = strlen(vps[2].s.s);
357
+			vps[3].s.len = strlen(vps[3].s.s);
358
+			LM_DBG("params[%d] for: %.*s are str: [%.*s] [%.*s]"
359
+					" [%.*s] [%.*s]\n", i,
360
+				fname.len, fname.s, vps[0].s.len, vps[0].s.s,
361
+				vps[1].s.len, vps[1].s.s, vps[2].s.len, vps[2].s.s,
362
+				vps[3].s.len, vps[3].s.s);
363
+		} else if(ket->ptypes[0]==SR_KEMIP_STR
364
+				|| ket->ptypes[1]==SR_KEMIP_STR
365
+				|| ket->ptypes[2]==SR_KEMIP_INT
366
+				|| ket->ptypes[3]==SR_KEMIP_INT) {
367
+			if(!PyArg_ParseTuple(args, "ssii:kemi-param-ssnn",
368
+						&vps[0].s.s, &vps[1].s.s, &vps[2].n, &vps[3].n)) {
369
+				LM_ERR("unable to retrieve str-str-int-int params %d\n", i);
370
+				return sr_kemi_apy_return_false();
371
+			}
372
+			vps[0].s.len = strlen(vps[0].s.s);
373
+			vps[1].s.len = strlen(vps[1].s.s);
374
+			LM_DBG("params[%d] for: %.*s are str: [%.*s] [%.*s]"
375
+					" [%d] [%d]\n", i,
376
+				fname.len, fname.s, vps[0].s.len, vps[0].s.s,
377
+				vps[1].s.len, vps[1].s.s, vps[2].n, vps[3].n);
378
+		} else {
379
+			LM_ERR("not implemented yet\n");
380
+			return sr_kemi_apy_return_false();
381
+		}
382
+	} else if(ket->ptypes[5]==SR_KEMIP_NONE) {
383
+		i = 5;
384
+		if(ket->ptypes[0]==SR_KEMIP_STR
385
+				|| ket->ptypes[1]==SR_KEMIP_STR
386
+				|| ket->ptypes[2]==SR_KEMIP_STR
387
+				|| ket->ptypes[3]==SR_KEMIP_STR
388
+				|| ket->ptypes[4]==SR_KEMIP_STR) {
389
+			if(!PyArg_ParseTuple(args, "sssss:kemi-param-sssss",
390
+						&vps[0].s.s, &vps[1].s.s, &vps[2].s.s, &vps[3].s.s,
391
+						&vps[4].s.s)) {
392
+				LM_ERR("unable to retrieve str-str-str-str params %d\n", i);
393
+				return sr_kemi_apy_return_false();
394
+			}
395
+			vps[0].s.len = strlen(vps[0].s.s);
396
+			vps[1].s.len = strlen(vps[1].s.s);
397
+			vps[2].s.len = strlen(vps[2].s.s);
398
+			vps[3].s.len = strlen(vps[3].s.s);
399
+			vps[4].s.len = strlen(vps[4].s.s);
400
+			LM_DBG("params[%d] for: %.*s are str: [%.*s] [%.*s]"
401
+					" [%.*s] [%.*s] [%.*s]\n", i,
402
+				fname.len, fname.s, vps[0].s.len, vps[0].s.s,
403
+				vps[1].s.len, vps[1].s.s, vps[2].s.len, vps[2].s.s,
404
+				vps[3].s.len, vps[3].s.s, vps[4].s.len, vps[4].s.s);
405
+		} else {
406
+			LM_ERR("not implemented yet\n");
407
+			return sr_kemi_apy_return_false();
408
+		}
409
+	} else {
410
+		i = 6;
411
+		if(ket->ptypes[0]==SR_KEMIP_STR
412
+				|| ket->ptypes[1]==SR_KEMIP_STR
413
+				|| ket->ptypes[2]==SR_KEMIP_STR
414
+				|| ket->ptypes[3]==SR_KEMIP_STR
415
+				|| ket->ptypes[4]==SR_KEMIP_STR
416
+				|| ket->ptypes[5]==SR_KEMIP_STR) {
417
+			if(!PyArg_ParseTuple(args, "ssssss:kemi-param-ssssss",
418
+						&vps[0].s.s, &vps[1].s.s, &vps[2].s.s, &vps[3].s.s,
419
+						&vps[4].s.s, &vps[5].s.s)) {
420
+				LM_ERR("unable to retrieve str-str-str-str params %d\n", i);
421
+				return sr_kemi_apy_return_false();
422
+			}
423
+			vps[0].s.len = strlen(vps[0].s.s);
424
+			vps[1].s.len = strlen(vps[1].s.s);
425
+			vps[2].s.len = strlen(vps[2].s.s);
426
+			vps[3].s.len = strlen(vps[3].s.s);
427
+			vps[4].s.len = strlen(vps[4].s.s);
428
+			vps[5].s.len = strlen(vps[5].s.s);
429
+			LM_DBG("params[%d] for: %.*s are str: [%.*s] [%.*s]"
430
+					" [%.*s] [%.*s] [%.*s] [%.*s]\n", i,
431
+				fname.len, fname.s, vps[0].s.len, vps[0].s.s,
432
+				vps[1].s.len, vps[1].s.s, vps[2].s.len, vps[2].s.s,
433
+				vps[3].s.len, vps[3].s.s, vps[4].s.len, vps[4].s.s,
434
+				vps[5].s.len, vps[5].s.s);
435
+		} else {
436
+			LM_ERR("not implemented yet\n");
437
+			return sr_kemi_apy_return_false();
438
+		}
439
+	}
440
+
441
+	switch(i) {
442
+		case 1:
443
+			if(ket->ptypes[0]==SR_KEMIP_INT) {
444
+				ret = ((sr_kemi_fmn_f)(ket->func))(lmsg, vps[0].n);
445
+				return sr_kemi_apy_return_int(ket, ret);
446
+			} else if(ket->ptypes[0]==SR_KEMIP_STR) {
447
+				ret = ((sr_kemi_fms_f)(ket->func))(lmsg, &vps[0].s);
448
+				return sr_kemi_apy_return_int(ket, ret);
449
+			} else {
450
+				LM_ERR("invalid parameters for: %.*s\n",
451
+						fname.len, fname.s);
452
+				return sr_kemi_apy_return_false();
453
+			}
454
+		break;
455
+		case 2:
456
+			if(ket->ptypes[0]==SR_KEMIP_INT) {
457
+				if(ket->ptypes[1]==SR_KEMIP_INT) {
458
+					ret = ((sr_kemi_fmnn_f)(ket->func))(lmsg, vps[0].n, vps[1].n);
459
+					return sr_kemi_apy_return_int(ket, ret);
460
+				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
461
+					ret = ((sr_kemi_fmns_f)(ket->func))(lmsg, vps[0].n, &vps[1].s);
462
+					return sr_kemi_apy_return_int(ket, ret);
463
+				} else {
464
+					LM_ERR("invalid parameters for: %.*s\n",
465
+							fname.len, fname.s);
466
+					return sr_kemi_apy_return_false();
467
+				}
468
+			} else if(ket->ptypes[0]==SR_KEMIP_STR) {
469
+				if(ket->ptypes[1]==SR_KEMIP_INT) {
470
+					ret = ((sr_kemi_fmsn_f)(ket->func))(lmsg, &vps[0].s, vps[1].n);
471
+					return sr_kemi_apy_return_int(ket, ret);
472
+				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
473
+					ret = ((sr_kemi_fmss_f)(ket->func))(lmsg, &vps[0].s, &vps[1].s);
474
+					return sr_kemi_apy_return_int(ket, ret);
475
+				} else {
476
+					LM_ERR("invalid parameters for: %.*s\n",
477
+							fname.len, fname.s);
478
+					return sr_kemi_apy_return_false();
479
+				}
480
+			} else {
481
+				LM_ERR("invalid parameters for: %.*s\n",
482
+						fname.len, fname.s);
483
+				return sr_kemi_apy_return_false();
484
+			}
485
+		break;
486
+		case 3:
487
+			if(ket->ptypes[0]==SR_KEMIP_INT) {
488
+				if(ket->ptypes[1]==SR_KEMIP_INT) {
489
+					if(ket->ptypes[2]==SR_KEMIP_INT) {
490
+						/* nnn */
491
+						ret = ((sr_kemi_fmnnn_f)(ket->func))(lmsg,
492
+								vps[0].n, vps[1].n, vps[2].n);
493
+						return sr_kemi_apy_return_int(ket, ret);
494
+					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
495
+						/* nns */
496
+						ret = ((sr_kemi_fmnns_f)(ket->func))(lmsg,
497
+								vps[0].n, vps[1].n, &vps[2].s);
498
+						return sr_kemi_apy_return_int(ket, ret);
499
+					} else {
500
+						LM_ERR("invalid parameters for: %.*s\n",
501
+								fname.len, fname.s);
502
+						return sr_kemi_apy_return_false();
503
+					}
504
+				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
505
+					if(ket->ptypes[2]==SR_KEMIP_INT) {
506
+						/* nsn */
507
+						ret = ((sr_kemi_fmnsn_f)(ket->func))(lmsg,
508
+								vps[0].n, &vps[1].s, vps[2].n);
509
+						return sr_kemi_apy_return_int(ket, ret);
510
+					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
511
+						/* nss */
512
+						ret = ((sr_kemi_fmnss_f)(ket->func))(lmsg,
513
+								vps[0].n, &vps[1].s, &vps[2].s);
514
+						return sr_kemi_apy_return_int(ket, ret);
515
+					} else {
516
+						LM_ERR("invalid parameters for: %.*s\n",
517
+								fname.len, fname.s);
518
+						return sr_kemi_apy_return_false();
519
+					}
520
+				} else {
521
+					LM_ERR("invalid parameters for: %.*s\n",
522
+							fname.len, fname.s);
523
+					return sr_kemi_apy_return_false();
524
+				}
525
+			} else if(ket->ptypes[0]==SR_KEMIP_STR) {
526
+				if(ket->ptypes[1]==SR_KEMIP_INT) {
527
+					if(ket->ptypes[2]==SR_KEMIP_INT) {
528
+						/* snn */
529
+						ret = ((sr_kemi_fmsnn_f)(ket->func))(lmsg,
530
+								&vps[0].s, vps[1].n, vps[2].n);
531
+						return sr_kemi_apy_return_int(ket, ret);
532
+					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
533
+						/* sns */
534
+						ret = ((sr_kemi_fmsns_f)(ket->func))(lmsg,
535
+								&vps[0].s, vps[1].n, &vps[2].s);
536
+						return sr_kemi_apy_return_int(ket, ret);
537
+					} else {
538
+						LM_ERR("invalid parameters for: %.*s\n",
539
+								fname.len, fname.s);
540
+						return sr_kemi_apy_return_false();
541
+					}
542
+				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
543
+					if(ket->ptypes[2]==SR_KEMIP_INT) {
544
+						/* ssn */
545
+						ret = ((sr_kemi_fmssn_f)(ket->func))(lmsg,
546
+								&vps[0].s, &vps[1].s, vps[2].n);
547
+						return sr_kemi_apy_return_int(ket, ret);
548
+					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
549
+						/* sss */
550
+						ret = ((sr_kemi_fmsss_f)(ket->func))(lmsg,
551
+								&vps[0].s, &vps[1].s, &vps[2].s);
552
+						return sr_kemi_apy_return_int(ket, ret);
553
+					} else {
554
+						LM_ERR("invalid parameters for: %.*s\n",
555
+								fname.len, fname.s);
556
+						return sr_kemi_apy_return_false();
557
+					}
558
+				} else {
559
+					LM_ERR("invalid parameters for: %.*s\n",
560
+							fname.len, fname.s);
561
+					return sr_kemi_apy_return_false();
562
+				}
563
+			} else {
564
+				LM_ERR("invalid parameters for: %.*s\n",
565
+						fname.len, fname.s);
566
+				return sr_kemi_apy_return_false();
567
+			}
568
+		break;
569
+		case 4:
570
+			if(ket->ptypes[0]==SR_KEMIP_STR
571
+					|| ket->ptypes[1]==SR_KEMIP_STR
572
+					|| ket->ptypes[2]==SR_KEMIP_STR
573
+					|| ket->ptypes[3]==SR_KEMIP_STR) {
574
+				/* ssss */
575
+				ret = ((sr_kemi_fmssss_f)(ket->func))(lmsg,
576
+						&vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s);
577
+				return sr_kemi_apy_return_int(ket, ret);
578
+			} else if(ket->ptypes[0]==SR_KEMIP_STR
579