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 extern int _ksr_app_ruby_xval_mode;
45 
46 int app_ruby_kemi_export_libs(void);
47 
48 typedef struct _sr_ruby_env
49 {
50 	ksr_ruby_context_t *R;
51 	sip_msg_t *msg;
52 	int rinit;
53 	unsigned int flags;
54 	unsigned int nload; /* number of scripts loaded */
55 } sr_ruby_env_t;
56 
57 typedef struct ksr_ruby_data {
58 	VALUE robj;
59 	ID metid;
60 	int nargs;
61 	VALUE vargs[4];
62 } ksr_ruby_data_t;
63 
64 static sr_ruby_env_t _sr_R_env = {0};
65 
66 str _sr_ruby_load_file = STR_NULL;
67 
68 static int *_sr_ruby_reload_version = NULL;
69 static int _sr_ruby_local_version = 0;
70 
71 /**
72  *
73  */
app_ruby_sr_env_get(void)74 sr_ruby_env_t *app_ruby_sr_env_get(void)
75 {
76 	return &_sr_R_env;
77 }
78 
79 /**
80  *
81  */
ruby_sr_init_mod(void)82 int ruby_sr_init_mod(void)
83 {
84 	if(_sr_ruby_load_file.s == NULL || _sr_ruby_load_file.len<=0) {
85 		LM_ERR("no ruby script file to load was provided\n");
86 		return -1;
87 	}
88 	if(_sr_ruby_reload_version == NULL) {
89 		_sr_ruby_reload_version = (int*)shm_malloc(sizeof(int));
90 		if(_sr_ruby_reload_version == NULL) {
91 			LM_ERR("failed to allocated reload version\n");
92 			return -1;
93 		}
94 		*_sr_ruby_reload_version = 0;
95 	}
96 	memset(&_sr_R_env, 0, sizeof(sr_ruby_env_t));
97 	return 0;
98 }
99 
app_ruby_print_last_exception()100 static int app_ruby_print_last_exception()
101 {
102 	VALUE rException, rExceptStr;
103 
104 	rException = rb_errinfo();         /* get last exception */
105 	rb_set_errinfo(Qnil);              /* clear last exception */
106 	rExceptStr = rb_funcall(rException, rb_intern("to_s"), 0, Qnil);
107 	if(RSTRING_LEN(rExceptStr)!=4
108 			|| strncmp(RSTRING_PTR(rExceptStr), "exit", 4)!=0) {
109 		LM_ERR("exception: %.*s\n", (int)RSTRING_LEN(rExceptStr),
110 				RSTRING_PTR(rExceptStr));
111 		return 0;
112 	}
113 	return 1;
114 }
115 
116 /**
117  *
118  */
app_ruby_kemi_load_script(void)119 int app_ruby_kemi_load_script(void)
120 {
121 	int state = 0;
122 	VALUE script;
123 
124 	script  = rb_str_new_cstr(_sr_ruby_load_file.s);
125 
126 	/* handle exceptions like rb_eval_string_protect() */
127 	rb_load_protect(script, 0, &state);
128 
129 	if (state) {
130 		/* got exception */
131 		app_ruby_print_last_exception();
132 		LM_ERR("failed to load rb script file: %.*s (%d)\n",
133 				_sr_ruby_load_file.len, _sr_ruby_load_file.s, state);
134 		// return -1;
135 	}
136 	LM_DBG("rb script loaded: %s\n", _sr_ruby_load_file.s);
137 
138 	return 0;
139 }
140 
141 /**
142  *
143  */
app_ruby_kemi_reload_script(void)144 int app_ruby_kemi_reload_script(void)
145 {
146 	int v;
147 	if(_sr_ruby_load_file.s == NULL && _sr_ruby_load_file.len<=0) {
148 		LM_WARN("script file path not provided\n");
149 		return -1;
150 	}
151 	if(_sr_ruby_reload_version == NULL) {
152 		LM_WARN("reload not enabled\n");
153 		return -1;
154 	}
155 	if(_sr_R_env.rinit == 0) {
156 		LM_ERR("load ruby context not created\n");
157 		return -1;
158 	}
159 
160 	v = *_sr_ruby_reload_version;
161 	if(v == _sr_ruby_local_version) {
162 		/* same version */
163 		return 0;
164 	}
165 	LM_DBG("reloading ruby script file: %.*s (%d => %d)\n",
166 				_sr_ruby_load_file.len, _sr_ruby_load_file.s,
167 				_sr_ruby_local_version, v);
168 	app_ruby_kemi_load_script();
169 	_sr_ruby_local_version = v;
170 	return 0;
171 }
172 
173 /**
174  *
175  */
ruby_sr_init_child(void)176 int ruby_sr_init_child(void)
177 {
178 	int state = 0;
179 	VALUE rbres;
180 
181 	/* construct the VM */
182 	ruby_init();
183 	ruby_init_loadpath();
184 	ruby_script(_sr_ruby_load_file.s);
185 
186 	/* Ruby goes here */
187 	rbres = rb_eval_string_protect("puts 'Hello " NAME "!'", &state);
188 
189 	if (state) {
190 		/* handle exception */
191 		app_ruby_print_last_exception();
192 		LM_ERR("test execution with error (res type: %d)\n", TYPE(rbres));
193 		return -1;
194 	} else {
195 		LM_DBG("test execution without error\n");
196 	}
197 
198 	if(app_ruby_kemi_export_libs()<0) {
199 		return -1;
200 	}
201 
202 	if(app_ruby_kemi_load_script()<0) {
203 		return -1;
204 	}
205 
206 	_sr_R_env.rinit = 1;
207 
208 	return 0;
209 }
210 
211 /**
212  *
213  */
ruby_sr_destroy(void)214 void ruby_sr_destroy(void)
215 {
216 	if(_sr_R_env.rinit == 1) {
217 		return;
218 	}
219 	memset(&_sr_R_env, 0, sizeof(sr_ruby_env_t));
220 	/* destruct the VM */
221 	ruby_cleanup(0);
222 	return;
223 }
224 
225 /**
226  *
227  */
ruby_sr_initialized(void)228 int ruby_sr_initialized(void)
229 {
230 	if(_sr_R_env.rinit==1) {
231 		return 1;
232 	}
233 	return 0;
234 }
235 
236 /**
237  *
238  */
sr_kemi_ruby_return_int(sr_kemi_t * ket,int rc)239 int sr_kemi_ruby_return_int(sr_kemi_t *ket, int rc)
240 {
241 	if(ket->rtype==SR_KEMIP_INT || ket->rtype==SR_KEMIP_XVAL) {
242 		return INT2NUM(rc);
243 	}
244 	if(ket->rtype==SR_KEMIP_BOOL && rc!=SR_KEMI_FALSE) {
245 		return Qtrue;
246 	}
247 	return Qfalse;
248 }
249 
250 /**
251  *
252  */
sr_kemi_ruby_return_none(int rmode)253 static VALUE sr_kemi_ruby_return_none(int rmode)
254 {
255 	if(rmode==1) {
256 		return rb_str_new_cstr("<<null>>");
257 	} else if(rmode==2) {
258 		return rb_str_new_cstr("");
259 	}
260 	return Qnil;
261 }
262 
263 /**
264  *
265  */
app_ruby_pv_get_mode(int argc,VALUE * argv,VALUE self,int rmode)266 static VALUE app_ruby_pv_get_mode(int argc, VALUE* argv, VALUE self, int rmode)
267 {
268 	str pvn;
269 	pv_spec_t *pvs;
270 	pv_value_t val;
271 	sr_ruby_env_t *env_R;
272 	int pl;
273 
274 	env_R = app_ruby_sr_env_get();
275 
276 	if(env_R==NULL || env_R->msg==NULL || argc!=1) {
277 		LM_ERR("invalid ruby environment attributes or parameters\n");
278 		return sr_kemi_ruby_return_none(rmode);
279 	}
280 
281 	if(!RB_TYPE_P(argv[0], T_STRING)) {
282 		LM_ERR("invalid parameter type\n");
283 		return sr_kemi_ruby_return_none(rmode);
284 	}
285 
286 	pvn.s = StringValuePtr(argv[0]);
287 	if(pvn.s==NULL)
288 		return sr_kemi_ruby_return_none(rmode);
289 	pvn.len = strlen(pvn.s);
290 
291 	LM_DBG("pv get: %s\n", pvn.s);
292 	pl = pv_locate_name(&pvn);
293 	if(pl != pvn.len) {
294 		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
295 		return sr_kemi_ruby_return_none(rmode);
296 	}
297 	pvs = pv_cache_get(&pvn);
298 	if(pvs==NULL) {
299 		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
300 		return sr_kemi_ruby_return_none(rmode);
301 	}
302 	memset(&val, 0, sizeof(pv_value_t));
303 	if(pv_get_spec_value(env_R->msg, pvs, &val) != 0) {
304 		LM_ERR("unable to get pv value for [%s]\n", pvn.s);
305 		return sr_kemi_ruby_return_none(rmode);
306 	}
307 	if(val.flags&PV_VAL_NULL) {
308 		return sr_kemi_ruby_return_none(rmode);
309 	}
310 	if(val.flags&PV_TYPE_INT) {
311 		return INT2NUM(val.ri);
312 	}
313 	return rb_str_new(val.rs.s, val.rs.len);
314 }
315 
316 /**
317  *
318  */
app_ruby_pv_get(int argc,VALUE * argv,VALUE self)319 static VALUE app_ruby_pv_get(int argc, VALUE* argv, VALUE self)
320 {
321 	return app_ruby_pv_get_mode(argc, argv, self, 0);
322 }
323 
324 /**
325  *
326  */
app_ruby_pv_getw(int argc,VALUE * argv,VALUE self)327 static VALUE app_ruby_pv_getw(int argc, VALUE* argv, VALUE self)
328 {
329 	return app_ruby_pv_get_mode(argc, argv, self, 1);
330 }
331 
332 /**
333  *
334  */
app_ruby_pv_gete(int argc,VALUE * argv,VALUE self)335 static VALUE app_ruby_pv_gete(int argc, VALUE* argv, VALUE self)
336 {
337 	return app_ruby_pv_get_mode(argc, argv, self, 2);
338 }
339 
340 /**
341  *
342  */
app_ruby_pv_seti(int argc,VALUE * argv,VALUE self)343 static VALUE app_ruby_pv_seti(int argc, VALUE* argv, VALUE self)
344 {
345 	str pvn;
346 	pv_spec_t *pvs;
347 	pv_value_t val;
348 	sr_ruby_env_t *env_R;
349 	int pl;
350 
351 	env_R = app_ruby_sr_env_get();
352 
353 	if(env_R==NULL || env_R->msg==NULL || argc!=2) {
354 		LM_ERR("invalid ruby environment attributes or parameters\n");
355 		return Qfalse;
356 	}
357 
358 	if(!RB_TYPE_P(argv[0], T_STRING)) {
359 		LM_ERR("invalid pv name parameter type\n");
360 		return Qfalse;
361 	}
362 
363 	if(!RB_TYPE_P(argv[1], T_FIXNUM)) {
364 		LM_ERR("invalid pv val parameter type\n");
365 		return Qfalse;
366 	}
367 
368 	pvn.s = StringValuePtr(argv[0]);
369 	if(pvn.s==NULL)
370 		return Qfalse;
371 	pvn.len = strlen(pvn.s);
372 
373 	LM_DBG("pv get: %s\n", pvn.s);
374 	pl = pv_locate_name(&pvn);
375 	if(pl != pvn.len) {
376 		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
377 		return Qfalse;
378 	}
379 	pvs = pv_cache_get(&pvn);
380 	if(pvs==NULL) {
381 		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
382 		return Qfalse;
383 	}
384 
385 	memset(&val, 0, sizeof(pv_value_t));
386 	val.ri = NUM2INT(argv[1]);
387 	val.flags |= PV_TYPE_INT|PV_VAL_INT;
388 
389 	if(pv_set_spec_value(env_R->msg, pvs, 0, &val)<0) {
390 		LM_ERR("unable to set pv [%s]\n", pvn.s);
391 		return Qfalse;
392 	}
393 
394 	return Qtrue;
395 }
396 
397 /**
398  *
399  */
app_ruby_pv_sets(int argc,VALUE * argv,VALUE self)400 static VALUE app_ruby_pv_sets(int argc, VALUE* argv, VALUE self)
401 {
402 	str pvn;
403 	pv_spec_t *pvs;
404 	pv_value_t val;
405 	sr_ruby_env_t *env_R;
406 	int pl;
407 
408 	env_R = app_ruby_sr_env_get();
409 
410 	if(env_R==NULL || env_R->msg==NULL || argc!=2) {
411 		LM_ERR("invalid ruby environment attributes or parameters\n");
412 		return Qfalse;
413 	}
414 
415 	if(!RB_TYPE_P(argv[0], T_STRING)) {
416 		LM_ERR("invalid pv name parameter type\n");
417 		return Qfalse;
418 	}
419 
420 	if(!RB_TYPE_P(argv[1], T_STRING)) {
421 		LM_ERR("invalid pv val parameter type\n");
422 		return Qfalse;
423 	}
424 
425 	pvn.s = StringValuePtr(argv[0]);
426 	if(pvn.s==NULL)
427 		return Qfalse;
428 	pvn.len = strlen(pvn.s);
429 
430 	LM_DBG("pv get: %s\n", pvn.s);
431 	pl = pv_locate_name(&pvn);
432 	if(pl != pvn.len) {
433 		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
434 		return Qfalse;
435 	}
436 	pvs = pv_cache_get(&pvn);
437 	if(pvs==NULL) {
438 		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
439 		return Qfalse;
440 	}
441 
442 	memset(&val, 0, sizeof(pv_value_t));
443 	val.rs.s = StringValuePtr(argv[1]);
444 	if(val.rs.s==NULL) {
445 		LM_ERR("invalid str value\n");
446 		return Qfalse;
447 	}
448 	val.rs.len = strlen(val.rs.s);
449 	val.flags |= PV_VAL_STR;
450 
451 	if(pv_set_spec_value(env_R->msg, pvs, 0, &val)<0) {
452 		LM_ERR("unable to set pv [%s]\n", pvn.s);
453 		return Qfalse;
454 	}
455 
456 	return Qtrue;
457 }
458 
459 /**
460  *
461  */
app_ruby_pv_unset(int argc,VALUE * argv,VALUE self)462 static VALUE app_ruby_pv_unset(int argc, VALUE* argv, VALUE self)
463 {
464 	str pvn;
465 	pv_spec_t *pvs;
466 	pv_value_t val;
467 	sr_ruby_env_t *env_R;
468 	int pl;
469 
470 	env_R = app_ruby_sr_env_get();
471 
472 	if(env_R==NULL || env_R->msg==NULL || argc!=1) {
473 		LM_ERR("invalid ruby environment attributes or parameters\n");
474 		return Qfalse;
475 	}
476 
477 	if(!RB_TYPE_P(argv[0], T_STRING)) {
478 		LM_ERR("invalid parameter type\n");
479 		return Qfalse;
480 	}
481 
482 	pvn.s = StringValuePtr(argv[0]);
483 	if(pvn.s==NULL)
484 		return Qfalse;
485 	pvn.len = strlen(pvn.s);
486 
487 	LM_DBG("pv get: %s\n", pvn.s);
488 	pl = pv_locate_name(&pvn);
489 	if(pl != pvn.len) {
490 		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
491 		return Qfalse;
492 	}
493 	pvs = pv_cache_get(&pvn);
494 	if(pvs==NULL) {
495 		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
496 		return Qfalse;
497 	}
498 
499 	memset(&val, 0, sizeof(pv_value_t));
500 	val.flags |= PV_VAL_NULL;
501 	if(pv_set_spec_value(env_R->msg, pvs, 0, &val)<0)
502 	{
503 		LM_ERR("unable to unset pv [%s]\n", pvn.s);
504 		return Qfalse;
505 	}
506 
507 	return Qtrue;
508 }
509 
510 /**
511  *
512  */
app_ruby_pv_is_null(int argc,VALUE * argv,VALUE self)513 static VALUE app_ruby_pv_is_null(int argc, VALUE* argv, VALUE self)
514 {
515 	str pvn;
516 	pv_spec_t *pvs;
517 	pv_value_t val;
518 	sr_ruby_env_t *env_R;
519 	int pl;
520 
521 	env_R = app_ruby_sr_env_get();
522 
523 	if(env_R==NULL || env_R->msg==NULL || argc!=1) {
524 		LM_ERR("invalid ruby environment attributes or parameters\n");
525 		return Qfalse;
526 	}
527 
528 	if(!RB_TYPE_P(argv[0], T_STRING)) {
529 		LM_ERR("invalid parameter type\n");
530 		return Qfalse;
531 	}
532 
533 	pvn.s = StringValuePtr(argv[0]);
534 	if(pvn.s==NULL)
535 		return Qfalse;
536 	pvn.len = strlen(pvn.s);
537 
538 	LM_DBG("pv get: %s\n", pvn.s);
539 	pl = pv_locate_name(&pvn);
540 	if(pl != pvn.len) {
541 		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
542 		return Qfalse;
543 	}
544 	pvs = pv_cache_get(&pvn);
545 	if(pvs==NULL) {
546 		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
547 		return Qfalse;
548 	}
549 
550 	memset(&val, 0, sizeof(pv_value_t));
551 	if(pv_get_spec_value(env_R->msg, pvs, &val) != 0) {
552 		LM_NOTICE("unable to get pv value for [%s]\n", pvn.s);
553 		return Qtrue;
554 	}
555 	if(val.flags&PV_VAL_NULL) {
556 		return Qtrue;
557 	} else {
558 		pv_value_destroy(&val);
559 		return Qfalse;
560 	}
561 }
562 
563 /**
564  *
565  */
566 static ksr_ruby_export_t _sr_kemi_pv_R_Map[] = {
567 	{"PV", "get", app_ruby_pv_get},
568 	{"PV", "getw", app_ruby_pv_getw},
569 	{"PV", "gete", app_ruby_pv_gete},
570 	{"PV", "seti", app_ruby_pv_seti},
571 	{"PV", "sets", app_ruby_pv_sets},
572 	{"PV", "unset", app_ruby_pv_unset},
573 	{"PV", "is_null", app_ruby_pv_is_null},
574 	{0, 0, 0}
575 };
576 
577 /**
578  *
579  */
app_ruby_sr_modf(int argc,VALUE * argv,VALUE self)580 static VALUE app_ruby_sr_modf(int argc, VALUE* argv, VALUE self)
581 {
582 	int ret;
583 	char *rbv[MAX_ACTIONS];
584 	char *paramv[MAX_ACTIONS];
585 	int i;
586 	int mod_type;
587 	struct run_act_ctx ra_ctx;
588 	struct action *act;
589 	ksr_cmd_export_t* expf;
590 	sr_ruby_env_t *env_R;
591 
592 	ret = 1;
593 	act = NULL;
594 	memset(rbv, 0, MAX_ACTIONS*sizeof(char*));
595 	memset(paramv, 0, MAX_ACTIONS*sizeof(char*));
596 	env_R = app_ruby_sr_env_get();
597 	if(env_R->msg==NULL)
598 		goto error;
599 
600 	if(argc==0) {
601 		LM_ERR("name of module function not provided\n");
602 		goto error;
603 	}
604 	if(argc>=MAX_ACTIONS) {
605 		LM_ERR("too many parameters\n");
606 		goto error;
607 	}
608 	/* first is function name, then parameters */
609 	for(i=0; i<argc; i++) {
610 		if(!RB_TYPE_P(argv[i], T_STRING)) {
611 			LM_ERR("invalid parameter type (%d)\n", i);
612 			return INT2NUM(-1);
613 		}
614 		rbv[i] = (char*)StringValuePtr(argv[i]);
615 	}
616 	LM_ERR("request to execute cfg function '%s'\n", rbv[0]);
617 	/* pkg copy only parameters */
618 	for(i=1; i<MAX_ACTIONS; i++) {
619 		if(rbv[i]!=NULL) {
620 			paramv[i] = (char*)pkg_malloc(strlen(rbv[i])+1);
621 			if(paramv[i]==NULL) {
622 				LM_ERR("no more pkg\n");
623 				goto error;
624 			}
625 			strcpy(paramv[i], rbv[i]);
626 		}
627 	}
628 
629 	expf = find_export_record(rbv[0], argc-1, 0);
630 	if (expf==NULL) {
631 		LM_ERR("function '%s' is not available\n", rbv[0]);
632 		goto error;
633 	}
634 	/* check fixups */
635 	if (expf->fixup!=NULL && expf->free_fixup==NULL) {
636 		LM_ERR("function '%s' has fixup - cannot be used\n", rbv[0]);
637 		goto error;
638 	}
639 	switch(expf->param_no) {
640 		case 0:
641 			mod_type = MODULE0_T;
642 			break;
643 		case 1:
644 			mod_type = MODULE1_T;
645 			break;
646 		case 2:
647 			mod_type = MODULE2_T;
648 			break;
649 		case 3:
650 			mod_type = MODULE3_T;
651 			break;
652 		case 4:
653 			mod_type = MODULE4_T;
654 			break;
655 		case 5:
656 			mod_type = MODULE5_T;
657 			break;
658 		case 6:
659 			mod_type = MODULE6_T;
660 			break;
661 		case VAR_PARAM_NO:
662 			mod_type = MODULEX_T;
663 			break;
664 		default:
665 			LM_ERR("unknown/bad definition for function '%s' (%d params)\n",
666 					rbv[0], expf->param_no);
667 			goto error;
668 	}
669 
670 	act = mk_action(mod_type,  argc+1   /* number of (type, value) pairs */,
671 					MODEXP_ST, expf,    /* function */
672 					NUMBER_ST, argc-1,  /* parameter number */
673 					STRING_ST, paramv[1], /* param. 1 */
674 					STRING_ST, paramv[2], /* param. 2 */
675 					STRING_ST, paramv[3], /* param. 3 */
676 					STRING_ST, paramv[4], /* param. 4 */
677 					STRING_ST, paramv[5], /* param. 5 */
678 					STRING_ST, paramv[6]  /* param. 6 */
679 			);
680 
681 	if (act==NULL) {
682 		LM_ERR("action structure could not be created for '%s'\n", rbv[0]);
683 		goto error;
684 	}
685 
686 	/* handle fixups */
687 	if (expf->fixup) {
688 		if(argc==1) {
689 			/* no parameters */
690 			if(expf->fixup(0, 0)<0) {
691 				LM_ERR("Error in fixup (0) for '%s'\n", rbv[0]);
692 				goto error;
693 			}
694 		} else {
695 			for(i=1; i<argc; i++) {
696 				if(expf->fixup(&(act->val[i+1].u.data), i)<0) {
697 					LM_ERR("Error in fixup (%d) for '%s'\n", i, rbv[0]);
698 					goto error;
699 				}
700 				act->val[i+1].type = MODFIXUP_ST;
701 			}
702 		}
703 	}
704 	init_run_actions_ctx(&ra_ctx);
705 	ret = do_action(&ra_ctx, act, env_R->msg);
706 
707 	/* free fixups */
708 	if (expf->fixup) {
709 		for(i=1; i<argc; i++) {
710 			if ((act->val[i+1].type == MODFIXUP_ST) && (act->val[i+1].u.data)) {
711 				expf->free_fixup(&(act->val[i+1].u.data), i);
712 			}
713 		}
714 	}
715 	pkg_free(act);
716 	for(i=0; i<MAX_ACTIONS; i++) {
717 		if(paramv[i]!=NULL) pkg_free(paramv[i]);
718 		paramv[i] = 0;
719 	}
720 	return INT2NUM(ret);
721 
722 error:
723 	if(act!=NULL)
724 		pkg_free(act);
725 	for(i=0; i<MAX_ACTIONS; i++) {
726 		if(paramv[i]!=NULL) pkg_free(paramv[i]);
727 		paramv[i] = 0;
728 	}
729 	return INT2NUM(-1);
730 }
731 
732 /**
733  *
734  */
735 static ksr_ruby_export_t _sr_kemi_x_R_Map[] = {
736 	{"X", "modf", app_ruby_sr_modf},
737 	{0, 0, 0}
738 };
739 
740 /**
741  *
742  */
ksr_ruby_exec_callback(VALUE ptr)743 static VALUE ksr_ruby_exec_callback(VALUE ptr)
744 {
745 	ksr_ruby_data_t *data = (ksr_ruby_data_t *)ptr;
746 	return rb_funcall2(data->robj, data->metid, data->nargs, data->vargs);
747 }
748 
749 /**
750  *
751  */
sr_kemi_ruby_return_xval(sr_kemi_t * ket,sr_kemi_xval_t * rx)752 VALUE sr_kemi_ruby_return_xval(sr_kemi_t *ket, sr_kemi_xval_t *rx)
753 {
754 	switch(rx->vtype) {
755 		case SR_KEMIP_NONE:
756 			return Qnil;
757 		case SR_KEMIP_INT:
758 			return INT2NUM(rx->v.n);
759 		case SR_KEMIP_STR:
760 			if(_ksr_app_ruby_xval_mode==0) {
761 				LM_ERR("attempt to return xval str - support disabled - returning null\n");
762 				return Qnil;
763 			} else {
764 				return rb_str_new(rx->v.s.s, rx->v.s.len);
765 			}
766 		case SR_KEMIP_BOOL:
767 			if(rx->v.n!=SR_KEMI_FALSE) {
768 				return Qtrue;
769 			} else {
770 				return Qfalse;
771 			}
772 		case SR_KEMIP_ARRAY:
773 			LM_ERR("unsupported return type: array\n");
774 			sr_kemi_xval_free(rx);
775 			return Qnil;
776 		case SR_KEMIP_DICT:
777 			LM_ERR("unsupported return type: map\n");
778 			sr_kemi_xval_free(rx);
779 			return Qnil;
780 		case SR_KEMIP_XVAL:
781 			/* unknown content - return false */
782 			return Qfalse;
783 		case SR_KEMIP_NULL:
784 			return Qnil;
785 		default:
786 			/* unknown type - return false */
787 			return Qfalse;
788 	}
789 }
790 
791 /**
792  *
793  */
sr_kemi_ruby_exec_func_ex(ksr_ruby_context_t * R,sr_kemi_t * ket,int argc,VALUE * argv,VALUE self)794 VALUE sr_kemi_ruby_exec_func_ex(ksr_ruby_context_t *R, sr_kemi_t *ket, int argc,
795 		VALUE* argv, VALUE self)
796 {
797 	sr_kemi_val_t vps[SR_KEMI_PARAMS_MAX];
798 	sr_ruby_env_t *env_R;
799 	str *fname;
800 	str *mname;
801 	int i;
802 	int ret = -1;
803 	sr_kemi_xval_t *xret;
804 
805 	env_R = app_ruby_sr_env_get();
806 	if(env_R==NULL || env_R->msg==NULL || ket==NULL) {
807 		LM_ERR("invalid ruby environment attributes or parameters (%p/%p/%p)\n",
808 				env_R, env_R->msg, ket);
809 		return Qfalse;
810 	}
811 
812 	if(argc==0 && ket->ptypes[0]==SR_KEMIP_NONE) {
813 		if(ket->rtype==SR_KEMIP_XVAL) {
814 			xret = ((sr_kemi_xfm_f)(ket->func))(env_R->msg);
815 			return sr_kemi_ruby_return_xval(ket, xret);
816 		} else {
817 			ret = ((sr_kemi_fm_f)(ket->func))(env_R->msg);
818 			return sr_kemi_ruby_return_int(ket, ret);
819 		}
820 	}
821 	fname = &ket->fname;
822 	mname = &ket->mname;
823 	if(argc==0 && ket->ptypes[0]!=SR_KEMIP_NONE) {
824 		LM_ERR("invalid number of parameters for: %.*s.%.*s\n",
825 				mname->len, mname->s, fname->len, fname->s);
826 		return Qfalse;
827 	}
828 
829 	if(argc>SR_KEMI_PARAMS_MAX) {
830 		LM_ERR("too many parameters for: %.*s.%.*s\n",
831 				mname->len, mname->s, fname->len, fname->s);
832 		return Qfalse;
833 	}
834 
835 	memset(vps, 0, SR_KEMI_PARAMS_MAX*sizeof(sr_kemi_val_t));
836 	for(i=0; i<SR_KEMI_PARAMS_MAX; i++) {
837 		if(ket->ptypes[i]==SR_KEMIP_NONE) {
838 			break;
839 		} else if(ket->ptypes[i]==SR_KEMIP_STR) {
840 			if(!RB_TYPE_P(argv[i], T_STRING)) {
841 				LM_ERR("invalid str parameter type %d (%d)\n", ket->ptypes[i], i);
842 				return Qfalse;
843 			}
844 			vps[i].s.s = StringValuePtr(argv[i]);
845 			vps[i].s.len = strlen(vps[i].s.s);
846 			LM_DBG("param[%d] for: %.*s.%.*s is str: %.*s\n", i,
847 				mname->len, mname->s, fname->len, fname->s, vps[i].s.len, vps[i].s.s);
848 		} else if(ket->ptypes[i]==SR_KEMIP_INT) {
849 			if(!RB_TYPE_P(argv[i], T_FIXNUM)) {
850 				LM_ERR("invalid int parameter type %d (%d)\n", ket->ptypes[i], i);
851 				return Qfalse;
852 			}
853 			vps[i].n = NUM2INT(argv[i]);
854 			LM_DBG("param[%d] for: %.*s.%.*s is int: %d\n", i,
855 				mname->len, mname->s, fname->len, fname->s, vps[i].n);
856 		} else {
857 			LM_ERR("unknown parameter type %d (%d)\n", ket->ptypes[i], i);
858 			return Qfalse;
859 		}
860 	}
861 
862 	switch(i) {
863 		case 1:
864 			if(ket->ptypes[0]==SR_KEMIP_INT) {
865 				if(ket->rtype==SR_KEMIP_XVAL) {
866 					xret = ((sr_kemi_xfmn_f)(ket->func))(env_R->msg, vps[0].n);
867 					return sr_kemi_ruby_return_xval(ket, xret);
868 				} else {
869 					ret = ((sr_kemi_fmn_f)(ket->func))(env_R->msg, vps[0].n);
870 					return sr_kemi_ruby_return_int(ket, ret);
871 				}
872 			} else if(ket->ptypes[0]==SR_KEMIP_STR) {
873 				if(ket->rtype==SR_KEMIP_XVAL) {
874 					xret = ((sr_kemi_xfms_f)(ket->func))(env_R->msg, &vps[0].s);
875 					return sr_kemi_ruby_return_xval(ket, xret);
876 				} else {
877 					ret = ((sr_kemi_fms_f)(ket->func))(env_R->msg, &vps[0].s);
878 					return sr_kemi_ruby_return_int(ket, ret);
879 				}
880 			} else {
881 				LM_ERR("invalid parameters for: %.*s\n",
882 						fname->len, fname->s);
883 				return Qfalse;
884 			}
885 		break;
886 		case 2:
887 			if(ket->ptypes[0]==SR_KEMIP_INT) {
888 				if(ket->ptypes[1]==SR_KEMIP_INT) {
889 					if(ket->rtype==SR_KEMIP_XVAL) {
890 						xret = ((sr_kemi_xfmnn_f)(ket->func))(env_R->msg, vps[0].n, vps[1].n);
891 						return sr_kemi_ruby_return_xval(ket, xret);
892 					} else {
893 						ret = ((sr_kemi_fmnn_f)(ket->func))(env_R->msg, vps[0].n, vps[1].n);
894 						return sr_kemi_ruby_return_int(ket, ret);
895 					}
896 				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
897 					if(ket->rtype==SR_KEMIP_XVAL) {
898 						xret = ((sr_kemi_xfmns_f)(ket->func))(env_R->msg, vps[0].n, &vps[1].s);
899 						return sr_kemi_ruby_return_xval(ket, xret);
900 					} else {
901 						ret = ((sr_kemi_fmns_f)(ket->func))(env_R->msg, vps[0].n, &vps[1].s);
902 						return sr_kemi_ruby_return_int(ket, ret);
903 					}
904 				} else {
905 					LM_ERR("invalid parameters for: %.*s\n",
906 							fname->len, fname->s);
907 					return Qfalse;
908 				}
909 			} else if(ket->ptypes[0]==SR_KEMIP_STR) {
910 				if(ket->ptypes[1]==SR_KEMIP_INT) {
911 					if(ket->rtype==SR_KEMIP_XVAL) {
912 						xret = ((sr_kemi_xfmsn_f)(ket->func))(env_R->msg, &vps[0].s, vps[1].n);
913 						return sr_kemi_ruby_return_xval(ket, xret);
914 					} else {
915 						ret = ((sr_kemi_fmsn_f)(ket->func))(env_R->msg, &vps[0].s, vps[1].n);
916 						return sr_kemi_ruby_return_int(ket, ret);
917 					}
918 				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
919 					if(ket->rtype==SR_KEMIP_XVAL) {
920 						xret = ((sr_kemi_xfmss_f)(ket->func))(env_R->msg, &vps[0].s, &vps[1].s);
921 						return sr_kemi_ruby_return_xval(ket, xret);
922 					} else {
923 						ret = ((sr_kemi_fmss_f)(ket->func))(env_R->msg, &vps[0].s, &vps[1].s);
924 						return sr_kemi_ruby_return_int(ket, ret);
925 					}
926 				} else {
927 					LM_ERR("invalid parameters for: %.*s\n",
928 							fname->len, fname->s);
929 					return Qfalse;
930 				}
931 			} else {
932 				LM_ERR("invalid parameters for: %.*s\n",
933 						fname->len, fname->s);
934 				return Qfalse;
935 			}
936 		break;
937 		case 3:
938 			if(ket->ptypes[0]==SR_KEMIP_INT) {
939 				if(ket->ptypes[1]==SR_KEMIP_INT) {
940 					if(ket->ptypes[2]==SR_KEMIP_INT) {
941 						ret = ((sr_kemi_fmnnn_f)(ket->func))(env_R->msg,
942 								vps[0].n, vps[1].n, vps[2].n);
943 						return sr_kemi_ruby_return_int(ket, ret);
944 					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
945 						ret = ((sr_kemi_fmnns_f)(ket->func))(env_R->msg,
946 								vps[0].n, vps[1].n, &vps[2].s);
947 						return sr_kemi_ruby_return_int(ket, ret);
948 					} else {
949 						LM_ERR("invalid parameters for: %.*s\n",
950 								fname->len, fname->s);
951 						return Qfalse;
952 					}
953 				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
954 					if(ket->ptypes[2]==SR_KEMIP_INT) {
955 						ret = ((sr_kemi_fmnsn_f)(ket->func))(env_R->msg,
956 								vps[0].n, &vps[1].s, vps[2].n);
957 						return sr_kemi_ruby_return_int(ket, ret);
958 					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
959 						ret = ((sr_kemi_fmnss_f)(ket->func))(env_R->msg,
960 								vps[0].n, &vps[1].s, &vps[2].s);
961 						return sr_kemi_ruby_return_int(ket, ret);
962 					} else {
963 						LM_ERR("invalid parameters for: %.*s\n",
964 								fname->len, fname->s);
965 						return Qfalse;
966 					}
967 				} else {
968 					LM_ERR("invalid parameters for: %.*s\n",
969 							fname->len, fname->s);
970 					return Qfalse;
971 				}
972 			} else if(ket->ptypes[0]==SR_KEMIP_STR) {
973 				if(ket->ptypes[1]==SR_KEMIP_INT) {
974 					if(ket->ptypes[2]==SR_KEMIP_INT) {
975 						ret = ((sr_kemi_fmsnn_f)(ket->func))(env_R->msg,
976 								&vps[0].s, vps[1].n, vps[2].n);
977 						return sr_kemi_ruby_return_int(ket, ret);
978 					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
979 						ret = ((sr_kemi_fmsns_f)(ket->func))(env_R->msg,
980 								&vps[0].s, vps[1].n, &vps[2].s);
981 						return sr_kemi_ruby_return_int(ket, ret);
982 					} else {
983 						LM_ERR("invalid parameters for: %.*s\n",
984 								fname->len, fname->s);
985 						return Qfalse;
986 					}
987 				} else if(ket->ptypes[1]==SR_KEMIP_STR) {
988 					if(ket->ptypes[2]==SR_KEMIP_INT) {
989 						ret = ((sr_kemi_fmssn_f)(ket->func))(env_R->msg,
990 								&vps[0].s, &vps[1].s, vps[2].n);
991 						return sr_kemi_ruby_return_int(ket, ret);
992 					} else if(ket->ptypes[2]==SR_KEMIP_STR) {
993 						ret = ((sr_kemi_fmsss_f)(ket->func))(env_R->msg,
994 								&vps[0].s, &vps[1].s, &vps[2].s);
995 						return sr_kemi_ruby_return_int(ket, ret);
996 					} else {
997 						LM_ERR("invalid parameters for: %.*s\n",
998 								fname->len, fname->s);
999 						return Qfalse;
1000 					}
1001 				} else {
1002 					LM_ERR("invalid parameters for: %.*s\n",
1003 							fname->len, fname->s);
1004 					return Qfalse;
1005 				}
1006 			} else {
1007 				LM_ERR("invalid parameters for: %.*s\n",
1008 						fname->len, fname->s);
1009 				return Qfalse;
1010 			}
1011 		break;
1012 		case 4:
1013 			if(ket->ptypes[0]==SR_KEMIP_STR
1014 					&& ket->ptypes[1]==SR_KEMIP_STR
1015 					&& ket->ptypes[2]==SR_KEMIP_STR
1016 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1017 				ret = ((sr_kemi_fmssss_f)(ket->func))(env_R->msg,
1018 						&vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s);
1019 				return sr_kemi_ruby_return_int(ket, ret);
1020 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1021 					&& ket->ptypes[1]==SR_KEMIP_STR
1022 					&& ket->ptypes[2]==SR_KEMIP_STR
1023 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1024 				ret = ((sr_kemi_fmsssn_f)(ket->func))(env_R->msg,
1025 						&vps[0].s, &vps[1].s, &vps[2].s, vps[3].n);
1026 				return sr_kemi_ruby_return_int(ket, ret);
1027 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1028 					&& ket->ptypes[1]==SR_KEMIP_STR
1029 					&& ket->ptypes[2]==SR_KEMIP_INT
1030 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1031 				ret = ((sr_kemi_fmssns_f)(ket->func))(env_R->msg,
1032 						&vps[0].s, &vps[1].s, vps[2].n, &vps[3].s);
1033 				return sr_kemi_ruby_return_int(ket, ret);
1034 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1035 					&& ket->ptypes[1]==SR_KEMIP_STR
1036 					&& ket->ptypes[2]==SR_KEMIP_INT
1037 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1038 				ret = ((sr_kemi_fmssnn_f)(ket->func))(env_R->msg,
1039 						&vps[0].s, &vps[1].s, vps[2].n, vps[3].n);
1040 				return sr_kemi_ruby_return_int(ket, ret);
1041 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1042 					&& ket->ptypes[1]==SR_KEMIP_INT
1043 					&& ket->ptypes[2]==SR_KEMIP_STR
1044 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1045 				ret = ((sr_kemi_fmsnss_f)(ket->func))(env_R->msg,
1046 						&vps[0].s, vps[1].n, &vps[2].s, &vps[3].s);
1047 				return sr_kemi_ruby_return_int(ket, ret);
1048 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1049 					&& ket->ptypes[1]==SR_KEMIP_INT
1050 					&& ket->ptypes[2]==SR_KEMIP_STR
1051 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1052 				ret = ((sr_kemi_fmsnsn_f)(ket->func))(env_R->msg,
1053 						&vps[0].s, vps[1].n, &vps[2].s, vps[3].n);
1054 				return sr_kemi_ruby_return_int(ket, ret);
1055 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1056 					&& ket->ptypes[1]==SR_KEMIP_INT
1057 					&& ket->ptypes[2]==SR_KEMIP_INT
1058 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1059 				ret = ((sr_kemi_fmsnns_f)(ket->func))(env_R->msg,
1060 						&vps[0].s, vps[1].n, vps[2].n, &vps[3].s);
1061 				return sr_kemi_ruby_return_int(ket, ret);
1062 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1063 					&& ket->ptypes[1]==SR_KEMIP_INT
1064 					&& ket->ptypes[2]==SR_KEMIP_INT
1065 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1066 				ret = ((sr_kemi_fmsnnn_f)(ket->func))(env_R->msg,
1067 						&vps[0].s, vps[1].n, vps[2].n, vps[3].n);
1068 				return sr_kemi_ruby_return_int(ket, ret);
1069 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1070 					&& ket->ptypes[1]==SR_KEMIP_STR
1071 					&& ket->ptypes[2]==SR_KEMIP_STR
1072 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1073 				ret = ((sr_kemi_fmnsss_f)(ket->func))(env_R->msg,
1074 						vps[0].n, &vps[1].s, &vps[2].s, &vps[3].s);
1075 				return sr_kemi_ruby_return_int(ket, ret);
1076 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1077 					&& ket->ptypes[1]==SR_KEMIP_STR
1078 					&& ket->ptypes[2]==SR_KEMIP_STR
1079 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1080 				ret = ((sr_kemi_fmnssn_f)(ket->func))(env_R->msg,
1081 						vps[0].n, &vps[1].s, &vps[2].s, vps[3].n);
1082 				return sr_kemi_ruby_return_int(ket, ret);
1083 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1084 					&& ket->ptypes[1]==SR_KEMIP_STR
1085 					&& ket->ptypes[2]==SR_KEMIP_INT
1086 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1087 				ret = ((sr_kemi_fmnsns_f)(ket->func))(env_R->msg,
1088 						vps[0].n, &vps[1].s, vps[2].n, &vps[3].s);
1089 				return sr_kemi_ruby_return_int(ket, ret);
1090 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1091 					&& ket->ptypes[1]==SR_KEMIP_STR
1092 					&& ket->ptypes[2]==SR_KEMIP_INT
1093 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1094 				ret = ((sr_kemi_fmnsnn_f)(ket->func))(env_R->msg,
1095 						vps[0].n, &vps[1].s, vps[2].n, vps[3].n);
1096 				return sr_kemi_ruby_return_int(ket, ret);
1097 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1098 					&& ket->ptypes[1]==SR_KEMIP_INT
1099 					&& ket->ptypes[2]==SR_KEMIP_STR
1100 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1101 				ret = ((sr_kemi_fmnnss_f)(ket->func))(env_R->msg,
1102 						vps[0].n, vps[1].n, &vps[2].s, &vps[3].s);
1103 				return sr_kemi_ruby_return_int(ket, ret);
1104 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1105 					&& ket->ptypes[1]==SR_KEMIP_INT
1106 					&& ket->ptypes[2]==SR_KEMIP_STR
1107 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1108 				ret = ((sr_kemi_fmnnsn_f)(ket->func))(env_R->msg,
1109 						vps[0].n, vps[1].n, &vps[2].s, vps[3].n);
1110 				return sr_kemi_ruby_return_int(ket, ret);
1111 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1112 					&& ket->ptypes[1]==SR_KEMIP_INT
1113 					&& ket->ptypes[2]==SR_KEMIP_INT
1114 					&& ket->ptypes[3]==SR_KEMIP_STR) {
1115 				ret = ((sr_kemi_fmnnns_f)(ket->func))(env_R->msg,
1116 						vps[0].n, vps[1].n, vps[2].n, &vps[3].s);
1117 				return sr_kemi_ruby_return_int(ket, ret);
1118 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1119 					&& ket->ptypes[1]==SR_KEMIP_INT
1120 					&& ket->ptypes[2]==SR_KEMIP_INT
1121 					&& ket->ptypes[3]==SR_KEMIP_INT) {
1122 				ret = ((sr_kemi_fmnnnn_f)(ket->func))(env_R->msg,
1123 						vps[0].n, vps[1].n, vps[2].n, vps[3].n);
1124 				return sr_kemi_ruby_return_int(ket, ret);
1125 			} else {
1126 				LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s);
1127 				return Qfalse;
1128 			}
1129 		break;
1130 		case 5:
1131 			if(ket->ptypes[0]==SR_KEMIP_STR
1132 					&& ket->ptypes[1]==SR_KEMIP_STR
1133 					&& ket->ptypes[2]==SR_KEMIP_STR
1134 					&& ket->ptypes[3]==SR_KEMIP_STR
1135 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1136 				ret = ((sr_kemi_fmsssss_f)(ket->func))(env_R->msg,
1137 						&vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s, &vps[4].s);
1138 				return sr_kemi_ruby_return_int(ket, ret);
1139 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1140 					&& ket->ptypes[1]==SR_KEMIP_STR
1141 					&& ket->ptypes[2]==SR_KEMIP_STR
1142 					&& ket->ptypes[3]==SR_KEMIP_STR
1143 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1144 				ret = ((sr_kemi_fmssssn_f)(ket->func))(env_R->msg,
1145 						&vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s, vps[4].n);
1146 				return sr_kemi_ruby_return_int(ket, ret);
1147 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1148 					&& ket->ptypes[1]==SR_KEMIP_STR
1149 					&& ket->ptypes[2]==SR_KEMIP_STR
1150 					&& ket->ptypes[3]==SR_KEMIP_INT
1151 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1152 				ret = ((sr_kemi_fmsssns_f)(ket->func))(env_R->msg,
1153 						&vps[0].s, &vps[1].s, &vps[2].s, vps[3].n, &vps[4].s);
1154 				return sr_kemi_ruby_return_int(ket, ret);
1155 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1156 					&& ket->ptypes[1]==SR_KEMIP_STR
1157 					&& ket->ptypes[2]==SR_KEMIP_STR
1158 					&& ket->ptypes[3]==SR_KEMIP_INT
1159 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1160 				ret = ((sr_kemi_fmsssnn_f)(ket->func))(env_R->msg,
1161 						&vps[0].s, &vps[1].s, &vps[2].s, vps[3].n, vps[4].n);
1162 				return sr_kemi_ruby_return_int(ket, ret);
1163 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1164 					&& ket->ptypes[1]==SR_KEMIP_STR
1165 					&& ket->ptypes[2]==SR_KEMIP_INT
1166 					&& ket->ptypes[3]==SR_KEMIP_STR
1167 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1168 				ret = ((sr_kemi_fmssnss_f)(ket->func))(env_R->msg,
1169 						&vps[0].s, &vps[1].s, vps[2].n, &vps[3].s, &vps[4].s);
1170 				return sr_kemi_ruby_return_int(ket, ret);
1171 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1172 					&& ket->ptypes[1]==SR_KEMIP_STR
1173 					&& ket->ptypes[2]==SR_KEMIP_INT
1174 					&& ket->ptypes[3]==SR_KEMIP_STR
1175 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1176 				ret = ((sr_kemi_fmssnsn_f)(ket->func))(env_R->msg,
1177 						&vps[0].s, &vps[1].s, vps[2].n, &vps[3].s, vps[4].n);
1178 				return sr_kemi_ruby_return_int(ket, ret);
1179 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1180 					&& ket->ptypes[1]==SR_KEMIP_STR
1181 					&& ket->ptypes[2]==SR_KEMIP_INT
1182 					&& ket->ptypes[3]==SR_KEMIP_INT
1183 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1184 				ret = ((sr_kemi_fmssnns_f)(ket->func))(env_R->msg,
1185 						&vps[0].s, &vps[1].s, vps[2].n, vps[3].n, &vps[4].s);
1186 				return sr_kemi_ruby_return_int(ket, ret);
1187 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1188 					&& ket->ptypes[1]==SR_KEMIP_STR
1189 					&& ket->ptypes[2]==SR_KEMIP_INT
1190 					&& ket->ptypes[3]==SR_KEMIP_INT
1191 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1192 				ret = ((sr_kemi_fmssnnn_f)(ket->func))(env_R->msg,
1193 						&vps[0].s, &vps[1].s, vps[2].n, vps[3].n, vps[4].n);
1194 				return sr_kemi_ruby_return_int(ket, ret);
1195 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1196 					&& ket->ptypes[1]==SR_KEMIP_INT
1197 					&& ket->ptypes[2]==SR_KEMIP_STR
1198 					&& ket->ptypes[3]==SR_KEMIP_STR
1199 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1200 				ret = ((sr_kemi_fmsnsss_f)(ket->func))(env_R->msg,
1201 						&vps[0].s, vps[1].n, &vps[2].s, &vps[3].s, &vps[4].s);
1202 				return sr_kemi_ruby_return_int(ket, ret);
1203 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1204 					&& ket->ptypes[1]==SR_KEMIP_INT
1205 					&& ket->ptypes[2]==SR_KEMIP_STR
1206 					&& ket->ptypes[3]==SR_KEMIP_STR
1207 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1208 				ret = ((sr_kemi_fmsnssn_f)(ket->func))(env_R->msg,
1209 						&vps[0].s, vps[1].n, &vps[2].s, &vps[3].s, vps[4].n);
1210 				return sr_kemi_ruby_return_int(ket, ret);
1211 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1212 					&& ket->ptypes[1]==SR_KEMIP_INT
1213 					&& ket->ptypes[2]==SR_KEMIP_STR
1214 					&& ket->ptypes[3]==SR_KEMIP_INT
1215 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1216 				ret = ((sr_kemi_fmsnsns_f)(ket->func))(env_R->msg,
1217 						&vps[0].s, vps[1].n, &vps[2].s, vps[3].n, &vps[4].s);
1218 				return sr_kemi_ruby_return_int(ket, ret);
1219 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1220 					&& ket->ptypes[1]==SR_KEMIP_INT
1221 					&& ket->ptypes[2]==SR_KEMIP_STR
1222 					&& ket->ptypes[3]==SR_KEMIP_INT
1223 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1224 				ret = ((sr_kemi_fmsnsnn_f)(ket->func))(env_R->msg,
1225 						&vps[0].s, vps[1].n, &vps[2].s, vps[3].n, vps[4].n);
1226 				return sr_kemi_ruby_return_int(ket, ret);
1227 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1228 					&& ket->ptypes[1]==SR_KEMIP_INT
1229 					&& ket->ptypes[2]==SR_KEMIP_INT
1230 					&& ket->ptypes[3]==SR_KEMIP_STR
1231 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1232 				ret = ((sr_kemi_fmsnnss_f)(ket->func))(env_R->msg,
1233 						&vps[0].s, vps[1].n, vps[2].n, &vps[3].s, &vps[4].s);
1234 				return sr_kemi_ruby_return_int(ket, ret);
1235 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1236 					&& ket->ptypes[1]==SR_KEMIP_INT
1237 					&& ket->ptypes[2]==SR_KEMIP_INT
1238 					&& ket->ptypes[3]==SR_KEMIP_STR
1239 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1240 				ret = ((sr_kemi_fmsnnsn_f)(ket->func))(env_R->msg,
1241 						&vps[0].s, vps[1].n, vps[2].n, &vps[3].s, vps[4].n);
1242 				return sr_kemi_ruby_return_int(ket, ret);
1243 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1244 					&& ket->ptypes[1]==SR_KEMIP_INT
1245 					&& ket->ptypes[2]==SR_KEMIP_INT
1246 					&& ket->ptypes[3]==SR_KEMIP_INT
1247 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1248 				ret = ((sr_kemi_fmsnnns_f)(ket->func))(env_R->msg,
1249 						&vps[0].s, vps[1].n, vps[2].n, vps[3].n, &vps[4].s);
1250 				return sr_kemi_ruby_return_int(ket, ret);
1251 			} else if(ket->ptypes[0]==SR_KEMIP_STR
1252 					&& ket->ptypes[1]==SR_KEMIP_INT
1253 					&& ket->ptypes[2]==SR_KEMIP_INT
1254 					&& ket->ptypes[3]==SR_KEMIP_INT
1255 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1256 				ret = ((sr_kemi_fmsnnnn_f)(ket->func))(env_R->msg,
1257 						&vps[0].s, vps[1].n, vps[2].n, vps[3].n, vps[4].n);
1258 				return sr_kemi_ruby_return_int(ket, ret);
1259 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1260 					&& ket->ptypes[1]==SR_KEMIP_STR
1261 					&& ket->ptypes[2]==SR_KEMIP_STR
1262 					&& ket->ptypes[3]==SR_KEMIP_STR
1263 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1264 				ret = ((sr_kemi_fmnssss_f)(ket->func))(env_R->msg,
1265 						vps[0].n, &vps[1].s, &vps[2].s, &vps[3].s, &vps[4].s);
1266 				return sr_kemi_ruby_return_int(ket, ret);
1267 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1268 					&& ket->ptypes[1]==SR_KEMIP_STR
1269 					&& ket->ptypes[2]==SR_KEMIP_STR
1270 					&& ket->ptypes[3]==SR_KEMIP_STR
1271 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1272 				ret = ((sr_kemi_fmnsssn_f)(ket->func))(env_R->msg,
1273 						vps[0].n, &vps[1].s, &vps[2].s, &vps[3].s, vps[4].n);
1274 				return sr_kemi_ruby_return_int(ket, ret);
1275 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1276 					&& ket->ptypes[1]==SR_KEMIP_STR
1277 					&& ket->ptypes[2]==SR_KEMIP_STR
1278 					&& ket->ptypes[3]==SR_KEMIP_INT
1279 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1280 				ret = ((sr_kemi_fmnssns_f)(ket->func))(env_R->msg,
1281 						vps[0].n, &vps[1].s, &vps[2].s, vps[3].n, &vps[4].s);
1282 				return sr_kemi_ruby_return_int(ket, ret);
1283 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1284 					&& ket->ptypes[1]==SR_KEMIP_STR
1285 					&& ket->ptypes[2]==SR_KEMIP_STR
1286 					&& ket->ptypes[3]==SR_KEMIP_INT
1287 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1288 				ret = ((sr_kemi_fmnssnn_f)(ket->func))(env_R->msg,
1289 						vps[0].n, &vps[1].s, &vps[2].s, vps[3].n, vps[4].n);
1290 				return sr_kemi_ruby_return_int(ket, ret);
1291 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1292 					&& ket->ptypes[1]==SR_KEMIP_STR
1293 					&& ket->ptypes[2]==SR_KEMIP_INT
1294 					&& ket->ptypes[3]==SR_KEMIP_STR
1295 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1296 				ret = ((sr_kemi_fmnsnss_f)(ket->func))(env_R->msg,
1297 						vps[0].n, &vps[1].s, vps[2].n, &vps[3].s, &vps[4].s);
1298 				return sr_kemi_ruby_return_int(ket, ret);
1299 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1300 					&& ket->ptypes[1]==SR_KEMIP_STR
1301 					&& ket->ptypes[2]==SR_KEMIP_INT
1302 					&& ket->ptypes[3]==SR_KEMIP_STR
1303 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1304 				ret = ((sr_kemi_fmnsnsn_f)(ket->func))(env_R->msg,
1305 						vps[0].n, &vps[1].s, vps[2].n, &vps[3].s, vps[4].n);
1306 				return sr_kemi_ruby_return_int(ket, ret);
1307 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1308 					&& ket->ptypes[1]==SR_KEMIP_STR
1309 					&& ket->ptypes[2]==SR_KEMIP_INT
1310 					&& ket->ptypes[3]==SR_KEMIP_INT
1311 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1312 				ret = ((sr_kemi_fmnsnns_f)(ket->func))(env_R->msg,
1313 						vps[0].n, &vps[1].s, vps[2].n, vps[3].n, &vps[4].s);
1314 				return sr_kemi_ruby_return_int(ket, ret);
1315 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1316 					&& ket->ptypes[1]==SR_KEMIP_STR
1317 					&& ket->ptypes[2]==SR_KEMIP_INT
1318 					&& ket->ptypes[3]==SR_KEMIP_INT
1319 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1320 				ret = ((sr_kemi_fmnsnnn_f)(ket->func))(env_R->msg,
1321 						vps[0].n, &vps[1].s, vps[2].n, vps[3].n, vps[4].n);
1322 				return sr_kemi_ruby_return_int(ket, ret);
1323 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1324 					&& ket->ptypes[1]==SR_KEMIP_INT
1325 					&& ket->ptypes[2]==SR_KEMIP_STR
1326 					&& ket->ptypes[3]==SR_KEMIP_STR
1327 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1328 				ret = ((sr_kemi_fmnnsss_f)(ket->func))(env_R->msg,
1329 						vps[0].n, vps[1].n, &vps[2].s, &vps[3].s, &vps[4].s);
1330 				return sr_kemi_ruby_return_int(ket, ret);
1331 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1332 					&& ket->ptypes[1]==SR_KEMIP_INT
1333 					&& ket->ptypes[2]==SR_KEMIP_STR
1334 					&& ket->ptypes[3]==SR_KEMIP_STR
1335 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1336 				ret = ((sr_kemi_fmnnssn_f)(ket->func))(env_R->msg,
1337 						vps[0].n, vps[1].n, &vps[2].s, &vps[3].s, vps[4].n);
1338 				return sr_kemi_ruby_return_int(ket, ret);
1339 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1340 					&& ket->ptypes[1]==SR_KEMIP_INT
1341 					&& ket->ptypes[2]==SR_KEMIP_STR
1342 					&& ket->ptypes[3]==SR_KEMIP_INT
1343 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1344 				ret = ((sr_kemi_fmnnsns_f)(ket->func))(env_R->msg,
1345 						vps[0].n, vps[1].n, &vps[2].s, vps[3].n, &vps[4].s);
1346 				return sr_kemi_ruby_return_int(ket, ret);
1347 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1348 					&& ket->ptypes[1]==SR_KEMIP_INT
1349 					&& ket->ptypes[2]==SR_KEMIP_STR
1350 					&& ket->ptypes[3]==SR_KEMIP_INT
1351 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1352 				ret = ((sr_kemi_fmnnsnn_f)(ket->func))(env_R->msg,
1353 						vps[0].n, vps[1].n, &vps[2].s, vps[3].n, vps[4].n);
1354 				return sr_kemi_ruby_return_int(ket, ret);
1355 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1356 					&& ket->ptypes[1]==SR_KEMIP_INT
1357 					&& ket->ptypes[2]==SR_KEMIP_INT
1358 					&& ket->ptypes[3]==SR_KEMIP_STR
1359 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1360 				ret = ((sr_kemi_fmnnnss_f)(ket->func))(env_R->msg,
1361 						vps[0].n, vps[1].n, vps[2].n, &vps[3].s, &vps[4].s);
1362 				return sr_kemi_ruby_return_int(ket, ret);
1363 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1364 					&& ket->ptypes[1]==SR_KEMIP_INT
1365 					&& ket->ptypes[2]==SR_KEMIP_INT
1366 					&& ket->ptypes[3]==SR_KEMIP_STR
1367 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1368 				ret = ((sr_kemi_fmnnnsn_f)(ket->func))(env_R->msg,
1369 						vps[0].n, vps[1].n, vps[2].n, &vps[3].s, vps[4].n);
1370 				return sr_kemi_ruby_return_int(ket, ret);
1371 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1372 					&& ket->ptypes[1]==SR_KEMIP_INT
1373 					&& ket->ptypes[2]==SR_KEMIP_INT
1374 					&& ket->ptypes[3]==SR_KEMIP_INT
1375 					&& ket->ptypes[4]==SR_KEMIP_STR) {
1376 				ret = ((sr_kemi_fmnnnns_f)(ket->func))(env_R->msg,
1377 						vps[0].n, vps[1].n, vps[2].n, vps[3].n, &vps[4].s);
1378 				return sr_kemi_ruby_return_int(ket, ret);
1379 			} else if(ket->ptypes[0]==SR_KEMIP_INT
1380 					&& ket->ptypes[1]==SR_KEMIP_INT
1381 					&& ket->ptypes[2]==SR_KEMIP_INT
1382 					&& ket->ptypes[3]==SR_KEMIP_INT
1383 					&& ket->ptypes[4]==SR_KEMIP_INT) {
1384 				ret = ((sr_kemi_fmnnnnn_f)(ket->func))(env_R->msg,
1385 						vps[0].n, vps[1].n, vps[2].n, vps[3].n, vps[4].n);
1386 				return sr_kemi_ruby_return_int(ket, ret);
1387 			} else {
1388 				LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s);
1389 				return Qfalse;
1390 			}
1391 		break;
1392 		case 6:
1393 			if(ket->ptypes[0]==SR_KEMIP_STR
1394 					&& ket->ptypes[1]==SR_KEMIP_STR
1395 					&& ket->ptypes[2]==SR_KEMIP_STR
1396 					&& ket->ptypes[3]==SR_KEMIP_STR
1397 					&& ket->ptypes[4]==SR_KEMIP_STR
1398 					&& ket->ptypes[5]==SR_KEMIP_STR) {
1399 				ret = ((sr_kemi_fmssssss_f)(ket->func))(env_R->msg,
1400 						&vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s,
1401 						&vps[4].s, &vps[5].s);
1402 				return sr_kemi_ruby_return_int(ket, ret);
1403 			} else {
1404 				LM_ERR("invalid parameters for: %.*s\n",
1405 						fname->len, fname->s);
1406 				return Qfalse;
1407 			}
1408 		break;
1409 		default:
1410 			LM_ERR("invalid parameters for: %.*s\n",
1411 					fname->len, fname->s);
1412 			return Qfalse;
1413 	}
1414 }
1415 
1416 /**
1417  *
1418  */
sr_kemi_ruby_exec_func(ksr_ruby_context_t * R,int eidx,int argc,VALUE * argv,VALUE self)1419 VALUE sr_kemi_ruby_exec_func(ksr_ruby_context_t *R, int eidx, int argc,
1420 		VALUE* argv, VALUE self)
1421 {
1422 	sr_kemi_t *ket;
1423 	int ret;
1424 	struct timeval tvb = {0}, tve = {0};
1425 	struct timezone tz;
1426 	unsigned int tdiff;
1427 
1428 	ket = sr_kemi_ruby_export_get(eidx);
1429 
1430 	LM_DBG("executing %p eidx %d\n", ket, eidx);
1431 
1432 	if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)
1433 			&& is_printable(cfg_get(core, core_cfg, latency_log))) {
1434 		gettimeofday(&tvb, &tz);
1435 	}
1436 
1437 	ret = sr_kemi_ruby_exec_func_ex(R, ket, argc, argv, self);
1438 
1439 	if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)
1440 			&& is_printable(cfg_get(core, core_cfg, latency_log))) {
1441 		gettimeofday(&tve, &tz);
1442 		tdiff = (tve.tv_sec - tvb.tv_sec) * 1000000
1443 				   + (tve.tv_usec - tvb.tv_usec);
1444 		if(tdiff >= cfg_get(core, core_cfg, latency_limit_action)) {
1445 			LOG(cfg_get(core, core_cfg, latency_log),
1446 						"alert - action KSR.%s%s%s(...)"
1447 						" took too long [%u us]\n",
1448 						(ket->mname.len>0)?ket->mname.s:"",
1449 						(ket->mname.len>0)?".":"", ket->fname.s,
1450 						tdiff);
1451 		}
1452 	}
1453 
1454 	return ret;
1455 }
1456 
1457 /**
1458  *
1459  */
app_ruby_run_ex(sip_msg_t * msg,char * func,char * p1,char * p2,char * p3,int emode)1460 int app_ruby_run_ex(sip_msg_t *msg, char *func, char *p1, char *p2,
1461 		char *p3, int emode)
1462 {
1463 	sip_msg_t *bmsg;
1464 	ksr_ruby_data_t rbdata;
1465     int rberr = 0;
1466     VALUE rbres;
1467 
1468 	if(_sr_R_env.rinit==0) {
1469 		LM_ERR("js loading state not initialized (call: %s)\n", func);
1470 		return -1;
1471 	}
1472 	/* check the script version loaded */
1473 	app_ruby_kemi_reload_script();
1474 
1475 	memset(&rbdata, 0, sizeof(ksr_ruby_data_t));
1476 	rbdata.robj = rb_mKernel;
1477 	rbdata.metid = rb_intern(func);
1478 
1479 	LM_DBG("executing ruby function: [[%s]]\n", func);
1480 	bmsg = _sr_R_env.msg;
1481 	_sr_R_env.msg = msg;
1482 	if(p1!=NULL) {
1483 		rbdata.vargs[rbdata.nargs] = rb_str_new_cstr(p1);
1484 		rbdata.nargs++;
1485 		if(p2!=NULL) {
1486 			rbdata.vargs[rbdata.nargs] = rb_str_new_cstr(p2);
1487 			rbdata.nargs++;
1488 			if(p3!=NULL) {
1489 				rbdata.vargs[rbdata.nargs] = rb_str_new_cstr(p3);
1490 				rbdata.nargs++;
1491 			}
1492 		}
1493 	}
1494 
1495 	rbres = rb_protect(ksr_ruby_exec_callback, (VALUE)&rbdata, &rberr);
1496 
1497 	_sr_R_env.msg = bmsg;
1498 
1499 	if (rberr) {
1500 		if(app_ruby_print_last_exception()==0) {
1501 			LM_ERR("ruby exception (%d) on callback for: %s (res type: %d)\n",
1502 					rberr, func, TYPE(rbres));
1503 			return -1;
1504 		}
1505 	}
1506 
1507 	return 1;
1508 }
1509 
1510 /**
1511  *
1512  */
app_ruby_run(sip_msg_t * msg,char * func,char * p1,char * p2,char * p3)1513 int app_ruby_run(sip_msg_t *msg, char *func, char *p1, char *p2,
1514 		char *p3)
1515 {
1516 	return app_ruby_run_ex(msg, func, p1, p2, p3, 0);
1517 }
1518 
1519 /**
1520  *
1521  */
app_ruby_runstring(sip_msg_t * msg,char * script)1522 int app_ruby_runstring(sip_msg_t *msg, char *script)
1523 {
1524 	LM_ERR("not implemented\n");
1525 	return -1;
1526 }
1527 
1528 /**
1529  *
1530  */
app_ruby_dostring(sip_msg_t * msg,char * script)1531 int app_ruby_dostring(sip_msg_t *msg, char *script)
1532 {
1533 	LM_ERR("not implemented\n");
1534 	return -1;
1535 }
1536 
1537 /**
1538  *
1539  */
app_ruby_dofile(sip_msg_t * msg,char * script)1540 int app_ruby_dofile(sip_msg_t *msg, char *script)
1541 {
1542 	LM_ERR("not implemented\n");
1543 	return -1;
1544 }
1545 
1546 ksr_ruby_export_t *_sr_R_KSRMethods = NULL;
1547 #define SR_RUBY_KSR_MODULES_SIZE	256
1548 #define SR_RUBY_KSR_METHODS_SIZE	(SR_KEMI_RUBY_EXPORT_SIZE + SR_RUBY_KSR_MODULES_SIZE)
1549 
1550 static VALUE _ksr_mKSR;
1551 static VALUE _ksr_mSMD[SR_RUBY_KSR_MODULES_SIZE];
1552 
1553 /**
1554  *
1555  */
ksr_app_ruby_toupper(char * bin,char * bout)1556 void ksr_app_ruby_toupper(char *bin, char *bout)
1557 {
1558 	int i;
1559 	for(i=0; bin[i]!='\0'; i++) {
1560 		bout[i] = (char)toupper(bin[i]);
1561 	}
1562 	bout[i] = '\0';
1563 }
1564 /**
1565  *
1566  */
app_ruby_kemi_export_libs(void)1567 int app_ruby_kemi_export_libs(void)
1568 {
1569 	ksr_ruby_export_t *_sr_crt_R_KSRMethods = NULL;
1570 	sr_kemi_module_t *emods = NULL;
1571 	int emods_size = 0;
1572 	int i;
1573 	int k;
1574 	int n;
1575 	int m;
1576 	char rmname[128];
1577 
1578 	_sr_R_KSRMethods = malloc(SR_RUBY_KSR_METHODS_SIZE * sizeof(ksr_ruby_export_t));
1579 	if(_sr_R_KSRMethods==NULL) {
1580 		LM_ERR("no more pkg memory\n");
1581 		return 0;
1582 	}
1583 	memset(_sr_R_KSRMethods, 0, SR_RUBY_KSR_METHODS_SIZE * sizeof(ksr_ruby_export_t));
1584 
1585 	emods_size = sr_kemi_modules_size_get();
1586 	emods = sr_kemi_modules_get();
1587 
1588 	n = 0;
1589 	_sr_crt_R_KSRMethods = _sr_R_KSRMethods;
1590 	if(emods_size==0 || emods[0].kexp==NULL) {
1591 		LM_ERR("no kemi exports registered\n");
1592 		return 0;
1593 	}
1594 
1595 	/* toplevel module KSR */
1596 	_ksr_mKSR = rb_define_module("KSR");
1597 
1598 	for(i=0; emods[0].kexp[i].func!=NULL; i++) {
1599 		LM_DBG("exporting KSR.%s(...)\n", emods[0].kexp[i].fname.s);
1600 		_sr_crt_R_KSRMethods[i].mname = "";
1601 		_sr_crt_R_KSRMethods[i].fname = emods[0].kexp[i].fname.s;
1602 		_sr_crt_R_KSRMethods[i].func =
1603 			sr_kemi_ruby_export_associate(&emods[0].kexp[i]);
1604 		if(_sr_crt_R_KSRMethods[i].func == NULL) {
1605 			LM_ERR("failed to associate kemi function with ruby export\n");
1606 			free(_sr_R_KSRMethods);
1607 			_sr_R_KSRMethods = NULL;
1608 			return 0;
1609 		}
1610 
1611 		rb_define_singleton_method(_ksr_mKSR, _sr_crt_R_KSRMethods[i].fname,
1612 						_sr_crt_R_KSRMethods[i].func, -1);
1613 
1614 		n++;
1615 	}
1616 
1617 	m = 0;
1618 
1619 	if(_ksr_app_ruby_xval_mode==0) {
1620 		/* pv submodule */
1621 		_ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, "PV");
1622 		for(i=0; _sr_kemi_pv_R_Map[i].fname!=0; i++) {
1623 			LM_DBG("exporting KSR.PV.%s(...)\n", _sr_kemi_pv_R_Map[i].fname);
1624 			rb_define_singleton_method(_ksr_mSMD[m], _sr_kemi_pv_R_Map[i].fname,
1625 					_sr_kemi_pv_R_Map[i].func, -1);
1626 		}
1627 		LM_DBG("initialized kemi sub-module: KSR.PV\n");
1628 		m++;
1629 	}
1630 
1631 	/* x submodule */
1632 	_ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, "X");
1633 	for(i=0; _sr_kemi_x_R_Map[i].fname!=0; i++) {
1634 		LM_DBG("exporting KSR.X.%s(...)\n", _sr_kemi_x_R_Map[i].fname);
1635 		rb_define_singleton_method(_ksr_mSMD[m], _sr_kemi_x_R_Map[i].fname,
1636 				_sr_kemi_x_R_Map[i].func, -1);
1637 	}
1638 	LM_DBG("initialized kemi sub-module: KSR.X\n");
1639 	m++;
1640 
1641 	/* registered kemi modules */
1642 	if(emods_size>1) {
1643 		for(k=1; k<emods_size; k++) {
1644 			if((_ksr_app_ruby_xval_mode==0) && emods[k].kexp[0].mname.len==2
1645 					&& strncasecmp(emods[k].kexp[0].mname.s, "pv", 2)==0) {
1646 				LM_DBG("skipping external pv sub-module\n");
1647 				continue;
1648 			}
1649 			n++;
1650 			_sr_crt_R_KSRMethods = _sr_R_KSRMethods + n;
1651 			ksr_app_ruby_toupper(emods[k].kexp[0].mname.s, rmname);
1652 			_ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, rmname);
1653 			for(i=0; emods[k].kexp[i].func!=NULL; i++) {
1654 				_sr_crt_R_KSRMethods[i].mname = emods[k].kexp[0].mname.s;
1655 				_sr_crt_R_KSRMethods[i].fname = emods[k].kexp[i].fname.s;
1656 				_sr_crt_R_KSRMethods[i].func =
1657 					sr_kemi_ruby_export_associate(&emods[k].kexp[i]);
1658 				LM_DBG("exporting KSR.%s.%s(...)\n", rmname,
1659 						emods[k].kexp[i].fname.s);
1660 				if(_sr_crt_R_KSRMethods[i].func == NULL) {
1661 					LM_ERR("failed to associate kemi function with func export\n");
1662 					free(_sr_R_KSRMethods);
1663 					_sr_R_KSRMethods = NULL;
1664 					return 0;
1665 				}
1666 
1667 				rb_define_singleton_method(_ksr_mSMD[m], _sr_crt_R_KSRMethods[i].fname,
1668 						_sr_crt_R_KSRMethods[i].func, -1);
1669 
1670 				n++;
1671 			}
1672 			m++;
1673 			LM_DBG("initialized kemi sub-module: KSR.%s\n", rmname);
1674 		}
1675 	}
1676 	LM_DBG("module 'KSR' has been initialized\n");
1677 
1678 	return 1;
1679 }
1680 
1681 static const char* app_ruby_rpc_reload_doc[2] = {
1682 	"Reload javascript file",
1683 	0
1684 };
1685 
1686 
app_ruby_rpc_reload(rpc_t * rpc,void * ctx)1687 static void app_ruby_rpc_reload(rpc_t* rpc, void* ctx)
1688 {
1689 	int v;
1690 	void *vh;
1691 
1692 	if(_sr_ruby_load_file.s == NULL && _sr_ruby_load_file.len<=0) {
1693 		LM_WARN("script file path not provided\n");
1694 		rpc->fault(ctx, 500, "No script file");
1695 		return;
1696 	}
1697 	if(_sr_ruby_reload_version == NULL) {
1698 		LM_WARN("reload not enabled\n");
1699 		rpc->fault(ctx, 500, "Reload not enabled");
1700 		return;
1701 	}
1702 
1703 	v = *_sr_ruby_reload_version;
1704 	*_sr_ruby_reload_version += 1;
1705 	LM_INFO("marking for reload ruby script file: %.*s (%d / %d => %d)\n",
1706 				_sr_ruby_load_file.len, _sr_ruby_load_file.s,
1707 				_sr_ruby_local_version, v, *_sr_ruby_reload_version);
1708 
1709 	if (rpc->add(ctx, "{", &vh) < 0) {
1710 		rpc->fault(ctx, 500, "Server error");
1711 		return;
1712 	}
1713 	rpc->struct_add(vh, "dd",
1714 			"old", v,
1715 			"new", *_sr_ruby_reload_version);
1716 }
1717 
1718 static const char* app_ruby_rpc_api_list_doc[2] = {
1719 	"List kemi exports to ruby",
1720 	0
1721 };
1722 
app_ruby_rpc_api_list(rpc_t * rpc,void * ctx)1723 static void app_ruby_rpc_api_list(rpc_t* rpc, void* ctx)
1724 {
1725 	int i;
1726 	int n;
1727 	sr_kemi_t *ket;
1728 	void* th;
1729 	void* sh;
1730 	void* ih;
1731 
1732 	if (rpc->add(ctx, "{", &th) < 0) {
1733 		rpc->fault(ctx, 500, "Internal error root reply");
1734 		return;
1735 	}
1736 	n = 0;
1737 	for(i=0; i<SR_KEMI_RUBY_EXPORT_SIZE; i++) {
1738 		ket = sr_kemi_ruby_export_get(i);
1739 		if(ket==NULL) continue;
1740 		n++;
1741 	}
1742 
1743 	if(rpc->struct_add(th, "d[",
1744 				"msize", n,
1745 				"methods",  &ih)<0)
1746 	{
1747 		rpc->fault(ctx, 500, "Internal error array structure");
1748 		return;
1749 	}
1750 	for(i=0; i<SR_KEMI_RUBY_EXPORT_SIZE; i++) {
1751 		ket = sr_kemi_ruby_export_get(i);
1752 		if(ket==NULL) continue;
1753 		if(rpc->struct_add(ih, "{", "func", &sh)<0) {
1754 			rpc->fault(ctx, 500, "Internal error internal structure");
1755 			return;
1756 		}
1757 		if(rpc->struct_add(sh, "SSSS",
1758 				"ret", sr_kemi_param_map_get_name(ket->rtype),
1759 				"module", &ket->mname,
1760 				"name", &ket->fname,
1761 				"params", sr_kemi_param_map_get_params(ket->ptypes))<0) {
1762 			LM_ERR("failed to add the structure with attributes (%d)\n", i);
1763 			rpc->fault(ctx, 500, "Internal error creating dest struct");
1764 			return;
1765 		}
1766 	}
1767 }
1768 
1769 /**
1770  *
1771  */
1772 rpc_export_t app_ruby_rpc_cmds[] = {
1773 	{"app_ruby.reload", app_ruby_rpc_reload,
1774 		app_ruby_rpc_reload_doc, 0},
1775 	{"app_ruby.api_list", app_ruby_rpc_api_list,
1776 		app_ruby_rpc_api_list_doc, 0},
1777 	{0, 0, 0, 0}
1778 };
1779 
1780 /**
1781  *
1782  */
app_ruby_init_rpc(void)1783 int app_ruby_init_rpc(void)
1784 {
1785 	if (rpc_register_array(app_ruby_rpc_cmds)!=0) {
1786 		LM_ERR("failed to register RPC commands\n");
1787 		return -1;
1788 	}
1789 	return 0;
1790 }
1791