瀏覽代碼

rtpengine: added rtpengine_query_v()

- do a query cmd and store the response in a variable as a json
Daniel-Constantin Mierla 4 年之前
父節點
當前提交
697f34d484
共有 2 個文件被更改,包括 278 次插入0 次删除
  1. 30 0
      src/modules/rtpengine/doc/rtpengine_admin.xml
  2. 248 0
      src/modules/rtpengine/rtpengine.c

+ 30 - 0
src/modules/rtpengine/doc/rtpengine_admin.xml

@@ -2789,6 +2789,36 @@ rtpengine_delete();
 ...
 rtpengine_query();
 ...
+</programlisting>
+		</example>
+	</section>
+	<section id="rtpengine.f.rtpengine_query_v">
+		<title>
+		<function moreinfo="none">rtpengine_query_v(fmt, var)</function>
+		</title>
+		<para>
+		Queries the &rtp; proxy about the current status and statistics of a running
+		call, converts the response to JSON according to fmt and sets the variable
+		var with the result.
+		</para>
+		<para>
+		The fmt parameter can be 'j' for compacted JSON and 'jp' for pretty-formatted
+		JSON.
+		</para>
+		<para>
+		The var parameter has to be the name of a writable variable.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>rtpengine_query_v</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(rtpengine_query_v("j", "$var(rdata)")) {
+    xinfo("rtpengine query response: $var(rdata)\n");
+}
+...
 </programlisting>
 		</example>
 	</section>

+ 248 - 0
src/modules/rtpengine/rtpengine.c

@@ -78,6 +78,7 @@
 #include "../../core/rpc_lookup.h"
 #include "../../core/kemi.h"
 #include "../../core/char_msg_val.h"
+#include "../../core/utils/srjson.h"
 #include "../../modules/tm/tm_load.h"
 #include "../../modules/crypto/api.h"
 #include "../../modules/lwsc/api.h"
@@ -216,6 +217,10 @@ static int rtpengine_manage1_f(struct sip_msg *, char *, char *);
 static int rtpengine_query1_f(struct sip_msg *, char *, char *);
 static int rtpengine_info1_f(struct sip_msg *, char *, char *);
 
+static int w_rtpengine_query_v(sip_msg_t *msg, char *pfmt, char *pvar);
+static int fixup_rtpengine_query_v(void **param, int param_no);
+static int fixup_free_rtpengine_query_v(void **param, int param_no);
+
 static int parse_flags(struct ng_flags_parse *, struct sip_msg *, enum rtpe_operation *, const char *);
 
 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[] = {
 	{"rtpengine_query",	(cmd_function)rtpengine_query1_f,	1,
 		fixup_spve_null, 0,
 		ANY_ROUTE},
+	{"rtpengine_query_v",	(cmd_function)w_rtpengine_query_v,	2,
+		fixup_rtpengine_query_v, fixup_free_rtpengine_query_v,
+		ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -4165,6 +4173,241 @@ pv_get_rtpestat_f(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 	return rtpengine_rtpp_set_wrap(msg, rtpengine_rtpstat_wrap, parms, 1, OP_ANY);
 }
 
+/**
+ *
+ */
+static srjson_t *rtpengine_query_v_build_json(srjson_doc_t *jdoc,
+		bencode_item_t *dict)
+{
+	srjson_t *vnode;
+	srjson_t *tnode;
+	bencode_item_t *it;
+	str sval;
+
+	if(jdoc==NULL || dict==NULL) {
+		LM_ERR("invalid parameters\n");
+		return NULL;
+	}
+
+	switch (dict->type) {
+		case BENCODE_STRING:
+			return srjson_CreateStr(jdoc, dict->iov[1].iov_base, dict->iov[1].iov_len);
+
+		case BENCODE_INTEGER:
+			return srjson_CreateNumber(jdoc, dict->value);
+
+		case BENCODE_LIST:
+			vnode = srjson_CreateArray(jdoc);
+			if(vnode==NULL) {
+				LM_ERR("failed to create the array node\n");
+				return NULL;
+			}
+			for (it = dict->child; it; it = it->sibling) {
+				tnode = rtpengine_query_v_build_json(jdoc, it);
+				if (!tnode) {
+					srjson_Delete(jdoc, vnode);
+					return NULL;
+				}
+				srjson_AddItemToArray(jdoc, vnode, tnode);
+			}
+			return vnode;
+
+		case BENCODE_DICTIONARY:
+			vnode = srjson_CreateObject(jdoc);
+			if(vnode==NULL) {
+				LM_ERR("failed to create the object node\n");
+				return NULL;
+			}
+			for (it = dict->child; it; it = it->sibling) {
+				/* name of the item */
+				sval.s = it->iov[1].iov_base;
+				sval.len = it->iov[1].iov_len;
+				/* value of the item */
+				it = it->sibling;
+				tnode = rtpengine_query_v_build_json(jdoc, it);
+				if (!tnode) {
+					srjson_Delete(jdoc, vnode);
+					return NULL;
+				}
+				srjson_AddStrItemToObject(jdoc, vnode, sval.s, sval.len, tnode);
+			}
+			return vnode;
+
+		default:
+			LM_ERR("unsupported bencode item type %d\n", dict->type);
+			return NULL;
+	}
+}
+
+/**
+ *
+ */
+static int rtpengine_query_v_print(bencode_item_t *dict, str *fmt,
+		str *bout)
+{
+	srjson_doc_t jdoc;
+
+	if(fmt==NULL || fmt->s==NULL || fmt->len<=0) {
+		LM_ERR("invalid format parameter\n");
+		return -1;
+	}
+	if(fmt->s[0]!='j' && fmt->s[0]!='J') {
+		LM_ERR("invalid format parameter value: %.*s\n", fmt->len, fmt->s);
+		return -1;
+	}
+
+	srjson_InitDoc(&jdoc, NULL);
+	jdoc.root = rtpengine_query_v_build_json(&jdoc, dict);
+
+	if(jdoc.root==NULL) {
+		LM_ERR("failed to build json document\n");
+		return -1;
+	}
+
+	if(fmt->len>1 && (fmt->s[1]=='p' || fmt->s[1]=='P')) {
+		bout->s = srjson_Print(&jdoc, jdoc.root);
+	} else {
+		bout->s = srjson_PrintUnformatted(&jdoc, jdoc.root);
+	}
+	if(bout->s==NULL) {
+		LM_ERR("unable to serialize json document\n");
+		srjson_DestroyDoc(&jdoc);
+		return -1;
+	}
+	bout->len = strlen(bout->s);
+	srjson_DestroyDoc(&jdoc);
+
+	return 0;
+}
+
+/**
+ *
+ */
+static int rtpengine_query_v_wrap(struct sip_msg *msg, void *d, int more,
+		enum rtpe_operation op)
+{
+	void **parms;
+	str *fmt = NULL;
+	pv_spec_t *dst = NULL;
+	pv_value_t val = {0};
+	bencode_buffer_t bencbuf;
+	bencode_item_t *dict;
+
+	parms = d;
+	fmt = parms[0];
+	dst = parms[1];
+
+	dict = rtpp_function_call_ok(&bencbuf, msg, OP_QUERY, NULL, NULL);
+	if (!dict) {
+		return -1;
+	}
+	if(rtpengine_query_v_print(dict, fmt, &val.rs)<0) {
+		goto error;
+	}
+
+	val.flags = PV_VAL_STR;
+	if(dst->setf) {
+		dst->setf(msg, &dst->pvp, (int)EQ_T, &val);
+	} else {
+		LM_WARN("target pv is not writable\n");
+	}
+
+	/* val.rs.s is allocated by srjson print */
+	free(val.rs.s);
+
+	bencode_buffer_free(&bencbuf);
+	return 1;
+
+error:
+	bencode_buffer_free(&bencbuf);
+	return -1;
+}
+
+/**
+ *
+ */
+static int ki_rtpengine_query_v(sip_msg_t *msg, str *fmt, str *dpv)
+{
+	void *parms[2];
+	pv_spec_t *dst;
+
+	dst = pv_cache_get(dpv);
+	if(dst==NULL) {
+		LM_ERR("failed to get pv spec for: %.*s\n", dpv->len, dpv->s);
+		return -1;
+	}
+	if(dst->setf==NULL) {
+		LM_ERR("target pv is not writable: %.*s\n", dpv->len, dpv->s);
+		return -1;
+	}
+	parms[0] = fmt;
+	parms[1] = dst;
+	return rtpengine_rtpp_set_wrap(msg, rtpengine_query_v_wrap, parms, 1, OP_ANY);
+}
+
+/*
+ * Store the cmd QUERY result to variable
+ */
+static int w_rtpengine_query_v(sip_msg_t *msg, char *pfmt, char *pvar)
+{
+	void *parms[2];
+	str fmt = {NULL, 0};
+	pv_spec_t *dst;
+
+	if(fixup_get_svalue(msg, (gparam_t*)pfmt, &fmt) < 0 || fmt.len <= 0) {
+		LM_ERR("fmt has no value\n");
+		return -1;
+	}
+	dst = (pv_spec_t *)pvar;
+
+	parms[0] = &fmt;
+	parms[1] = dst;
+
+	return rtpengine_rtpp_set_wrap(msg, rtpengine_query_v_wrap, parms, 1, OP_ANY);
+}
+
+/**
+ *
+ */
+static int fixup_rtpengine_query_v(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_spve_null(param, 1);
+	}
+
+	if(param_no == 2) {
+		if(fixup_pvar_null(param, 1) != 0) {
+			LM_ERR("failed to fixup result pvar\n");
+			return -1;
+		}
+		if(((pv_spec_t *)(*param))->setf == NULL) {
+			LM_ERR("result pvar is not writeble\n");
+			return -1;
+		}
+		return 0;
+	}
+
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/**
+ *
+ */
+static int fixup_free_rtpengine_query_v(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_free_spve_null(param, 1);
+	}
+
+	if(param_no == 2) {
+		return fixup_free_pvar_null(param, 1);
+	}
+
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
 static int
 set_rtp_inst_pvar(struct sip_msg *msg, const str * const uri) {
 	pv_value_t val;
@@ -4529,6 +4772,11 @@ static sr_kemi_t sr_kemi_rtpengine_exports[] = {
         { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
             SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
     },
+   { str_init("rtpengine"), str_init("rtpengine_query_v"),
+        SR_KEMIP_INT, ki_rtpengine_query_v,
+        { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+            SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+    },
 
     { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };