app_ruby: memset rbdata to 0 in app_ruby_run_ex()
[sip-router] / src / modules / app_ruby / app_ruby_api.c
1 /**
2  * Copyright (C) 2018 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file 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  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "../../core/dprint.h"
30 #include "../../core/pvar.h"
31 #include "../../core/sr_module.h"
32 #include "../../core/mem/shm.h"
33 #include "../../core/kemi.h"
34 #include "../../core/rpc.h"
35 #include "../../core/rpc_lookup.h"
36
37 #include "app_ruby_api.h"
38 #include "app_ruby_kemi_export.h"
39
40 /* ruby.h defines xmalloc macro, replacing the shm.xmalloc field name */
41 #undef xmalloc
42 #undef xfree
43
44 int app_ruby_kemi_export_libs(void);
45
46 typedef struct _sr_ruby_env
47 {
48         ksr_ruby_context_t *R;
49         sip_msg_t *msg;
50         int rinit;
51         unsigned int flags;
52         unsigned int nload; /* number of scripts loaded */
53 } sr_ruby_env_t;
54
55 typedef struct ksr_ruby_data {
56         VALUE robj;
57         ID metid;
58         int nargs;
59         VALUE vargs[4];
60 } ksr_ruby_data_t;
61
62 static sr_ruby_env_t _sr_R_env = {0};
63
64 str _sr_ruby_load_file = STR_NULL;
65
66 static int *_sr_ruby_reload_version = NULL;
67 static int _sr_ruby_local_version = 0;
68
69 /**
70  *
71  */
72 sr_ruby_env_t *app_ruby_sr_env_get(void)
73 {
74         return &_sr_R_env;
75 }
76
77 /**
78  * 
79  */
80 int ruby_sr_init_mod(void)
81 {
82         if(_sr_ruby_load_file.s == NULL || _sr_ruby_load_file.len<=0) {
83                 LM_ERR("no ruby script file to load was provided\n");
84                 return -1;
85         }
86         if(_sr_ruby_reload_version == NULL) {
87                 _sr_ruby_reload_version = (int*)shm_malloc(sizeof(int));
88                 if(_sr_ruby_reload_version == NULL) {
89                         LM_ERR("failed to allocated reload version\n");
90                         return -1;
91                 }
92                 *_sr_ruby_reload_version = 0;
93         }
94         memset(&_sr_R_env, 0, sizeof(sr_ruby_env_t));
95         return 0;
96 }
97
98 static int app_ruby_print_last_exception()
99 {
100         VALUE rException, rExceptStr;
101
102         rException = rb_errinfo();         /* get last exception */
103         rb_set_errinfo(Qnil);              /* clear last exception */
104         rExceptStr = rb_funcall(rException, rb_intern("to_s"), 0, Qnil);
105         if(RSTRING_LEN(rExceptStr)!=4
106                         || strncmp(RSTRING_PTR(rExceptStr), "exit", 4)!=0) {
107                 LM_ERR("exception: %.*s\n", (int)RSTRING_LEN(rExceptStr),
108                                 RSTRING_PTR(rExceptStr));
109                 return 0;
110         }
111         return 1;
112 }
113
114 /**
115  *
116  */
117 int app_ruby_kemi_load_script(void)
118 {
119         int state = 0;
120         VALUE script;
121
122         script  = rb_str_new_cstr(_sr_ruby_load_file.s);
123
124         /* handle exceptions like rb_eval_string_protect() */
125         rb_load_protect(script, 0, &state);
126
127         if (state) {
128                 /* got exception */
129                 app_ruby_print_last_exception();
130                 LM_ERR("failed to load rb script file: %.*s (%d)\n",
131                                 _sr_ruby_load_file.len, _sr_ruby_load_file.s, state);
132                 // return -1;
133         }
134         LM_DBG("rb script loaded: %s\n", _sr_ruby_load_file.s);
135
136         return 0;
137 }
138
139 /**
140  *
141  */
142 int app_ruby_kemi_reload_script(void)
143 {
144         int v;
145         if(_sr_ruby_load_file.s == NULL && _sr_ruby_load_file.len<=0) {
146                 LM_WARN("script file path not provided\n");
147                 return -1;
148         }
149         if(_sr_ruby_reload_version == NULL) {
150                 LM_WARN("reload not enabled\n");
151                 return -1;
152         }
153         if(_sr_R_env.rinit == 0) {
154                 LM_ERR("load ruby context not created\n");
155                 return -1;
156         }
157
158         v = *_sr_ruby_reload_version;
159         if(v == _sr_ruby_local_version) {
160                 /* same version */
161                 return 0;
162         }
163         LM_DBG("reloading ruby script file: %.*s (%d => %d)\n",
164                                 _sr_ruby_load_file.len, _sr_ruby_load_file.s,
165                                 _sr_ruby_local_version, v);
166         app_ruby_kemi_load_script();
167         _sr_ruby_local_version = v;
168         return 0;
169 }
170
171 /**
172  *
173  */
174 int ruby_sr_init_child(void)
175 {
176         int state = 0;
177         VALUE rbres;
178
179         /* construct the VM */
180         ruby_init();
181         ruby_init_loadpath();
182         ruby_script(_sr_ruby_load_file.s);
183
184         /* Ruby goes here */
185         rbres = rb_eval_string_protect("puts 'Hello " NAME "!'", &state);
186
187         if (state) {
188                 /* handle exception */
189                 app_ruby_print_last_exception();
190                 LM_ERR("test execution with error (res type: %d)\n", TYPE(rbres));
191                 return -1;
192         } else {
193                 LM_DBG("test execution without error\n");
194         }
195
196         if(app_ruby_kemi_export_libs()<0) {
197                 return -1;
198         }
199
200         if(app_ruby_kemi_load_script()<0) {
201                 return -1;
202         }
203
204         _sr_R_env.rinit = 1;
205
206         return 0;
207 }
208
209 /**
210  * 
211  */
212 void ruby_sr_destroy(void)
213 {
214         if(_sr_R_env.rinit == 1) {
215                 return;
216         }
217         memset(&_sr_R_env, 0, sizeof(sr_ruby_env_t));
218         /* destruct the VM */
219         ruby_cleanup(0);
220         return;
221 }
222
223 /**
224  * 
225  */
226 int ruby_sr_initialized(void)
227 {
228         if(_sr_R_env.rinit==1) {
229                 return 1;
230         }
231         return 0;
232 }
233
234 /**
235  *
236  */
237 int sr_kemi_ruby_return_int(sr_kemi_t *ket, int rc)
238 {
239         if(ket->rtype==SR_KEMIP_INT || ket->rtype==SR_KEMIP_XVAL) {
240                 return INT2NUM(rc);
241         }
242         if(ket->rtype==SR_KEMIP_BOOL && rc!=SR_KEMI_FALSE) {
243                 return Qtrue;
244         }
245         return Qfalse;
246 }
247
248 /**
249  *
250  */
251 static VALUE app_ruby_sr_modf(int argc, VALUE* argv, VALUE self)
252 {
253         int ret;
254         char *rbv[MAX_ACTIONS];
255         char *paramv[MAX_ACTIONS];
256         int i;
257         int mod_type;
258         struct run_act_ctx ra_ctx;
259         struct action *act;
260         ksr_cmd_export_t* expf;
261         sr_ruby_env_t *env_R;
262
263         ret = 1;
264         act = NULL;
265         memset(rbv, 0, MAX_ACTIONS*sizeof(char*));
266         memset(paramv, 0, MAX_ACTIONS*sizeof(char*));
267         env_R = app_ruby_sr_env_get();
268         if(env_R->msg==NULL)
269                 goto error;
270
271         if(argc==0) {
272                 LM_ERR("name of module function not provided\n");
273                 goto error;
274         }
275         if(argc>=MAX_ACTIONS) {
276                 LM_ERR("too many parameters\n");
277                 goto error;
278         }
279         /* first is function name, then parameters */
280         for(i=0; i<argc; i++) {
281                 if(!RB_TYPE_P(argv[i], T_STRING)) {
282                         LM_ERR("invalid parameter type (%d)\n", i);
283                         return INT2NUM(-1);
284                 }
285                 rbv[i] = (char*)StringValuePtr(argv[i]);
286         }
287         LM_ERR("request to execute cfg function '%s'\n", rbv[0]);
288         /* pkg copy only parameters */
289         for(i=1; i<MAX_ACTIONS; i++) {
290                 if(rbv[i]!=NULL) {
291                         paramv[i] = (char*)pkg_malloc(strlen(rbv[i])+1);
292                         if(paramv[i]==NULL) {
293                                 LM_ERR("no more pkg\n");
294                                 goto error;
295                         }
296                         strcpy(paramv[i], rbv[i]);
297                 }
298         }
299
300         expf = find_export_record(rbv[0], argc-1, 0);
301         if (expf==NULL) {
302                 LM_ERR("function '%s' is not available\n", rbv[0]);
303                 goto error;
304         }
305         /* check fixups */
306         if (expf->fixup!=NULL && expf->free_fixup==NULL) {
307                 LM_ERR("function '%s' has fixup - cannot be used\n", rbv[0]);
308                 goto error;
309         }
310         switch(expf->param_no) {
311                 case 0:
312                         mod_type = MODULE0_T;
313                         break;
314                 case 1:
315                         mod_type = MODULE1_T;
316                         break;
317                 case 2:
318                         mod_type = MODULE2_T;
319                         break;
320                 case 3:
321                         mod_type = MODULE3_T;
322                         break;
323                 case 4:
324                         mod_type = MODULE4_T;
325                         break;
326                 case 5:
327                         mod_type = MODULE5_T;
328                         break;
329                 case 6:
330                         mod_type = MODULE6_T;
331                         break;
332                 case VAR_PARAM_NO:
333                         mod_type = MODULEX_T;
334                         break;
335                 default:
336                         LM_ERR("unknown/bad definition for function '%s' (%d params)\n",
337                                         rbv[0], expf->param_no);
338                         goto error;
339         }
340
341         act = mk_action(mod_type,  argc+1   /* number of (type, value) pairs */,
342                                         MODEXP_ST, expf,    /* function */
343                                         NUMBER_ST, argc-1,  /* parameter number */
344                                         STRING_ST, paramv[1], /* param. 1 */
345                                         STRING_ST, paramv[2], /* param. 2 */
346                                         STRING_ST, paramv[3], /* param. 3 */
347                                         STRING_ST, paramv[4], /* param. 4 */
348                                         STRING_ST, paramv[5], /* param. 5 */
349                                         STRING_ST, paramv[6]  /* param. 6 */
350                         );
351
352         if (act==NULL) {
353                 LM_ERR("action structure could not be created for '%s'\n", rbv[0]);
354                 goto error;
355         }
356
357         /* handle fixups */
358         if (expf->fixup) {
359                 if(argc==1) {
360                         /* no parameters */
361                         if(expf->fixup(0, 0)<0) {
362                                 LM_ERR("Error in fixup (0) for '%s'\n", rbv[0]);
363                                 goto error;
364                         }
365                 } else {
366                         for(i=1; i<argc; i++) {
367                                 if(expf->fixup(&(act->val[i+1].u.data), i)<0) {
368                                         LM_ERR("Error in fixup (%d) for '%s'\n", i, rbv[0]);
369                                         goto error;
370                                 }
371                                 act->val[i+1].type = MODFIXUP_ST;
372                         }
373                 }
374         }
375         init_run_actions_ctx(&ra_ctx);
376         ret = do_action(&ra_ctx, act, env_R->msg);
377
378         /* free fixups */
379         if (expf->fixup) {
380                 for(i=1; i<argc; i++) {
381                         if ((act->val[i+1].type == MODFIXUP_ST) && (act->val[i+1].u.data)) {
382                                 expf->free_fixup(&(act->val[i+1].u.data), i);
383                         }
384                 }
385         }
386         pkg_free(act);
387         for(i=0; i<MAX_ACTIONS; i++) {
388                 if(paramv[i]!=NULL) pkg_free(paramv[i]);
389                 paramv[i] = 0;
390         }
391         return INT2NUM(ret);
392
393 error:
394         if(act!=NULL)
395                 pkg_free(act);
396         for(i=0; i<MAX_ACTIONS; i++) {
397                 if(paramv[i]!=NULL) pkg_free(paramv[i]);
398                 paramv[i] = 0;
399         }
400         return INT2NUM(-1);
401 }
402
403 /**
404  *
405  */
406 static ksr_ruby_export_t _sr_kemi_x_R_Map[] = {
407         {"X", "modf", app_ruby_sr_modf},
408         {0, 0, 0}
409 };
410
411 /**
412  *
413  */
414 static VALUE ksr_ruby_exec_callback(VALUE ptr)
415 {
416         ksr_ruby_data_t *data = (ksr_ruby_data_t *)ptr;
417         return rb_funcall2(data->robj, data->metid, data->nargs, data->vargs);
418 }
419
420 /**
421  *
422  */
423 VALUE sr_kemi_ruby_return_xval(sr_kemi_t *ket, sr_kemi_xval_t *rx)
424 {
425         switch(rx->vtype) {
426                 case SR_KEMIP_NONE:
427                         return Qnil;
428                 case SR_KEMIP_INT:
429                         return INT2NUM(rx->v.n);
430                 case SR_KEMIP_STR:
431                         return rb_str_new(rx->v.s.s, rx->v.s.len);
432                 case SR_KEMIP_BOOL:
433                         if(rx->v.n!=SR_KEMI_FALSE) {
434                                 return Qtrue;
435                         } else {
436                                 return Qfalse;
437                         }
438                 case SR_KEMIP_XVAL:
439                         /* unknown content - return false */
440                         return Qfalse;
441                 case SR_KEMIP_NULL:
442                         return Qnil;
443                 default:
444                         /* unknown type - return false */
445                         return Qfalse;
446         }
447 }
448
449 /**
450  *
451  */
452 VALUE sr_kemi_ruby_exec_func_ex(ksr_ruby_context_t *R, sr_kemi_t *ket, int argc,
453                 VALUE* argv, VALUE self)
454 {
455         sr_kemi_val_t vps[SR_KEMI_PARAMS_MAX];
456         sr_ruby_env_t *env_R;
457         str *fname;
458         str *mname;
459         int i;
460         int ret = -1;
461         sr_kemi_xval_t *xret;
462
463         env_R = app_ruby_sr_env_get();
464         if(env_R==NULL || env_R->msg==NULL || ket==NULL) {
465                 LM_ERR("invalid ruby environment attributes or parameters (%p/%p/%p)\n",
466                                 env_R, env_R->msg, ket);
467                 return Qfalse;
468         }
469
470         if(argc==0 && ket->ptypes[0]==SR_KEMIP_NONE) {
471                 if(ket->rtype==SR_KEMIP_XVAL) {
472                         xret = ((sr_kemi_xfm_f)(ket->func))(env_R->msg);
473                         return sr_kemi_ruby_return_xval(ket, xret);
474                 } else {
475                         ret = ((sr_kemi_fm_f)(ket->func))(env_R->msg);
476                         return sr_kemi_ruby_return_int(ket, ret);
477                 }
478         }
479         fname = &ket->fname;
480         mname = &ket->mname;
481         if(argc==0 && ket->ptypes[0]!=SR_KEMIP_NONE) {
482                 LM_ERR("invalid number of parameters for: %.*s.%.*s\n",
483                                 mname->len, mname->s, fname->len, fname->s);
484                 return Qfalse;
485         }
486
487         if(argc>SR_KEMI_PARAMS_MAX) {
488                 LM_ERR("too many parameters for: %.*s.%.*s\n",
489                                 mname->len, mname->s, fname->len, fname->s);
490                 return Qfalse;
491         }
492
493         memset(vps, 0, SR_KEMI_PARAMS_MAX*sizeof(sr_kemi_val_t));
494         for(i=0; i<SR_KEMI_PARAMS_MAX; i++) {
495                 if(ket->ptypes[i]==SR_KEMIP_NONE) {
496                         break;
497                 } else if(ket->ptypes[i]==SR_KEMIP_STR) {
498                         if(!RB_TYPE_P(argv[i], T_STRING)) {
499                                 LM_ERR("invalid str parameter type %d (%d)\n", ket->ptypes[i], i);
500                                 return Qfalse;
501                         }
502                         vps[i].s.s = StringValuePtr(argv[i]);
503                         vps[i].s.len = strlen(vps[i].s.s);
504                         LM_DBG("param[%d] for: %.*s.%.*s is str: %.*s\n", i,
505                                 mname->len, mname->s, fname->len, fname->s, vps[i].s.len, vps[i].s.s);
506                 } else if(ket->ptypes[i]==SR_KEMIP_INT) {
507                         if(!RB_TYPE_P(argv[i], T_FIXNUM)) {
508                                 LM_ERR("invalid int parameter type %d (%d)\n", ket->ptypes[i], i);
509                                 return Qfalse;
510                         }
511                         vps[i].n = NUM2INT(argv[i]);
512                         LM_DBG("param[%d] for: %.*s.%.*s is int: %d\n", i,
513                                 mname->len, mname->s, fname->len, fname->s, vps[i].n);
514                 } else {
515                         LM_ERR("unknown parameter type %d (%d)\n", ket->ptypes[i], i);
516                         return Qfalse;
517                 }
518         }
519
520         switch(i) {
521                 case 1:
522                         if(ket->ptypes[0]==SR_KEMIP_INT) {
523                                 if(ket->rtype==SR_KEMIP_XVAL) {
524                                         xret = ((sr_kemi_xfmn_f)(ket->func))(env_R->msg, vps[0].n);
525                                         return sr_kemi_ruby_return_xval(ket, xret);
526                                 } else {
527                                         ret = ((sr_kemi_fmn_f)(ket->func))(env_R->msg, vps[0].n);
528                                         return sr_kemi_ruby_return_int(ket, ret);
529                                 }
530                         } else if(ket->ptypes[0]==SR_KEMIP_STR) {
531                                 if(ket->rtype==SR_KEMIP_XVAL) {
532                                         xret = ((sr_kemi_xfms_f)(ket->func))(env_R->msg, &vps[0].s);
533                                         return sr_kemi_ruby_return_xval(ket, xret);
534                                 } else {
535                                         ret = ((sr_kemi_fms_f)(ket->func))(env_R->msg, &vps[0].s);
536                                         return sr_kemi_ruby_return_int(ket, ret);
537                                 }
538                         } else {
539                                 LM_ERR("invalid parameters for: %.*s\n",
540                                                 fname->len, fname->s);
541                                 return Qfalse;
542                         }
543                 break;
544                 case 2:
545                         if(ket->ptypes[0]==SR_KEMIP_INT) {
546                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
547                                         if(ket->rtype==SR_KEMIP_XVAL) {
548                                                 xret = ((sr_kemi_xfmnn_f)(ket->func))(env_R->msg, vps[0].n, vps[1].n);
549                                                 return sr_kemi_ruby_return_xval(ket, xret);
550                                         } else {
551                                                 ret = ((sr_kemi_fmnn_f)(ket->func))(env_R->msg, vps[0].n, vps[1].n);
552                                                 return sr_kemi_ruby_return_int(ket, ret);
553                                         }
554                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
555                                         if(ket->rtype==SR_KEMIP_XVAL) {
556                                                 xret = ((sr_kemi_xfmns_f)(ket->func))(env_R->msg, vps[0].n, &vps[1].s);
557                                                 return sr_kemi_ruby_return_xval(ket, xret);
558                                         } else {
559                                                 ret = ((sr_kemi_fmns_f)(ket->func))(env_R->msg, vps[0].n, &vps[1].s);
560                                                 return sr_kemi_ruby_return_int(ket, ret);
561                                         }
562                                 } else {
563                                         LM_ERR("invalid parameters for: %.*s\n",
564                                                         fname->len, fname->s);
565                                         return Qfalse;
566                                 }
567                         } else if(ket->ptypes[0]==SR_KEMIP_STR) {
568                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
569                                         if(ket->rtype==SR_KEMIP_XVAL) {
570                                                 xret = ((sr_kemi_xfmsn_f)(ket->func))(env_R->msg, &vps[0].s, vps[1].n);
571                                                 return sr_kemi_ruby_return_xval(ket, xret);
572                                         } else {
573                                                 ret = ((sr_kemi_fmsn_f)(ket->func))(env_R->msg, &vps[0].s, vps[1].n);
574                                                 return sr_kemi_ruby_return_int(ket, ret);
575                                         }
576                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
577                                         if(ket->rtype==SR_KEMIP_XVAL) {
578                                                 xret = ((sr_kemi_xfmss_f)(ket->func))(env_R->msg, &vps[0].s, &vps[1].s);
579                                                 return sr_kemi_ruby_return_xval(ket, xret);
580                                         } else {
581                                                 ret = ((sr_kemi_fmss_f)(ket->func))(env_R->msg, &vps[0].s, &vps[1].s);
582                                                 return sr_kemi_ruby_return_int(ket, ret);
583                                         }
584                                 } else {
585                                         LM_ERR("invalid parameters for: %.*s\n",
586                                                         fname->len, fname->s);
587                                         return Qfalse;
588                                 }
589                         } else {
590                                 LM_ERR("invalid parameters for: %.*s\n",
591                                                 fname->len, fname->s);
592                                 return Qfalse;
593                         }
594                 break;
595                 case 3:
596                         if(ket->ptypes[0]==SR_KEMIP_INT) {
597                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
598                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
599                                                 ret = ((sr_kemi_fmnnn_f)(ket->func))(env_R->msg,
600                                                                 vps[0].n, vps[1].n, vps[2].n);
601                                                 return sr_kemi_ruby_return_int(ket, ret);
602                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
603                                                 ret = ((sr_kemi_fmnns_f)(ket->func))(env_R->msg,
604                                                                 vps[0].n, vps[1].n, &vps[2].s);
605                                                 return sr_kemi_ruby_return_int(ket, ret);
606                                         } else {
607                                                 LM_ERR("invalid parameters for: %.*s\n",
608                                                                 fname->len, fname->s);
609                                                 return Qfalse;
610                                         }
611                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
612                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
613                                                 ret = ((sr_kemi_fmnsn_f)(ket->func))(env_R->msg,
614                                                                 vps[0].n, &vps[1].s, vps[2].n);
615                                                 return sr_kemi_ruby_return_int(ket, ret);
616                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
617                                                 ret = ((sr_kemi_fmnss_f)(ket->func))(env_R->msg,
618                                                                 vps[0].n, &vps[1].s, &vps[2].s);
619                                                 return sr_kemi_ruby_return_int(ket, ret);
620                                         } else {
621                                                 LM_ERR("invalid parameters for: %.*s\n",
622                                                                 fname->len, fname->s);
623                                                 return Qfalse;
624                                         }
625                                 } else {
626                                         LM_ERR("invalid parameters for: %.*s\n",
627                                                         fname->len, fname->s);
628                                         return Qfalse;
629                                 }
630                         } else if(ket->ptypes[0]==SR_KEMIP_STR) {
631                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
632                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
633                                                 ret = ((sr_kemi_fmsnn_f)(ket->func))(env_R->msg,
634                                                                 &vps[0].s, vps[1].n, vps[2].n);
635                                                 return sr_kemi_ruby_return_int(ket, ret);
636                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
637                                                 ret = ((sr_kemi_fmsns_f)(ket->func))(env_R->msg,
638                                                                 &vps[0].s, vps[1].n, &vps[2].s);
639                                                 return sr_kemi_ruby_return_int(ket, ret);
640                                         } else {
641                                                 LM_ERR("invalid parameters for: %.*s\n",
642                                                                 fname->len, fname->s);
643                                                 return Qfalse;
644                                         }
645                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
646                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
647                                                 ret = ((sr_kemi_fmssn_f)(ket->func))(env_R->msg,
648                                                                 &vps[0].s, &vps[1].s, vps[2].n);
649                                                 return sr_kemi_ruby_return_int(ket, ret);
650                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
651                                                 ret = ((sr_kemi_fmsss_f)(ket->func))(env_R->msg,
652                                                                 &vps[0].s, &vps[1].s, &vps[2].s);
653                                                 return sr_kemi_ruby_return_int(ket, ret);
654                                         } else {
655                                                 LM_ERR("invalid parameters for: %.*s\n",
656                                                                 fname->len, fname->s);
657                                                 return Qfalse;
658                                         }
659                                 } else {
660                                         LM_ERR("invalid parameters for: %.*s\n",
661                                                         fname->len, fname->s);
662                                         return Qfalse;
663                                 }
664                         } else {
665                                 LM_ERR("invalid parameters for: %.*s\n",
666                                                 fname->len, fname->s);
667                                 return Qfalse;
668                         }
669                 break;
670                 case 4:
671                         if(ket->ptypes[0]==SR_KEMIP_STR
672                                         && ket->ptypes[1]==SR_KEMIP_STR
673                                         && ket->ptypes[2]==SR_KEMIP_STR
674                                         && ket->ptypes[3]==SR_KEMIP_STR) {
675                                 ret = ((sr_kemi_fmssss_f)(ket->func))(env_R->msg,
676                                                 &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s);
677                                 return sr_kemi_ruby_return_int(ket, ret);
678                         } else if(ket->ptypes[0]==SR_KEMIP_STR
679                                         && ket->ptypes[1]==SR_KEMIP_STR
680                                         && ket->ptypes[2]==SR_KEMIP_STR
681                                         && ket->ptypes[3]==SR_KEMIP_INT) {
682                                 ret = ((sr_kemi_fmsssn_f)(ket->func))(env_R->msg,
683                                                 &vps[0].s, &vps[1].s, &vps[2].s, vps[3].n);
684                                 return sr_kemi_ruby_return_int(ket, ret);
685                         } else if(ket->ptypes[0]==SR_KEMIP_STR
686                                         && ket->ptypes[1]==SR_KEMIP_STR
687                                         && ket->ptypes[2]==SR_KEMIP_INT
688                                         && ket->ptypes[3]==SR_KEMIP_STR) {
689                                 ret = ((sr_kemi_fmssns_f)(ket->func))(env_R->msg,
690                                                 &vps[0].s, &vps[1].s, vps[2].n, &vps[3].s);
691                                 return sr_kemi_ruby_return_int(ket, ret);
692                         } else if(ket->ptypes[0]==SR_KEMIP_STR
693                                         && ket->ptypes[1]==SR_KEMIP_STR
694                                         && ket->ptypes[2]==SR_KEMIP_INT
695                                         && ket->ptypes[3]==SR_KEMIP_INT) {
696                                 ret = ((sr_kemi_fmssnn_f)(ket->func))(env_R->msg,
697                                                 &vps[0].s, &vps[1].s, vps[2].n, vps[3].n);
698                                 return sr_kemi_ruby_return_int(ket, ret);
699                         } else if(ket->ptypes[0]==SR_KEMIP_STR
700                                         && ket->ptypes[1]==SR_KEMIP_INT
701                                         && ket->ptypes[2]==SR_KEMIP_STR
702                                         && ket->ptypes[3]==SR_KEMIP_STR) {
703                                 ret = ((sr_kemi_fmsnss_f)(ket->func))(env_R->msg,
704                                                 &vps[0].s, vps[1].n, &vps[2].s, &vps[3].s);
705                                 return sr_kemi_ruby_return_int(ket, ret);
706                         } else if(ket->ptypes[0]==SR_KEMIP_STR
707                                         && ket->ptypes[1]==SR_KEMIP_INT
708                                         && ket->ptypes[2]==SR_KEMIP_STR
709                                         && ket->ptypes[3]==SR_KEMIP_INT) {
710                                 ret = ((sr_kemi_fmsnsn_f)(ket->func))(env_R->msg,
711                                                 &vps[0].s, vps[1].n, &vps[2].s, vps[3].n);
712                                 return sr_kemi_ruby_return_int(ket, ret);
713                         } else if(ket->ptypes[0]==SR_KEMIP_STR
714                                         && ket->ptypes[1]==SR_KEMIP_INT
715                                         && ket->ptypes[2]==SR_KEMIP_INT
716                                         && ket->ptypes[3]==SR_KEMIP_STR) {
717                                 ret = ((sr_kemi_fmsnns_f)(ket->func))(env_R->msg,
718                                                 &vps[0].s, vps[1].n, vps[2].n, &vps[3].s);
719                                 return sr_kemi_ruby_return_int(ket, ret);
720                         } else if(ket->ptypes[0]==SR_KEMIP_STR
721                                         && ket->ptypes[1]==SR_KEMIP_INT
722                                         && ket->ptypes[2]==SR_KEMIP_INT
723                                         && ket->ptypes[3]==SR_KEMIP_INT) {
724                                 ret = ((sr_kemi_fmsnnn_f)(ket->func))(env_R->msg,
725                                                 &vps[0].s, vps[1].n, vps[2].n, vps[3].n);
726                                 return sr_kemi_ruby_return_int(ket, ret);
727                         } else if(ket->ptypes[0]==SR_KEMIP_INT
728                                         && ket->ptypes[1]==SR_KEMIP_STR
729                                         && ket->ptypes[2]==SR_KEMIP_STR
730                                         && ket->ptypes[3]==SR_KEMIP_STR) {
731                                 ret = ((sr_kemi_fmnsss_f)(ket->func))(env_R->msg,
732                                                 vps[0].n, &vps[1].s, &vps[2].s, &vps[3].s);
733                                 return sr_kemi_ruby_return_int(ket, ret);
734                         } else if(ket->ptypes[0]==SR_KEMIP_INT
735                                         && ket->ptypes[1]==SR_KEMIP_STR
736                                         && ket->ptypes[2]==SR_KEMIP_STR
737                                         && ket->ptypes[3]==SR_KEMIP_INT) {
738                                 ret = ((sr_kemi_fmnssn_f)(ket->func))(env_R->msg,
739                                                 vps[0].n, &vps[1].s, &vps[2].s, vps[3].n);
740                                 return sr_kemi_ruby_return_int(ket, ret);
741                         } else if(ket->ptypes[0]==SR_KEMIP_INT
742                                         && ket->ptypes[1]==SR_KEMIP_STR
743                                         && ket->ptypes[2]==SR_KEMIP_INT
744                                         && ket->ptypes[3]==SR_KEMIP_STR) {
745                                 ret = ((sr_kemi_fmnsns_f)(ket->func))(env_R->msg,
746                                                 vps[0].n, &vps[1].s, vps[2].n, &vps[3].s);
747                                 return sr_kemi_ruby_return_int(ket, ret);
748                         } else if(ket->ptypes[0]==SR_KEMIP_INT
749                                         && ket->ptypes[1]==SR_KEMIP_STR
750                                         && ket->ptypes[2]==SR_KEMIP_INT
751                                         && ket->ptypes[3]==SR_KEMIP_INT) {
752                                 ret = ((sr_kemi_fmnsnn_f)(ket->func))(env_R->msg,
753                                                 vps[0].n, &vps[1].s, vps[2].n, vps[3].n);
754                                 return sr_kemi_ruby_return_int(ket, ret);
755                         } else if(ket->ptypes[0]==SR_KEMIP_INT
756                                         && ket->ptypes[1]==SR_KEMIP_INT
757                                         && ket->ptypes[2]==SR_KEMIP_STR
758                                         && ket->ptypes[3]==SR_KEMIP_STR) {
759                                 ret = ((sr_kemi_fmnnss_f)(ket->func))(env_R->msg,
760                                                 vps[0].n, vps[1].n, &vps[2].s, &vps[3].s);
761                                 return sr_kemi_ruby_return_int(ket, ret);
762                         } else if(ket->ptypes[0]==SR_KEMIP_INT
763                                         && ket->ptypes[1]==SR_KEMIP_INT
764                                         && ket->ptypes[2]==SR_KEMIP_STR
765                                         && ket->ptypes[3]==SR_KEMIP_INT) {
766                                 ret = ((sr_kemi_fmnnsn_f)(ket->func))(env_R->msg,
767                                                 vps[0].n, vps[1].n, &vps[2].s, vps[3].n);
768                                 return sr_kemi_ruby_return_int(ket, ret);
769                         } else if(ket->ptypes[0]==SR_KEMIP_INT
770                                         && ket->ptypes[1]==SR_KEMIP_INT
771                                         && ket->ptypes[2]==SR_KEMIP_INT
772                                         && ket->ptypes[3]==SR_KEMIP_STR) {
773                                 ret = ((sr_kemi_fmnnns_f)(ket->func))(env_R->msg,
774                                                 vps[0].n, vps[1].n, vps[2].n, &vps[3].s);
775                                 return sr_kemi_ruby_return_int(ket, ret);
776                         } else if(ket->ptypes[0]==SR_KEMIP_INT
777                                         && ket->ptypes[1]==SR_KEMIP_INT
778                                         && ket->ptypes[2]==SR_KEMIP_INT
779                                         && ket->ptypes[3]==SR_KEMIP_INT) {
780                                 ret = ((sr_kemi_fmnnnn_f)(ket->func))(env_R->msg,
781                                                 vps[0].n, vps[1].n, vps[2].n, vps[3].n);
782                                 return sr_kemi_ruby_return_int(ket, ret);
783                         } else {
784                                 LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s);
785                                 return Qfalse;
786                         }
787                 break;
788                 case 5:
789                         if(ket->ptypes[0]==SR_KEMIP_STR
790                                         && ket->ptypes[1]==SR_KEMIP_STR
791                                         && ket->ptypes[2]==SR_KEMIP_STR
792                                         && ket->ptypes[3]==SR_KEMIP_STR
793                                         && ket->ptypes[4]==SR_KEMIP_STR) {
794                                 ret = ((sr_kemi_fmsssss_f)(ket->func))(env_R->msg,
795                                                 &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s, &vps[4].s);
796                                 return sr_kemi_ruby_return_int(ket, ret);
797                         } else if(ket->ptypes[0]==SR_KEMIP_STR
798                                         && ket->ptypes[1]==SR_KEMIP_STR
799                                         && ket->ptypes[2]==SR_KEMIP_STR
800                                         && ket->ptypes[3]==SR_KEMIP_STR
801                                         && ket->ptypes[4]==SR_KEMIP_INT) {
802                                 ret = ((sr_kemi_fmssssn_f)(ket->func))(env_R->msg,
803                                                 &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s, vps[4].n);
804                                 return sr_kemi_ruby_return_int(ket, ret);
805                         } else if(ket->ptypes[0]==SR_KEMIP_STR
806                                         && ket->ptypes[1]==SR_KEMIP_STR
807                                         && ket->ptypes[2]==SR_KEMIP_STR
808                                         && ket->ptypes[3]==SR_KEMIP_INT
809                                         && ket->ptypes[4]==SR_KEMIP_STR) {
810                                 ret = ((sr_kemi_fmsssns_f)(ket->func))(env_R->msg,
811                                                 &vps[0].s, &vps[1].s, &vps[2].s, vps[3].n, &vps[4].s);
812                                 return sr_kemi_ruby_return_int(ket, ret);
813                         } else if(ket->ptypes[0]==SR_KEMIP_STR
814                                         && ket->ptypes[1]==SR_KEMIP_STR
815                                         && ket->ptypes[2]==SR_KEMIP_STR
816                                         && ket->ptypes[3]==SR_KEMIP_INT
817                                         && ket->ptypes[4]==SR_KEMIP_INT) {
818                                 ret = ((sr_kemi_fmsssnn_f)(ket->func))(env_R->msg,
819                                                 &vps[0].s, &vps[1].s, &vps[2].s, vps[3].n, vps[4].n);
820                                 return sr_kemi_ruby_return_int(ket, ret);
821                         } else if(ket->ptypes[0]==SR_KEMIP_STR
822                                         && ket->ptypes[1]==SR_KEMIP_STR
823                                         && ket->ptypes[2]==SR_KEMIP_INT
824                                         && ket->ptypes[3]==SR_KEMIP_STR
825                                         && ket->ptypes[4]==SR_KEMIP_STR) {
826                                 ret = ((sr_kemi_fmssnss_f)(ket->func))(env_R->msg,
827                                                 &vps[0].s, &vps[1].s, vps[2].n, &vps[3].s, &vps[4].s);
828                                 return sr_kemi_ruby_return_int(ket, ret);
829                         } else if(ket->ptypes[0]==SR_KEMIP_STR
830                                         && ket->ptypes[1]==SR_KEMIP_STR
831                                         && ket->ptypes[2]==SR_KEMIP_INT
832                                         && ket->ptypes[3]==SR_KEMIP_STR
833                                         && ket->ptypes[4]==SR_KEMIP_INT) {
834                                 ret = ((sr_kemi_fmssnsn_f)(ket->func))(env_R->msg,
835                                                 &vps[0].s, &vps[1].s, vps[2].n, &vps[3].s, vps[4].n);
836                                 return sr_kemi_ruby_return_int(ket, ret);
837                         } else if(ket->ptypes[0]==SR_KEMIP_STR
838                                         && ket->ptypes[1]==SR_KEMIP_STR
839                                         && ket->ptypes[2]==SR_KEMIP_INT
840                                         && ket->ptypes[3]==SR_KEMIP_INT
841                                         && ket->ptypes[4]==SR_KEMIP_STR) {
842                                 ret = ((sr_kemi_fmssnns_f)(ket->func))(env_R->msg,
843                                                 &vps[0].s, &vps[1].s, vps[2].n, vps[3].n, &vps[4].s);
844                                 return sr_kemi_ruby_return_int(ket, ret);
845                         } else if(ket->ptypes[0]==SR_KEMIP_STR
846                                         && ket->ptypes[1]==SR_KEMIP_STR
847                                         && ket->ptypes[2]==SR_KEMIP_INT
848                                         && ket->ptypes[3]==SR_KEMIP_INT
849                                         && ket->ptypes[4]==SR_KEMIP_INT) {
850                                 ret = ((sr_kemi_fmssnnn_f)(ket->func))(env_R->msg,
851                                                 &vps[0].s, &vps[1].s, vps[2].n, vps[3].n, vps[4].n);
852                                 return sr_kemi_ruby_return_int(ket, ret);
853                         } else if(ket->ptypes[0]==SR_KEMIP_STR
854                                         && ket->ptypes[1]==SR_KEMIP_INT
855                                         && ket->ptypes[2]==SR_KEMIP_STR
856                                         && ket->ptypes[3]==SR_KEMIP_STR
857                                         && ket->ptypes[4]==SR_KEMIP_STR) {
858                                 ret = ((sr_kemi_fmsnsss_f)(ket->func))(env_R->msg,
859                                                 &vps[0].s, vps[1].n, &vps[2].s, &vps[3].s, &vps[4].s);
860                                 return sr_kemi_ruby_return_int(ket, ret);
861                         } else if(ket->ptypes[0]==SR_KEMIP_STR
862                                         && ket->ptypes[1]==SR_KEMIP_INT
863                                         && ket->ptypes[2]==SR_KEMIP_STR
864                                         && ket->ptypes[3]==SR_KEMIP_STR
865                                         && ket->ptypes[4]==SR_KEMIP_INT) {
866                                 ret = ((sr_kemi_fmsnssn_f)(ket->func))(env_R->msg,
867                                                 &vps[0].s, vps[1].n, &vps[2].s, &vps[3].s, vps[4].n);
868                                 return sr_kemi_ruby_return_int(ket, ret);
869                         } else if(ket->ptypes[0]==SR_KEMIP_STR
870                                         && ket->ptypes[1]==SR_KEMIP_INT
871                                         && ket->ptypes[2]==SR_KEMIP_STR
872                                         && ket->ptypes[3]==SR_KEMIP_INT
873                                         && ket->ptypes[4]==SR_KEMIP_STR) {
874                                 ret = ((sr_kemi_fmsnsns_f)(ket->func))(env_R->msg,
875                                                 &vps[0].s, vps[1].n, &vps[2].s, vps[3].n, &vps[4].s);
876                                 return sr_kemi_ruby_return_int(ket, ret);
877                         } else if(ket->ptypes[0]==SR_KEMIP_STR
878                                         && ket->ptypes[1]==SR_KEMIP_INT
879                                         && ket->ptypes[2]==SR_KEMIP_STR
880                                         && ket->ptypes[3]==SR_KEMIP_INT
881                                         && ket->ptypes[4]==SR_KEMIP_INT) {
882                                 ret = ((sr_kemi_fmsnsnn_f)(ket->func))(env_R->msg,
883                                                 &vps[0].s, vps[1].n, &vps[2].s, vps[3].n, vps[4].n);
884                                 return sr_kemi_ruby_return_int(ket, ret);
885                         } else if(ket->ptypes[0]==SR_KEMIP_STR
886                                         && ket->ptypes[1]==SR_KEMIP_INT
887                                         && ket->ptypes[2]==SR_KEMIP_INT
888                                         && ket->ptypes[3]==SR_KEMIP_STR
889                                         && ket->ptypes[4]==SR_KEMIP_STR) {
890                                 ret = ((sr_kemi_fmsnnss_f)(ket->func))(env_R->msg,
891                                                 &vps[0].s, vps[1].n, vps[2].n, &vps[3].s, &vps[4].s);
892                                 return sr_kemi_ruby_return_int(ket, ret);
893                         } else if(ket->ptypes[0]==SR_KEMIP_STR
894                                         && ket->ptypes[1]==SR_KEMIP_INT
895                                         && ket->ptypes[2]==SR_KEMIP_INT
896                                         && ket->ptypes[3]==SR_KEMIP_STR
897                                         && ket->ptypes[4]==SR_KEMIP_INT) {
898                                 ret = ((sr_kemi_fmsnnsn_f)(ket->func))(env_R->msg,
899                                                 &vps[0].s, vps[1].n, vps[2].n, &vps[3].s, vps[4].n);
900                                 return sr_kemi_ruby_return_int(ket, ret);
901                         } else if(ket->ptypes[0]==SR_KEMIP_STR
902                                         && ket->ptypes[1]==SR_KEMIP_INT
903                                         && ket->ptypes[2]==SR_KEMIP_INT
904                                         && ket->ptypes[3]==SR_KEMIP_INT
905                                         && ket->ptypes[4]==SR_KEMIP_STR) {
906                                 ret = ((sr_kemi_fmsnnns_f)(ket->func))(env_R->msg,
907                                                 &vps[0].s, vps[1].n, vps[2].n, vps[3].n, &vps[4].s);
908                                 return sr_kemi_ruby_return_int(ket, ret);
909                         } else if(ket->ptypes[0]==SR_KEMIP_STR
910                                         && ket->ptypes[1]==SR_KEMIP_INT
911                                         && ket->ptypes[2]==SR_KEMIP_INT
912                                         && ket->ptypes[3]==SR_KEMIP_INT
913                                         && ket->ptypes[4]==SR_KEMIP_INT) {
914                                 ret = ((sr_kemi_fmsnnnn_f)(ket->func))(env_R->msg,
915                                                 &vps[0].s, vps[1].n, vps[2].n, vps[3].n, vps[4].n);
916                                 return sr_kemi_ruby_return_int(ket, ret);
917                         } else if(ket->ptypes[0]==SR_KEMIP_INT
918                                         && ket->ptypes[1]==SR_KEMIP_STR
919                                         && ket->ptypes[2]==SR_KEMIP_STR
920                                         && ket->ptypes[3]==SR_KEMIP_STR
921                                         && ket->ptypes[4]==SR_KEMIP_STR) {
922                                 ret = ((sr_kemi_fmnssss_f)(ket->func))(env_R->msg,
923                                                 vps[0].n, &vps[1].s, &vps[2].s, &vps[3].s, &vps[4].s);
924                                 return sr_kemi_ruby_return_int(ket, ret);
925                         } else if(ket->ptypes[0]==SR_KEMIP_INT
926                                         && ket->ptypes[1]==SR_KEMIP_STR
927                                         && ket->ptypes[2]==SR_KEMIP_STR
928                                         && ket->ptypes[3]==SR_KEMIP_STR
929                                         && ket->ptypes[4]==SR_KEMIP_INT) {
930                                 ret = ((sr_kemi_fmnsssn_f)(ket->func))(env_R->msg,
931                                                 vps[0].n, &vps[1].s, &vps[2].s, &vps[3].s, vps[4].n);
932                                 return sr_kemi_ruby_return_int(ket, ret);
933                         } else if(ket->ptypes[0]==SR_KEMIP_INT
934                                         && ket->ptypes[1]==SR_KEMIP_STR
935                                         && ket->ptypes[2]==SR_KEMIP_STR
936                                         && ket->ptypes[3]==SR_KEMIP_INT
937                                         && ket->ptypes[4]==SR_KEMIP_STR) {
938                                 ret = ((sr_kemi_fmnssns_f)(ket->func))(env_R->msg,
939                                                 vps[0].n, &vps[1].s, &vps[2].s, vps[3].n, &vps[4].s);
940                                 return sr_kemi_ruby_return_int(ket, ret);
941                         } else if(ket->ptypes[0]==SR_KEMIP_INT
942                                         && ket->ptypes[1]==SR_KEMIP_STR
943                                         && ket->ptypes[2]==SR_KEMIP_STR
944                                         && ket->ptypes[3]==SR_KEMIP_INT
945                                         && ket->ptypes[4]==SR_KEMIP_INT) {
946                                 ret = ((sr_kemi_fmnssnn_f)(ket->func))(env_R->msg,
947                                                 vps[0].n, &vps[1].s, &vps[2].s, vps[3].n, vps[4].n);
948                                 return sr_kemi_ruby_return_int(ket, ret);
949                         } else if(ket->ptypes[0]==SR_KEMIP_INT
950                                         && ket->ptypes[1]==SR_KEMIP_STR
951                                         && ket->ptypes[2]==SR_KEMIP_INT
952                                         && ket->ptypes[3]==SR_KEMIP_STR
953                                         && ket->ptypes[4]==SR_KEMIP_STR) {
954                                 ret = ((sr_kemi_fmnsnss_f)(ket->func))(env_R->msg,
955                                                 vps[0].n, &vps[1].s, vps[2].n, &vps[3].s, &vps[4].s);
956                                 return sr_kemi_ruby_return_int(ket, ret);
957                         } else if(ket->ptypes[0]==SR_KEMIP_INT
958                                         && ket->ptypes[1]==SR_KEMIP_STR
959                                         && ket->ptypes[2]==SR_KEMIP_INT
960                                         && ket->ptypes[3]==SR_KEMIP_STR
961                                         && ket->ptypes[4]==SR_KEMIP_INT) {
962                                 ret = ((sr_kemi_fmnsnsn_f)(ket->func))(env_R->msg,
963                                                 vps[0].n, &vps[1].s, vps[2].n, &vps[3].s, vps[4].n);
964                                 return sr_kemi_ruby_return_int(ket, ret);
965                         } else if(ket->ptypes[0]==SR_KEMIP_INT
966                                         && ket->ptypes[1]==SR_KEMIP_STR
967                                         && ket->ptypes[2]==SR_KEMIP_INT
968                                         && ket->ptypes[3]==SR_KEMIP_INT
969                                         && ket->ptypes[4]==SR_KEMIP_STR) {
970                                 ret = ((sr_kemi_fmnsnns_f)(ket->func))(env_R->msg,
971                                                 vps[0].n, &vps[1].s, vps[2].n, vps[3].n, &vps[4].s);
972                                 return sr_kemi_ruby_return_int(ket, ret);
973                         } else if(ket->ptypes[0]==SR_KEMIP_INT
974                                         && ket->ptypes[1]==SR_KEMIP_STR
975                                         && ket->ptypes[2]==SR_KEMIP_INT
976                                         && ket->ptypes[3]==SR_KEMIP_INT
977                                         && ket->ptypes[4]==SR_KEMIP_INT) {
978                                 ret = ((sr_kemi_fmnsnnn_f)(ket->func))(env_R->msg,
979                                                 vps[0].n, &vps[1].s, vps[2].n, vps[3].n, vps[4].n);
980                                 return sr_kemi_ruby_return_int(ket, ret);
981                         } else if(ket->ptypes[0]==SR_KEMIP_INT
982                                         && ket->ptypes[1]==SR_KEMIP_INT
983                                         && ket->ptypes[2]==SR_KEMIP_STR
984                                         && ket->ptypes[3]==SR_KEMIP_STR
985                                         && ket->ptypes[4]==SR_KEMIP_STR) {
986                                 ret = ((sr_kemi_fmnnsss_f)(ket->func))(env_R->msg,
987                                                 vps[0].n, vps[1].n, &vps[2].s, &vps[3].s, &vps[4].s);
988                                 return sr_kemi_ruby_return_int(ket, ret);
989                         } else if(ket->ptypes[0]==SR_KEMIP_INT
990                                         && ket->ptypes[1]==SR_KEMIP_INT
991                                         && ket->ptypes[2]==SR_KEMIP_STR
992                                         && ket->ptypes[3]==SR_KEMIP_STR
993                                         && ket->ptypes[4]==SR_KEMIP_INT) {
994                                 ret = ((sr_kemi_fmnnssn_f)(ket->func))(env_R->msg,
995                                                 vps[0].n, vps[1].n, &vps[2].s, &vps[3].s, vps[4].n);
996                                 return sr_kemi_ruby_return_int(ket, ret);
997                         } else if(ket->ptypes[0]==SR_KEMIP_INT
998                                         && ket->ptypes[1]==SR_KEMIP_INT
999                                         && ket->ptypes[2]==SR_KEMIP_STR
1000                                         && ket->ptypes[3]==SR_KEMIP_INT
1001                                         && ket->ptypes[4]==SR_KEMIP_STR) {
1002                                 ret = ((sr_kemi_fmnnsns_f)(ket->func))(env_R->msg,
1003                                                 vps[0].n, vps[1].n, &vps[2].s, vps[3].n, &vps[4].s);
1004                                 return sr_kemi_ruby_return_int(ket, ret);
1005                         } else if(ket->ptypes[0]==SR_KEMIP_INT
1006                                         && ket->ptypes[1]==SR_KEMIP_INT
1007                                         && ket->ptypes[2]==SR_KEMIP_STR
1008                                         && ket->ptypes[3]==SR_KEMIP_INT
1009                                         && ket->ptypes[4]==SR_KEMIP_INT) {
1010                                 ret = ((sr_kemi_fmnnsnn_f)(ket->func))(env_R->msg,
1011                                                 vps[0].n, vps[1].n, &vps[2].s, vps[3].n, vps[4].n);
1012                                 return sr_kemi_ruby_return_int(ket, ret);
1013                         } else if(ket->ptypes[0]==SR_KEMIP_INT
1014                                         && ket->ptypes[1]==SR_KEMIP_INT
1015                                         && ket->ptypes[2]==SR_KEMIP_INT
1016                                         && ket->ptypes[3]==SR_KEMIP_STR
1017                                         && ket->ptypes[4]==SR_KEMIP_STR) {
1018                                 ret = ((sr_kemi_fmnnnss_f)(ket->func))(env_R->msg,
1019                                                 vps[0].n, vps[1].n, vps[2].n, &vps[3].s, &vps[4].s);
1020                                 return sr_kemi_ruby_return_int(ket, ret);
1021                         } else if(ket->ptypes[0]==SR_KEMIP_INT
1022                                         && ket->ptypes[1]==SR_KEMIP_INT
1023                                         && ket->ptypes[2]==SR_KEMIP_INT
1024                                         && ket->ptypes[3]==SR_KEMIP_STR
1025                                         && ket->ptypes[4]==SR_KEMIP_INT) {
1026                                 ret = ((sr_kemi_fmnnnsn_f)(ket->func))(env_R->msg,
1027                                                 vps[0].n, vps[1].n, vps[2].n, &vps[3].s, vps[4].n);
1028                                 return sr_kemi_ruby_return_int(ket, ret);
1029                         } else if(ket->ptypes[0]==SR_KEMIP_INT
1030                                         && ket->ptypes[1]==SR_KEMIP_INT
1031                                         && ket->ptypes[2]==SR_KEMIP_INT
1032                                         && ket->ptypes[3]==SR_KEMIP_INT
1033                                         && ket->ptypes[4]==SR_KEMIP_STR) {
1034                                 ret = ((sr_kemi_fmnnnns_f)(ket->func))(env_R->msg,
1035                                                 vps[0].n, vps[1].n, vps[2].n, vps[3].n, &vps[4].s);
1036                                 return sr_kemi_ruby_return_int(ket, ret);
1037                         } else if(ket->ptypes[0]==SR_KEMIP_INT
1038                                         && ket->ptypes[1]==SR_KEMIP_INT
1039                                         && ket->ptypes[2]==SR_KEMIP_INT
1040                                         && ket->ptypes[3]==SR_KEMIP_INT
1041                                         && ket->ptypes[4]==SR_KEMIP_INT) {
1042                                 ret = ((sr_kemi_fmnnnnn_f)(ket->func))(env_R->msg,
1043                                                 vps[0].n, vps[1].n, vps[2].n, vps[3].n, vps[4].n);
1044                                 return sr_kemi_ruby_return_int(ket, ret);
1045                         } else {
1046                                 LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s);
1047                                 return Qfalse;
1048                         }
1049                 break;
1050                 case 6:
1051                         if(ket->ptypes[0]==SR_KEMIP_STR
1052                                         && ket->ptypes[1]==SR_KEMIP_STR
1053                                         && ket->ptypes[2]==SR_KEMIP_STR
1054                                         && ket->ptypes[3]==SR_KEMIP_STR
1055                                         && ket->ptypes[4]==SR_KEMIP_STR
1056                                         && ket->ptypes[5]==SR_KEMIP_STR) {
1057                                 ret = ((sr_kemi_fmssssss_f)(ket->func))(env_R->msg,
1058                                                 &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s,
1059                                                 &vps[4].s, &vps[5].s);
1060                                 return sr_kemi_ruby_return_int(ket, ret);
1061                         } else {
1062                                 LM_ERR("invalid parameters for: %.*s\n",
1063                                                 fname->len, fname->s);
1064                                 return Qfalse;
1065                         }
1066                 break;
1067                 default:
1068                         LM_ERR("invalid parameters for: %.*s\n",
1069                                         fname->len, fname->s);
1070                         return Qfalse;
1071         }
1072 }
1073
1074 /**
1075  *
1076  */
1077 VALUE sr_kemi_ruby_exec_func(ksr_ruby_context_t *R, int eidx, int argc,
1078                 VALUE* argv, VALUE self)
1079 {
1080         sr_kemi_t *ket;
1081         int ret;
1082         struct timeval tvb, tve;
1083         struct timezone tz;
1084         unsigned int tdiff;
1085
1086         ket = sr_kemi_ruby_export_get(eidx);
1087
1088         LM_DBG("executing %p eidx %d\n", ket, eidx);
1089
1090         if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)
1091                         && is_printable(cfg_get(core, core_cfg, latency_log))) {
1092                 gettimeofday(&tvb, &tz);
1093         }
1094
1095         ret = sr_kemi_ruby_exec_func_ex(R, ket, argc, argv, self);
1096
1097         if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)
1098                         && is_printable(cfg_get(core, core_cfg, latency_log))) {
1099                 gettimeofday(&tve, &tz);
1100                 tdiff = (tve.tv_sec - tvb.tv_sec) * 1000000
1101                                    + (tve.tv_usec - tvb.tv_usec);
1102                 if(tdiff >= cfg_get(core, core_cfg, latency_limit_action)) {
1103                         LOG(cfg_get(core, core_cfg, latency_log),
1104                                                 "alert - action KSR.%s%s%s(...)"
1105                                                 " took too long [%u us]\n",
1106                                                 (ket->mname.len>0)?ket->mname.s:"",
1107                                                 (ket->mname.len>0)?".":"", ket->fname.s,
1108                                                 tdiff);
1109                 }
1110         }
1111
1112         return ret;
1113 }
1114
1115 /**
1116  *
1117  */
1118 int app_ruby_run_ex(sip_msg_t *msg, char *func, char *p1, char *p2,
1119                 char *p3, int emode)
1120 {
1121         sip_msg_t *bmsg;
1122         ksr_ruby_data_t rbdata;
1123     int rberr = 0;
1124     VALUE rbres;
1125
1126         if(_sr_R_env.rinit==0) {
1127                 LM_ERR("js loading state not initialized (call: %s)\n", func);
1128                 return -1;
1129         }
1130         /* check the script version loaded */
1131         app_ruby_kemi_reload_script();
1132
1133         memset(&rbdata, 0, sizeof(ksr_ruby_data_t));
1134         rbdata.robj = rb_mKernel;
1135         rbdata.metid = rb_intern(func);
1136
1137         LM_DBG("executing ruby function: [[%s]]\n", func);
1138         bmsg = _sr_R_env.msg;
1139         _sr_R_env.msg = msg;
1140         if(p1!=NULL) {
1141                 rbdata.vargs[rbdata.nargs] = rb_str_new_cstr(p1);
1142                 rbdata.nargs++;
1143                 if(p2!=NULL) {
1144                         rbdata.vargs[rbdata.nargs] = rb_str_new_cstr(p2);
1145                         rbdata.nargs++;
1146                         if(p3!=NULL) {
1147                                 rbdata.vargs[rbdata.nargs] = rb_str_new_cstr(p3);
1148                                 rbdata.nargs++;
1149                         }
1150                 }
1151         }
1152
1153         rbres = rb_protect(ksr_ruby_exec_callback, (VALUE)&rbdata, &rberr);
1154
1155         _sr_R_env.msg = bmsg;
1156
1157         if (rberr) {
1158                 if(app_ruby_print_last_exception()==0) {
1159                         LM_ERR("ruby exception (%d) on callback for: %s (res type: %d)\n",
1160                                         rberr, func, TYPE(rbres));
1161                         return -1;
1162                 }
1163         }
1164
1165         return 1;
1166 }
1167
1168 /**
1169  *
1170  */
1171 int app_ruby_run(sip_msg_t *msg, char *func, char *p1, char *p2,
1172                 char *p3)
1173 {
1174         return app_ruby_run_ex(msg, func, p1, p2, p3, 0);
1175 }
1176
1177 /**
1178  * 
1179  */
1180 int app_ruby_runstring(sip_msg_t *msg, char *script)
1181 {
1182         LM_ERR("not implemented\n");
1183         return -1;
1184 }
1185
1186 /**
1187  * 
1188  */
1189 int app_ruby_dostring(sip_msg_t *msg, char *script)
1190 {
1191         LM_ERR("not implemented\n");
1192         return -1;
1193 }
1194
1195 /**
1196  * 
1197  */
1198 int app_ruby_dofile(sip_msg_t *msg, char *script)
1199 {
1200         LM_ERR("not implemented\n");
1201         return -1;
1202 }
1203
1204 ksr_ruby_export_t *_sr_R_KSRMethods = NULL;
1205 #define SR_RUBY_KSR_MODULES_SIZE        256
1206 #define SR_RUBY_KSR_METHODS_SIZE        (SR_KEMI_RUBY_EXPORT_SIZE + SR_RUBY_KSR_MODULES_SIZE)
1207
1208 static VALUE _ksr_mKSR;
1209 static VALUE _ksr_mSMD[SR_RUBY_KSR_MODULES_SIZE];
1210
1211 /**
1212  * 
1213  */
1214 void ksr_app_ruby_toupper(char *bin, char *bout)
1215 {
1216         int i;
1217         for(i=0; bin[i]!='\0'; i++) {
1218                 bout[i] = (char)toupper(bin[i]);
1219         }
1220         bout[i] = '\0';
1221 }
1222 /**
1223  * 
1224  */
1225 int app_ruby_kemi_export_libs(void)
1226 {
1227         ksr_ruby_export_t *_sr_crt_R_KSRMethods = NULL;
1228         sr_kemi_module_t *emods = NULL;
1229         int emods_size = 0;
1230         int i;
1231         int k;
1232         int n;
1233         int m;
1234         char rmname[128];
1235
1236         _sr_R_KSRMethods = malloc(SR_RUBY_KSR_METHODS_SIZE * sizeof(ksr_ruby_export_t));
1237         if(_sr_R_KSRMethods==NULL) {
1238                 LM_ERR("no more pkg memory\n");
1239                 return 0;
1240         }
1241         memset(_sr_R_KSRMethods, 0, SR_RUBY_KSR_METHODS_SIZE * sizeof(ksr_ruby_export_t));
1242
1243         emods_size = sr_kemi_modules_size_get();
1244         emods = sr_kemi_modules_get();
1245
1246         n = 0;
1247         _sr_crt_R_KSRMethods = _sr_R_KSRMethods;
1248         if(emods_size==0 || emods[0].kexp==NULL) {
1249                 LM_ERR("no kemi exports registered\n");
1250                 return 0;
1251         }
1252
1253         /* toplevel module KSR */
1254         _ksr_mKSR = rb_define_module("KSR");
1255
1256         for(i=0; emods[0].kexp[i].func!=NULL; i++) {
1257                 LM_DBG("exporting KSR.%s(...)\n", emods[0].kexp[i].fname.s);
1258                 _sr_crt_R_KSRMethods[i].mname = "";
1259                 _sr_crt_R_KSRMethods[i].fname = emods[0].kexp[i].fname.s;
1260                 _sr_crt_R_KSRMethods[i].func =
1261                         sr_kemi_ruby_export_associate(&emods[0].kexp[i]);
1262                 if(_sr_crt_R_KSRMethods[i].func == NULL) {
1263                         LM_ERR("failed to associate kemi function with ruby export\n");
1264                         free(_sr_R_KSRMethods);
1265                         _sr_R_KSRMethods = NULL;
1266                         return 0;
1267                 }
1268
1269                 rb_define_singleton_method(_ksr_mKSR, _sr_crt_R_KSRMethods[i].fname,
1270                                                 _sr_crt_R_KSRMethods[i].func, -1);
1271
1272                 n++;
1273         }
1274
1275         m = 0;
1276
1277         /* x submodule */
1278         _ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, "X");
1279         for(i=0; _sr_kemi_x_R_Map[i].fname!=0; i++) {
1280                 LM_DBG("exporting KSR.X.%s(...)\n", _sr_kemi_x_R_Map[i].fname);
1281                 rb_define_singleton_method(_ksr_mSMD[m], _sr_kemi_x_R_Map[i].fname,
1282                                 _sr_kemi_x_R_Map[i].func, -1);
1283         }
1284         LM_DBG("initialized kemi sub-module: KSR.X\n");
1285         m++;
1286
1287         /* registered kemi modules */
1288         if(emods_size>1) {
1289                 for(k=1; k<emods_size; k++) {
1290                         n++;
1291                         _sr_crt_R_KSRMethods = _sr_R_KSRMethods + n;
1292                         ksr_app_ruby_toupper(emods[k].kexp[0].mname.s, rmname);
1293                         _ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, rmname);
1294                         for(i=0; emods[k].kexp[i].func!=NULL; i++) {
1295                                 _sr_crt_R_KSRMethods[i].mname = emods[k].kexp[0].mname.s;
1296                                 _sr_crt_R_KSRMethods[i].fname = emods[k].kexp[i].fname.s;
1297                                 _sr_crt_R_KSRMethods[i].func =
1298                                         sr_kemi_ruby_export_associate(&emods[k].kexp[i]);
1299                                 LM_DBG("exporting KSR.%s.%s(...)\n", rmname,
1300                                                 emods[k].kexp[i].fname.s);
1301                                 if(_sr_crt_R_KSRMethods[i].func == NULL) {
1302                                         LM_ERR("failed to associate kemi function with func export\n");
1303                                         free(_sr_R_KSRMethods);
1304                                         _sr_R_KSRMethods = NULL;
1305                                         return 0;
1306                                 }
1307
1308                                 rb_define_singleton_method(_ksr_mSMD[m], _sr_crt_R_KSRMethods[i].fname,
1309                                                 _sr_crt_R_KSRMethods[i].func, -1);
1310
1311                                 n++;
1312                         }
1313                         m++;
1314                         LM_DBG("initialized kemi sub-module: KSR.%s\n", rmname);
1315                 }
1316         }
1317         LM_DBG("module 'KSR' has been initialized\n");
1318
1319         return 1;
1320 }
1321
1322 static const char* app_ruby_rpc_reload_doc[2] = {
1323         "Reload javascript file",
1324         0
1325 };
1326
1327
1328 static void app_ruby_rpc_reload(rpc_t* rpc, void* ctx)
1329 {
1330         int v;
1331         void *vh;
1332
1333         if(_sr_ruby_load_file.s == NULL && _sr_ruby_load_file.len<=0) {
1334                 LM_WARN("script file path not provided\n");
1335                 rpc->fault(ctx, 500, "No script file");
1336                 return;
1337         }
1338         if(_sr_ruby_reload_version == NULL) {
1339                 LM_WARN("reload not enabled\n");
1340                 rpc->fault(ctx, 500, "Reload not enabled");
1341                 return;
1342         }
1343
1344         v = *_sr_ruby_reload_version;
1345         *_sr_ruby_reload_version += 1;
1346         LM_INFO("marking for reload ruby script file: %.*s (%d / %d => %d)\n",
1347                                 _sr_ruby_load_file.len, _sr_ruby_load_file.s,
1348                                 _sr_ruby_local_version, v, *_sr_ruby_reload_version);
1349
1350         if (rpc->add(ctx, "{", &vh) < 0) {
1351                 rpc->fault(ctx, 500, "Server error");
1352                 return;
1353         }
1354         rpc->struct_add(vh, "dd",
1355                         "old", v,
1356                         "new", *_sr_ruby_reload_version);
1357 }
1358
1359 static const char* app_ruby_rpc_api_list_doc[2] = {
1360         "List kemi exports to ruby",
1361         0
1362 };
1363
1364 static void app_ruby_rpc_api_list(rpc_t* rpc, void* ctx)
1365 {
1366         int i;
1367         int n;
1368         sr_kemi_t *ket;
1369         void* th;
1370         void* sh;
1371         void* ih;
1372
1373         if (rpc->add(ctx, "{", &th) < 0) {
1374                 rpc->fault(ctx, 500, "Internal error root reply");
1375                 return;
1376         }
1377         n = 0;
1378         for(i=0; i<SR_KEMI_RUBY_EXPORT_SIZE; i++) {
1379                 ket = sr_kemi_ruby_export_get(i);
1380                 if(ket==NULL) continue;
1381                 n++;
1382         }
1383
1384         if(rpc->struct_add(th, "d[",
1385                                 "msize", n,
1386                                 "methods",  &ih)<0)
1387         {
1388                 rpc->fault(ctx, 500, "Internal error array structure");
1389                 return;
1390         }
1391         for(i=0; i<SR_KEMI_RUBY_EXPORT_SIZE; i++) {
1392                 ket = sr_kemi_ruby_export_get(i);
1393                 if(ket==NULL) continue;
1394                 if(rpc->struct_add(ih, "{", "func", &sh)<0) {
1395                         rpc->fault(ctx, 500, "Internal error internal structure");
1396                         return;
1397                 }
1398                 if(rpc->struct_add(sh, "SSSS",
1399                                 "ret", sr_kemi_param_map_get_name(ket->rtype),
1400                                 "module", &ket->mname,
1401                                 "name", &ket->fname,
1402                                 "params", sr_kemi_param_map_get_params(ket->ptypes))<0) {
1403                         LM_ERR("failed to add the structure with attributes (%d)\n", i);
1404                         rpc->fault(ctx, 500, "Internal error creating dest struct");
1405                         return;
1406                 }
1407         }
1408 }
1409
1410 /**
1411  *
1412  */
1413 rpc_export_t app_ruby_rpc_cmds[] = {
1414         {"app_ruby.reload", app_ruby_rpc_reload,
1415                 app_ruby_rpc_reload_doc, 0},
1416         {"app_ruby.api_list", app_ruby_rpc_api_list,
1417                 app_ruby_rpc_api_list_doc, 0},
1418         {0, 0, 0, 0}
1419 };
1420
1421 /**
1422  *
1423  */
1424 int app_ruby_init_rpc(void)
1425 {
1426         if (rpc_register_array(app_ruby_rpc_cmds)!=0) {
1427                 LM_ERR("failed to register RPC commands\n");
1428                 return -1;
1429         }
1430         return 0;
1431 }