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)

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
... ...
@@ -248,6 +250,333 @@ int sr_kemi_ruby_return_int(sr_kemi_t *ket, int rc)
248 248
 /**
249 249
  *
250 250
  */
251
+static VALUE sr_kemi_ruby_return_none(int rmode)
252
+{
253
+	if(rmode==1) {
254
+		return rb_str_new_cstr("<<null>>");
255
+	} else if(rmode==2) {
256
+		return rb_str_new_cstr("");
257
+	}
258
+	return Qnil;
259
+}
260
+
261
+/**
262
+ *
263
+ */
264
+static VALUE app_ruby_pv_get_mode(int argc, VALUE* argv, VALUE self, int rmode)
265
+{
266
+	str pvn;
267
+	pv_spec_t *pvs;
268
+	pv_value_t val;
269
+	sr_ruby_env_t *env_R;
270
+	int pl;
271
+
272
+	env_R = app_ruby_sr_env_get();
273
+
274
+	if(env_R==NULL || env_R->msg==NULL || argc!=1) {
275
+		LM_ERR("invalid ruby environment attributes or parameters\n");
276
+		return sr_kemi_ruby_return_none(rmode);
277
+	}
278
+
279
+	if(!RB_TYPE_P(argv[0], T_STRING)) {
280
+		LM_ERR("invalid parameter type\n");
281
+		return sr_kemi_ruby_return_none(rmode);
282
+	}
283
+
284
+	pvn.s = StringValuePtr(argv[0]);
285
+	if(pvn.s==NULL)
286
+		return sr_kemi_ruby_return_none(rmode);
287
+	pvn.len = strlen(pvn.s);
288
+
289
+	LM_DBG("pv get: %s\n", pvn.s);
290
+	pl = pv_locate_name(&pvn);
291
+	if(pl != pvn.len) {
292
+		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
293
+		return sr_kemi_ruby_return_none(rmode);
294
+	}
295
+	pvs = pv_cache_get(&pvn);
296
+	if(pvs==NULL) {
297
+		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
298
+		return sr_kemi_ruby_return_none(rmode);
299
+	}
300
+	memset(&val, 0, sizeof(pv_value_t));
301
+	if(pv_get_spec_value(env_R->msg, pvs, &val) != 0) {
302
+		LM_ERR("unable to get pv value for [%s]\n", pvn.s);
303
+		return sr_kemi_ruby_return_none(rmode);
304
+	}
305
+	if(val.flags&PV_VAL_NULL) {
306
+		return sr_kemi_ruby_return_none(rmode);
307
+	}
308
+	if(val.flags&PV_TYPE_INT) {
309
+		return INT2NUM(val.ri);
310
+	}
311
+	return rb_str_new(val.rs.s, val.rs.len);
312
+}
313
+
314
+/**
315
+ *
316
+ */
317
+static VALUE app_ruby_pv_get(int argc, VALUE* argv, VALUE self)
318
+{
319
+	return app_ruby_pv_get_mode(argc, argv, self, 0);
320
+}
321
+
322
+/**
323
+ *
324
+ */
325
+static VALUE app_ruby_pv_getw(int argc, VALUE* argv, VALUE self)
326
+{
327
+	return app_ruby_pv_get_mode(argc, argv, self, 1);
328
+}
329
+
330
+/**
331
+ *
332
+ */
333
+static VALUE app_ruby_pv_gete(int argc, VALUE* argv, VALUE self)
334
+{
335
+	return app_ruby_pv_get_mode(argc, argv, self, 2);
336
+}
337
+
338
+/**
339
+ *
340
+ */
341
+static VALUE app_ruby_pv_seti(int argc, VALUE* argv, VALUE self)
342
+{
343
+	str pvn;
344
+	pv_spec_t *pvs;
345
+	pv_value_t val;
346
+	sr_ruby_env_t *env_R;
347
+	int pl;
348
+
349
+	env_R = app_ruby_sr_env_get();
350
+
351
+	if(env_R==NULL || env_R->msg==NULL || argc!=2) {
352
+		LM_ERR("invalid ruby environment attributes or parameters\n");
353
+		return Qfalse;
354
+	}
355
+
356
+	if(!RB_TYPE_P(argv[0], T_STRING)) {
357
+		LM_ERR("invalid pv name parameter type\n");
358
+		return Qfalse;
359
+	}
360
+
361
+	if(!RB_TYPE_P(argv[1], T_FIXNUM)) {
362
+		LM_ERR("invalid pv val parameter type\n");
363
+		return Qfalse;
364
+	}
365
+
366
+	pvn.s = StringValuePtr(argv[0]);
367
+	if(pvn.s==NULL)
368
+		return Qfalse;
369
+	pvn.len = strlen(pvn.s);
370
+
371
+	LM_DBG("pv get: %s\n", pvn.s);
372
+	pl = pv_locate_name(&pvn);
373
+	if(pl != pvn.len) {
374
+		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
375
+		return Qfalse;
376
+	}
377
+	pvs = pv_cache_get(&pvn);
378
+	if(pvs==NULL) {
379
+		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
380
+		return Qfalse;
381
+	}
382
+
383
+	memset(&val, 0, sizeof(pv_value_t));
384
+	val.ri = NUM2INT(argv[1]);
385
+	val.flags |= PV_TYPE_INT|PV_VAL_INT;
386
+
387
+	if(pv_set_spec_value(env_R->msg, pvs, 0, &val)<0) {
388
+		LM_ERR("unable to set pv [%s]\n", pvn.s);
389
+		return Qfalse;
390
+	}
391
+
392
+	return Qtrue;
393
+}
394
+
395
+/**
396
+ *
397
+ */
398
+static VALUE app_ruby_pv_sets(int argc, VALUE* argv, VALUE self)
399
+{
400
+	str pvn;
401
+	pv_spec_t *pvs;
402
+	pv_value_t val;
403
+	sr_ruby_env_t *env_R;
404
+	int pl;
405
+
406
+	env_R = app_ruby_sr_env_get();
407
+
408
+	if(env_R==NULL || env_R->msg==NULL || argc!=2) {
409
+		LM_ERR("invalid ruby environment attributes or parameters\n");
410
+		return Qfalse;
411
+	}
412
+
413
+	if(!RB_TYPE_P(argv[0], T_STRING)) {
414
+		LM_ERR("invalid pv name parameter type\n");
415
+		return Qfalse;
416
+	}
417
+
418
+	if(!RB_TYPE_P(argv[1], T_STRING)) {
419
+		LM_ERR("invalid pv val parameter type\n");
420
+		return Qfalse;
421
+	}
422
+
423
+	pvn.s = StringValuePtr(argv[0]);
424
+	if(pvn.s==NULL)
425
+		return Qfalse;
426
+	pvn.len = strlen(pvn.s);
427
+
428
+	LM_DBG("pv get: %s\n", pvn.s);
429
+	pl = pv_locate_name(&pvn);
430
+	if(pl != pvn.len) {
431
+		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
432
+		return Qfalse;
433
+	}
434
+	pvs = pv_cache_get(&pvn);
435
+	if(pvs==NULL) {
436
+		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
437
+		return Qfalse;
438
+	}
439
+
440
+	memset(&val, 0, sizeof(pv_value_t));
441
+	val.rs.s = StringValuePtr(argv[1]);
442
+	if(val.rs.s==NULL) {
443
+		LM_ERR("invalid str value\n");
444
+		return Qfalse;
445
+	}
446
+	val.rs.len = strlen(val.rs.s);
447
+	val.flags |= PV_VAL_STR;
448
+
449
+	if(pv_set_spec_value(env_R->msg, pvs, 0, &val)<0) {
450
+		LM_ERR("unable to set pv [%s]\n", pvn.s);
451
+		return Qfalse;
452
+	}
453
+
454
+	return Qtrue;
455
+}
456
+
457
+/**
458
+ *
459
+ */
460
+static VALUE app_ruby_pv_unset(int argc, VALUE* argv, VALUE self)
461
+{
462
+	str pvn;
463
+	pv_spec_t *pvs;
464
+	pv_value_t val;
465
+	sr_ruby_env_t *env_R;
466
+	int pl;
467
+
468
+	env_R = app_ruby_sr_env_get();
469
+
470
+	if(env_R==NULL || env_R->msg==NULL || argc!=1) {
471
+		LM_ERR("invalid ruby environment attributes or parameters\n");
472
+		return Qfalse;
473
+	}
474
+
475
+	if(!RB_TYPE_P(argv[0], T_STRING)) {
476
+		LM_ERR("invalid parameter type\n");
477
+		return Qfalse;
478
+	}
479
+
480
+	pvn.s = StringValuePtr(argv[0]);
481
+	if(pvn.s==NULL)
482
+		return Qfalse;
483
+	pvn.len = strlen(pvn.s);
484
+
485
+	LM_DBG("pv get: %s\n", pvn.s);
486
+	pl = pv_locate_name(&pvn);
487
+	if(pl != pvn.len) {
488
+		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
489
+		return Qfalse;
490
+	}
491
+	pvs = pv_cache_get(&pvn);
492
+	if(pvs==NULL) {
493
+		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
494
+		return Qfalse;
495
+	}
496
+
497
+	memset(&val, 0, sizeof(pv_value_t));
498
+	val.flags |= PV_VAL_NULL;
499
+	if(pv_set_spec_value(env_R->msg, pvs, 0, &val)<0)
500
+	{
501
+		LM_ERR("unable to unset pv [%s]\n", pvn.s);
502
+		return Qfalse;
503
+	}
504
+
505
+	return Qtrue;
506
+}
507
+
508
+/**
509
+ *
510
+ */
511
+static VALUE app_ruby_pv_is_null(int argc, VALUE* argv, VALUE self)
512
+{
513
+	str pvn;
514
+	pv_spec_t *pvs;
515
+	pv_value_t val;
516
+	sr_ruby_env_t *env_R;
517
+	int pl;
518
+
519
+	env_R = app_ruby_sr_env_get();
520
+
521
+	if(env_R==NULL || env_R->msg==NULL || argc!=1) {
522
+		LM_ERR("invalid ruby environment attributes or parameters\n");
523
+		return Qfalse;
524
+	}
525
+
526
+	if(!RB_TYPE_P(argv[0], T_STRING)) {
527
+		LM_ERR("invalid parameter type\n");
528
+		return Qfalse;
529
+	}
530
+
531
+	pvn.s = StringValuePtr(argv[0]);
532
+	if(pvn.s==NULL)
533
+		return Qfalse;
534
+	pvn.len = strlen(pvn.s);
535
+
536
+	LM_DBG("pv get: %s\n", pvn.s);
537
+	pl = pv_locate_name(&pvn);
538
+	if(pl != pvn.len) {
539
+		LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
540
+		return Qfalse;
541
+	}
542
+	pvs = pv_cache_get(&pvn);
543
+	if(pvs==NULL) {
544
+		LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
545
+		return Qfalse;
546
+	}
547
+
548
+	memset(&val, 0, sizeof(pv_value_t));
549
+	if(pv_get_spec_value(env_R->msg, pvs, &val) != 0) {
550
+		LM_NOTICE("unable to get pv value for [%s]\n", pvn.s);
551
+		return Qtrue;
552
+	}
553
+	if(val.flags&PV_VAL_NULL) {
554
+		return Qtrue;
555
+	} else {
556
+		pv_value_destroy(&val);
557
+		return Qfalse;
558
+	}
559
+}
560
+
561
+/**
562
+ *
563
+ */
564
+static ksr_ruby_export_t _sr_kemi_pv_R_Map[] = {
565
+	{"PV", "get", app_ruby_pv_get},
566
+	{"PV", "getw", app_ruby_pv_getw},
567
+	{"PV", "gete", app_ruby_pv_gete},
568
+	{"PV", "seti", app_ruby_pv_seti},
569
+	{"PV", "sets", app_ruby_pv_sets},
570
+	{"PV", "unset", app_ruby_pv_unset},
571
+	{"PV", "is_null", app_ruby_pv_is_null},
572
+	{0, 0, 0}
573
+};
574
+
575
+/**
576
+ *
577
+ */
251 578
 static VALUE app_ruby_sr_modf(int argc, VALUE* argv, VALUE self)
252 579
 {
253 580
 	int ret;
... ...
@@ -428,7 +757,12 @@ VALUE sr_kemi_ruby_return_xval(sr_kemi_t *ket, sr_kemi_xval_t *rx)
428 428
 		case SR_KEMIP_INT:
429 429
 			return INT2NUM(rx->v.n);
430 430
 		case SR_KEMIP_STR:
431
-			return rb_str_new(rx->v.s.s, rx->v.s.len);
431
+			if(_ksr_app_ruby_xval_mode==0) {
432
+				LM_ERR("attempt to return xval str - support disabled - returning null\n");
433
+				return Qnil;
434
+			} else {
435
+				return rb_str_new(rx->v.s.s, rx->v.s.len);
436
+			}
432 437
 		case SR_KEMIP_BOOL:
433 438
 			if(rx->v.n!=SR_KEMI_FALSE) {
434 439
 				return Qtrue;
... ...
@@ -1274,6 +1608,18 @@ int app_ruby_kemi_export_libs(void)
1274 1274
 
1275 1275
 	m = 0;
1276 1276
 
1277
+	if(_ksr_app_ruby_xval_mode==0) {
1278
+		/* pv submodule */
1279
+		_ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, "PV");
1280
+		for(i=0; _sr_kemi_pv_R_Map[i].fname!=0; i++) {
1281
+			LM_DBG("exporting KSR.PV.%s(...)\n", _sr_kemi_pv_R_Map[i].fname);
1282
+			rb_define_singleton_method(_ksr_mSMD[m], _sr_kemi_pv_R_Map[i].fname,
1283
+					_sr_kemi_pv_R_Map[i].func, -1);
1284
+		}
1285
+		LM_DBG("initialized kemi sub-module: KSR.PV\n");
1286
+		m++;
1287
+	}
1288
+
1277 1289
 	/* x submodule */
1278 1290
 	_ksr_mSMD[m] = rb_define_module_under(_ksr_mKSR, "X");
1279 1291
 	for(i=0; _sr_kemi_x_R_Map[i].fname!=0; i++) {
... ...
@@ -1287,6 +1633,11 @@ int app_ruby_kemi_export_libs(void)
1287 1287
 	/* registered kemi modules */
1288 1288
 	if(emods_size>1) {
1289 1289
 		for(k=1; k<emods_size; k++) {
1290
+			if((_ksr_app_ruby_xval_mode==0) && emods[k].kexp[0].mname.len==2
1291
+					&& strncasecmp(emods[k].kexp[0].mname.s, "pv", 2)==0) {
1292
+				LM_DBG("skipping external pv sub-module\n");
1293
+				continue;
1294
+			}
1290 1295
 			n++;
1291 1296
 			_sr_crt_R_KSRMethods = _sr_R_KSRMethods + n;
1292 1297
 			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 69
 
70 70
 static param_export_t params[]={
71 71
 	{"load", PARAM_STR, &_sr_ruby_load_file},
72
+	{"xval_mode", PARAM_INT, &_ksr_app_ruby_xval_mode},
72 73
 	{0, 0, 0}
73 74
 };
74 75