Browse code

app_ruby: option to use internal KSR::PV module and skip returning xval str

- controlled via xval_mode module parameter
- workaround for a reported regression causing crash by using core
KSR::PV exports (GH #2180)

(cherry picked from commit 9bafd4c4e09825b25a84bb35a6dc4a39dbd07b73)

Daniel-Constantin Mierla authored on 08/01/2020 19:50:42
Showing 2 changed files
... ...
@@ -41,6 +41,8 @@
41 41
 #undef xmalloc
42 42
 #undef xfree
43 43
 
44
+extern int _ksr_app_ruby_xval_mode;
45
+
44 46
 int app_ruby_kemi_export_libs(void);
45 47
 
46 48
 typedef struct _sr_ruby_env
... ...
@@ -245,6 +247,333 @@ int sr_kemi_ruby_return_int(sr_kemi_t *ket, int rc)
245 247
 	return Qfalse;
246 248
 }
247 249
 
250
+/**
251
+ *
252
+ */
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
+ */
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
+ */
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
+ */
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
+ */
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
+ */
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
+ */
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
+ */
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
+ */
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
+
248 577
 /**
249 578
  *
250 579
  */
... ...
@@ -428,7 +757,12 @@ VALUE sr_kemi_ruby_return_xval(sr_kemi_t *ket, sr_kemi_xval_t *rx)
428 757
 		case SR_KEMIP_INT:
429 758
 			return INT2NUM(rx->v.n);
430 759
 		case SR_KEMIP_STR:
431
-			return rb_str_new(rx->v.s.s, rx->v.s.len);
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
+			}
432 766
 		case SR_KEMIP_BOOL:
433 767
 			if(rx->v.n!=SR_KEMI_FALSE) {
434 768
 				return Qtrue;
... ...
@@ -1274,6 +1608,18 @@ int app_ruby_kemi_export_libs(void)
1274 1608
 
1275 1609
 	m = 0;
1276 1610
 
1611
+	if(_ksr_app_ruby_xval_mode==0) {
1612
+		/* pv submodule */
1613
+		_ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, "PV");
1614
+		for(i=0; _sr_kemi_pv_R_Map[i].fname!=0; i++) {
1615
+			LM_DBG("exporting KSR.PV.%s(...)\n", _sr_kemi_pv_R_Map[i].fname);
1616
+			rb_define_singleton_method(_ksr_mSMD[m], _sr_kemi_pv_R_Map[i].fname,
1617
+					_sr_kemi_pv_R_Map[i].func, -1);
1618
+		}
1619
+		LM_DBG("initialized kemi sub-module: KSR.PV\n");
1620
+		m++;
1621
+	}
1622
+
1277 1623
 	/* x submodule */
1278 1624
 	_ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, "X");
1279 1625
 	for(i=0; _sr_kemi_x_R_Map[i].fname!=0; i++) {
... ...
@@ -1287,6 +1633,11 @@ int app_ruby_kemi_export_libs(void)
1287 1633
 	/* registered kemi modules */
1288 1634
 	if(emods_size>1) {
1289 1635
 		for(k=1; k<emods_size; k++) {
1636
+			if((_ksr_app_ruby_xval_mode==0) && emods[k].kexp[0].mname.len==2
1637
+					&& strncasecmp(emods[k].kexp[0].mname.s, "pv", 2)==0) {
1638
+				LM_DBG("skipping external pv sub-module\n");
1639
+				continue;
1640
+			}
1290 1641
 			n++;
1291 1642
 			_sr_crt_R_KSRMethods = _sr_R_KSRMethods + n;
1292 1643
 			ksr_app_ruby_toupper(emods[k].kexp[0].mname.s, rmname);
... ...
@@ -52,6 +52,7 @@ static int w_app_ruby_run3(sip_msg_t *msg, char *func, char *p1, char *p2,
52 52
 static int fixup_ruby_run(void** param, int param_no);
53 53
 
54 54
 extern str _sr_ruby_load_file;
55
+int _ksr_app_ruby_xval_mode = 0;
55 56
 
56 57
 /* clang-format off */
57 58
 static cmd_export_t cmds[]={
... ...
@@ -69,6 +70,7 @@ static cmd_export_t cmds[]={
69 70
 
70 71
 static param_export_t params[]={
71 72
 	{"load", PARAM_STR, &_sr_ruby_load_file},
73
+	{"xval_mode", PARAM_INT, &_ksr_app_ruby_xval_mode},
72 74
 	{0, 0, 0}
73 75
 };
74 76