Browse code

rtpengine: added rtpengine_query_v()

- do a query cmd and store the response in a variable as a json

Daniel-Constantin Mierla authored on 27/08/2021 16:28:12
Showing 2 changed files
... ...
@@ -2789,6 +2789,36 @@ rtpengine_delete();
2789 2789
 ...
2790 2790
 rtpengine_query();
2791 2791
 ...
2792
+</programlisting>
2793
+		</example>
2794
+	</section>
2795
+	<section id="rtpengine.f.rtpengine_query_v">
2796
+		<title>
2797
+		<function moreinfo="none">rtpengine_query_v(fmt, var)</function>
2798
+		</title>
2799
+		<para>
2800
+		Queries the &rtp; proxy about the current status and statistics of a running
2801
+		call, converts the response to JSON according to fmt and sets the variable
2802
+		var with the result.
2803
+		</para>
2804
+		<para>
2805
+		The fmt parameter can be 'j' for compacted JSON and 'jp' for pretty-formatted
2806
+		JSON.
2807
+		</para>
2808
+		<para>
2809
+		The var parameter has to be the name of a writable variable.
2810
+		</para>
2811
+		<para>
2812
+		This function can be used from ANY_ROUTE.
2813
+		</para>
2814
+		<example>
2815
+		<title><function>rtpengine_query_v</function> usage</title>
2816
+		<programlisting format="linespecific">
2817
+...
2818
+if(rtpengine_query_v("j", "$var(rdata)")) {
2819
+    xinfo("rtpengine query response: $var(rdata)\n");
2820
+}
2821
+...
2792 2822
 </programlisting>
2793 2823
 		</example>
2794 2824
 	</section>
... ...
@@ -78,6 +78,7 @@
78 78
 #include "../../core/rpc_lookup.h"
79 79
 #include "../../core/kemi.h"
80 80
 #include "../../core/char_msg_val.h"
81
+#include "../../core/utils/srjson.h"
81 82
 #include "../../modules/tm/tm_load.h"
82 83
 #include "../../modules/crypto/api.h"
83 84
 #include "../../modules/lwsc/api.h"
... ...
@@ -216,6 +217,10 @@ static int rtpengine_manage1_f(struct sip_msg *, char *, char *);
216 217
 static int rtpengine_query1_f(struct sip_msg *, char *, char *);
217 218
 static int rtpengine_info1_f(struct sip_msg *, char *, char *);
218 219
 
220
+static int w_rtpengine_query_v(sip_msg_t *msg, char *pfmt, char *pvar);
221
+static int fixup_rtpengine_query_v(void **param, int param_no);
222
+static int fixup_free_rtpengine_query_v(void **param, int param_no);
223
+
219 224
 static int parse_flags(struct ng_flags_parse *, struct sip_msg *, enum rtpe_operation *, const char *);
220 225
 
221 226
 static int rtpengine_offer_answer(struct sip_msg *msg, const char *flags, enum rtpe_operation op, int more);
... ...
@@ -443,6 +448,9 @@ static cmd_export_t cmds[] = {
443 448
 	{"rtpengine_query",	(cmd_function)rtpengine_query1_f,	1,
444 449
 		fixup_spve_null, 0,
445 450
 		ANY_ROUTE},
451
+	{"rtpengine_query_v",	(cmd_function)w_rtpengine_query_v,	2,
452
+		fixup_rtpengine_query_v, fixup_free_rtpengine_query_v,
453
+		ANY_ROUTE},
446 454
 	{0, 0, 0, 0, 0, 0}
447 455
 };
448 456
 
... ...
@@ -4165,6 +4173,241 @@ pv_get_rtpestat_f(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
4165 4173
 	return rtpengine_rtpp_set_wrap(msg, rtpengine_rtpstat_wrap, parms, 1, OP_ANY);
4166 4174
 }
4167 4175
 
4176
+/**
4177
+ *
4178
+ */
4179
+static srjson_t *rtpengine_query_v_build_json(srjson_doc_t *jdoc,
4180
+		bencode_item_t *dict)
4181
+{
4182
+	srjson_t *vnode;
4183
+	srjson_t *tnode;
4184
+	bencode_item_t *it;
4185
+	str sval;
4186
+
4187
+	if(jdoc==NULL || dict==NULL) {
4188
+		LM_ERR("invalid parameters\n");
4189
+		return NULL;
4190
+	}
4191
+
4192
+	switch (dict->type) {
4193
+		case BENCODE_STRING:
4194
+			return srjson_CreateStr(jdoc, dict->iov[1].iov_base, dict->iov[1].iov_len);
4195
+
4196
+		case BENCODE_INTEGER:
4197
+			return srjson_CreateNumber(jdoc, dict->value);
4198
+
4199
+		case BENCODE_LIST:
4200
+			vnode = srjson_CreateArray(jdoc);
4201
+			if(vnode==NULL) {
4202
+				LM_ERR("failed to create the array node\n");
4203
+				return NULL;
4204
+			}
4205
+			for (it = dict->child; it; it = it->sibling) {
4206
+				tnode = rtpengine_query_v_build_json(jdoc, it);
4207
+				if (!tnode) {
4208
+					srjson_Delete(jdoc, vnode);
4209
+					return NULL;
4210
+				}
4211
+				srjson_AddItemToArray(jdoc, vnode, tnode);
4212
+			}
4213
+			return vnode;
4214
+
4215
+		case BENCODE_DICTIONARY:
4216
+			vnode = srjson_CreateObject(jdoc);
4217
+			if(vnode==NULL) {
4218
+				LM_ERR("failed to create the object node\n");
4219
+				return NULL;
4220
+			}
4221
+			for (it = dict->child; it; it = it->sibling) {
4222
+				/* name of the item */
4223
+				sval.s = it->iov[1].iov_base;
4224
+				sval.len = it->iov[1].iov_len;
4225
+				/* value of the item */
4226
+				it = it->sibling;
4227
+				tnode = rtpengine_query_v_build_json(jdoc, it);
4228
+				if (!tnode) {
4229
+					srjson_Delete(jdoc, vnode);
4230
+					return NULL;
4231
+				}
4232
+				srjson_AddStrItemToObject(jdoc, vnode, sval.s, sval.len, tnode);
4233
+			}
4234
+			return vnode;
4235
+
4236
+		default:
4237
+			LM_ERR("unsupported bencode item type %d\n", dict->type);
4238
+			return NULL;
4239
+	}
4240
+}
4241
+
4242
+/**
4243
+ *
4244
+ */
4245
+static int rtpengine_query_v_print(bencode_item_t *dict, str *fmt,
4246
+		str *bout)
4247
+{
4248
+	srjson_doc_t jdoc;
4249
+
4250
+	if(fmt==NULL || fmt->s==NULL || fmt->len<=0) {
4251
+		LM_ERR("invalid format parameter\n");
4252
+		return -1;
4253
+	}
4254
+	if(fmt->s[0]!='j' && fmt->s[0]!='J') {
4255
+		LM_ERR("invalid format parameter value: %.*s\n", fmt->len, fmt->s);
4256
+		return -1;
4257
+	}
4258
+
4259
+	srjson_InitDoc(&jdoc, NULL);
4260
+	jdoc.root = rtpengine_query_v_build_json(&jdoc, dict);
4261
+
4262
+	if(jdoc.root==NULL) {
4263
+		LM_ERR("failed to build json document\n");
4264
+		return -1;
4265
+	}
4266
+
4267
+	if(fmt->len>1 && (fmt->s[1]=='p' || fmt->s[1]=='P')) {
4268
+		bout->s = srjson_Print(&jdoc, jdoc.root);
4269
+	} else {
4270
+		bout->s = srjson_PrintUnformatted(&jdoc, jdoc.root);
4271
+	}
4272
+	if(bout->s==NULL) {
4273
+		LM_ERR("unable to serialize json document\n");
4274
+		srjson_DestroyDoc(&jdoc);
4275
+		return -1;
4276
+	}
4277
+	bout->len = strlen(bout->s);
4278
+	srjson_DestroyDoc(&jdoc);
4279
+
4280
+	return 0;
4281
+}
4282
+
4283
+/**
4284
+ *
4285
+ */
4286
+static int rtpengine_query_v_wrap(struct sip_msg *msg, void *d, int more,
4287
+		enum rtpe_operation op)
4288
+{
4289
+	void **parms;
4290
+	str *fmt = NULL;
4291
+	pv_spec_t *dst = NULL;
4292
+	pv_value_t val = {0};
4293
+	bencode_buffer_t bencbuf;
4294
+	bencode_item_t *dict;
4295
+
4296
+	parms = d;
4297
+	fmt = parms[0];
4298
+	dst = parms[1];
4299
+
4300
+	dict = rtpp_function_call_ok(&bencbuf, msg, OP_QUERY, NULL, NULL);
4301
+	if (!dict) {
4302
+		return -1;
4303
+	}
4304
+	if(rtpengine_query_v_print(dict, fmt, &val.rs)<0) {
4305
+		goto error;
4306
+	}
4307
+
4308
+	val.flags = PV_VAL_STR;
4309
+	if(dst->setf) {
4310
+		dst->setf(msg, &dst->pvp, (int)EQ_T, &val);
4311
+	} else {
4312
+		LM_WARN("target pv is not writable\n");
4313
+	}
4314
+
4315
+	/* val.rs.s is allocated by srjson print */
4316
+	free(val.rs.s);
4317
+
4318
+	bencode_buffer_free(&bencbuf);
4319
+	return 1;
4320
+
4321
+error:
4322
+	bencode_buffer_free(&bencbuf);
4323
+	return -1;
4324
+}
4325
+
4326
+/**
4327
+ *
4328
+ */
4329
+static int ki_rtpengine_query_v(sip_msg_t *msg, str *fmt, str *dpv)
4330
+{
4331
+	void *parms[2];
4332
+	pv_spec_t *dst;
4333
+
4334
+	dst = pv_cache_get(dpv);
4335
+	if(dst==NULL) {
4336
+		LM_ERR("failed to get pv spec for: %.*s\n", dpv->len, dpv->s);
4337
+		return -1;
4338
+	}
4339
+	if(dst->setf==NULL) {
4340
+		LM_ERR("target pv is not writable: %.*s\n", dpv->len, dpv->s);
4341
+		return -1;
4342
+	}
4343
+	parms[0] = fmt;
4344
+	parms[1] = dst;
4345
+	return rtpengine_rtpp_set_wrap(msg, rtpengine_query_v_wrap, parms, 1, OP_ANY);
4346
+}
4347
+
4348
+/*
4349
+ * Store the cmd QUERY result to variable
4350
+ */
4351
+static int w_rtpengine_query_v(sip_msg_t *msg, char *pfmt, char *pvar)
4352
+{
4353
+	void *parms[2];
4354
+	str fmt = {NULL, 0};
4355
+	pv_spec_t *dst;
4356
+
4357
+	if(fixup_get_svalue(msg, (gparam_t*)pfmt, &fmt) < 0 || fmt.len <= 0) {
4358
+		LM_ERR("fmt has no value\n");
4359
+		return -1;
4360
+	}
4361
+	dst = (pv_spec_t *)pvar;
4362
+
4363
+	parms[0] = &fmt;
4364
+	parms[1] = dst;
4365
+
4366
+	return rtpengine_rtpp_set_wrap(msg, rtpengine_query_v_wrap, parms, 1, OP_ANY);
4367
+}
4368
+
4369
+/**
4370
+ *
4371
+ */
4372
+static int fixup_rtpengine_query_v(void **param, int param_no)
4373
+{
4374
+	if(param_no == 1) {
4375
+		return fixup_spve_null(param, 1);
4376
+	}
4377
+
4378
+	if(param_no == 2) {
4379
+		if(fixup_pvar_null(param, 1) != 0) {
4380
+			LM_ERR("failed to fixup result pvar\n");
4381
+			return -1;
4382
+		}
4383
+		if(((pv_spec_t *)(*param))->setf == NULL) {
4384
+			LM_ERR("result pvar is not writeble\n");
4385
+			return -1;
4386
+		}
4387
+		return 0;
4388
+	}
4389
+
4390
+	LM_ERR("invalid parameter number <%d>\n", param_no);
4391
+	return -1;
4392
+}
4393
+
4394
+/**
4395
+ *
4396
+ */
4397
+static int fixup_free_rtpengine_query_v(void **param, int param_no)
4398
+{
4399
+	if(param_no == 1) {
4400
+		return fixup_free_spve_null(param, 1);
4401
+	}
4402
+
4403
+	if(param_no == 2) {
4404
+		return fixup_free_pvar_null(param, 1);
4405
+	}
4406
+
4407
+	LM_ERR("invalid parameter number <%d>\n", param_no);
4408
+	return -1;
4409
+}
4410
+
4168 4411
 static int
4169 4412
 set_rtp_inst_pvar(struct sip_msg *msg, const str * const uri) {
4170 4413
 	pv_value_t val;
... ...
@@ -4529,6 +4772,11 @@ static sr_kemi_t sr_kemi_rtpengine_exports[] = {
4529 4772
         { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
4530 4773
             SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
4531 4774
     },
4775
+   { str_init("rtpengine"), str_init("rtpengine_query_v"),
4776
+        SR_KEMIP_INT, ki_rtpengine_query_v,
4777
+        { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
4778
+            SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
4779
+    },
4532 4780
 
4533 4781
     { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
4534 4782
 };