Przeglądaj źródła

rtjson: new module facilitating routing based on json documents

- routing attributes such as r-uri, outbound proxy, etc. can be read from a
  json document. Retrieving the document can be done with other modules
  such as evapi, utils (http query), a.s.o.
Daniel-Constantin Mierla 10 lat temu
rodzic
commit
09e5b31a39

+ 15 - 0
modules/rtjson/Makefile

@@ -0,0 +1,15 @@
+# 
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=rtjson.so
+DEFS +=
+LIBS +=
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
+
+include ../../Makefile.modules

+ 182 - 0
modules/rtjson/README

@@ -0,0 +1,182 @@
+RTJSON Module
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2015 asipto.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. xavp_cfg (str)
+
+        4. Functions
+
+              4.1. rtjson_init_routes(rtdoc)
+              4.2. rtjson_push_routes()
+              4.3. rtjson_next_route()
+              4.4. rtjson_update_branch()
+
+        5. JSON Routing Structure
+
+   List of Examples
+
+   1.1. Set xavp_cfg parameter
+   1.2. rtjson_init_routes usage
+   1.3. rtjson_push_routes usage
+   1.4. rtjson_next_route usage
+   1.5. rtjson_update_branch usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. xavp_cfg (str)
+
+   4. Functions
+
+        4.1. rtjson_init_routes(rtdoc)
+        4.2. rtjson_push_routes()
+        4.3. rtjson_next_route()
+        4.4. rtjson_update_branch()
+
+   5. JSON Routing Structure
+
+1. Overview
+
+   This module facilitates SIP routing based on JSON specifications.
+
+   The values for R-URI ($ru), outbound proxy ($du) and other attributes
+   used for SIP routing can be retrieved in a JSON document. It is able to
+   process attributes for more than one destination and prepare for
+   routing in serial or parallel fashion.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * tm - (optional) transaction management.
+       uac - (optional) user agent operations.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None
+
+3. Parameters
+
+   3.1. xavp_cfg (str)
+
+3.1. xavp_cfg (str)
+
+   The name of the xavp to be used internally by the module.
+
+   Default value is "rtjson".
+
+   Example 1.1. Set xavp_cfg parameter
+...
+modparam("rtjson", "xavp_cfg", "myxavp")
+...
+
+4. Functions
+
+   4.1. rtjson_init_routes(rtdoc)
+   4.2. rtjson_push_routes()
+   4.3. rtjson_next_route()
+   4.4. rtjson_update_branch()
+
+4.1. rtjson_init_routes(rtdoc)
+
+   Initialize routing based on JSON document stored in rtdoc parameter.
+
+   The rtdoc parameter can be a static string or a dynamic string value
+   with config variables. It has to result in a valid JSON document with
+   the structure specified in chapter 'JSON Routing Structure'.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.2. rtjson_init_routes usage
+...
+rtjson_init_routes("$var(json)");
+...
+
+4.2. rtjson_push_routes()
+
+   Push the routes given in JSON document to rtjson_init_routes(rtdoc) to
+   the internal fields used by Kamailio for routing.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.3. rtjson_push_routes usage
+...
+rtjson_init_routes("$var(json)");
+rtjson_push_routes();
+...
+
+4.3. rtjson_next_route()
+
+   To be used in failure_route for serial forking, to push the next route
+   to the internal fields used by Kamailio for routing.
+
+   This function can be used from FAILURE_ROUTE.
+
+   Example 1.4. rtjson_next_route usage
+...
+rtjson_init_routes("$var(json)");
+rtjson_push_routes();
+...
+failure_route[REROUTE] {
+        rtjson_next_route();
+}
+...
+
+4.4. rtjson_update_branch()
+
+   To be used in branch_route if the JSON document had attributes that
+   needs to be set for each branch.
+
+   This function can be used from BRANCH_ROUTE.
+
+   Example 1.5. rtjson_update_branch usage
+...
+rtjson_init_routes("$var(json)");
+rtjson_push_routes();
+...
+branch_route[OUTGOING] {
+        rtjson_update_branch();
+}
+...
+
+5. JSON Routing Structure
+
+   TBA.

+ 4 - 0
modules/rtjson/doc/Makefile

@@ -0,0 +1,4 @@
+docs = rtjson.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 37 - 0
modules/rtjson/doc/rtjson.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>RTJSON Module</title>
+	<productname class="trade">kamailio.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2015</year>
+	    <holder>asipto.com</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="rtjson_admin.xml"/>
+    
+    
+</book>

+ 195 - 0
modules/rtjson/doc/rtjson_admin.xml

@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		This module facilitates SIP routing based on JSON specifications.
+	</para>
+	<para>
+		The values for R-URI ($ru), outbound proxy ($du) and other attributes
+		used for SIP routing can be retrieved in a JSON document. It is able
+		to process attributes for more than one destination and prepare for
+		routing in serial or parallel fashion.
+	</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>tm</emphasis> - (optional) transaction management.
+			</para>
+			<para>
+				<emphasis>uac</emphasis> - (optional) user agent operations.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>None</emphasis>
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Parameters</title>
+	<section id="rtjson.p.xavp_cfg">
+		<title><varname>xavp_cfg</varname> (str)</title>
+		<para>
+			The name of the xavp to be used internally by the module. 
+		</para>
+		<para>
+		<emphasis>
+			Default value is "rtjson".
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>xavp_cfg</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rtjson", "xavp_cfg", "myxavp")
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>Functions</title>
+	<section id="rtjson.f.rtjson_init_routes">
+	    <title>
+		<function moreinfo="none">rtjson_init_routes(rtdoc)</function>
+	    </title>
+	    <para>
+		Initialize routing based on JSON document stored in rtdoc parameter.
+		</para>
+		<para>
+		The rtdoc parameter can be a static string or a dynamic string
+		value with config variables. It has to result in a valid JSON document
+		with the structure specified in chapter 'JSON Routing Structure'.
+		</para>
+			<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title><function>rtjson_init_routes</function> usage</title>
+		<programlisting format="linespecific">
+...
+rtjson_init_routes("$var(json)");
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section id="rtjson.f.rtjson_push_routes">
+	    <title>
+		<function moreinfo="none">rtjson_push_routes()</function>
+	    </title>
+	    <para>
+		Push the routes given in JSON document to rtjson_init_routes(rtdoc) to
+		the internal fields used by &kamailio; for routing.
+		</para>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title><function>rtjson_push_routes</function> usage</title>
+		<programlisting format="linespecific">
+...
+rtjson_init_routes("$var(json)");
+rtjson_push_routes();
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section id="rtjson.f.rtjson_next_route">
+	    <title>
+		<function moreinfo="none">rtjson_next_route()</function>
+	    </title>
+	    <para>
+		To be used in failure_route for serial forking, to push the next route
+		to the internal fields used by &kamailio; for routing.
+		</para>
+		<para>
+		This function can be used from FAILURE_ROUTE.
+		</para>
+		<example>
+		<title><function>rtjson_next_route</function> usage</title>
+		<programlisting format="linespecific">
+...
+rtjson_init_routes("$var(json)");
+rtjson_push_routes();
+...
+failure_route[REROUTE] {
+	rtjson_next_route();
+}
+...
+</programlisting>
+	    </example>
+	</section>
+
+	<section id="rtjson.f.rtjson_update_branch">
+	    <title>
+		<function moreinfo="none">rtjson_update_branch()</function>
+	    </title>
+	    <para>
+		To be used in branch_route if the JSON document had attributes
+		that needs to be set for each branch.
+		</para>
+		<para>
+		This function can be used from BRANCH_ROUTE.
+		</para>
+		<example>
+		<title><function>rtjson_update_branch</function> usage</title>
+		<programlisting format="linespecific">
+...
+rtjson_init_routes("$var(json)");
+rtjson_push_routes();
+...
+branch_route[OUTGOING] {
+	rtjson_update_branch();
+}
+...
+</programlisting>
+	    </example>
+	</section>
+
+	</section>
+
+	<section id="rtjson.json-routing-structure">
+	<title>JSON Routing Structure</title>
+	<para>
+		TBA.
+	</para>
+	</section>
+</chapter>
+

+ 170 - 0
modules/rtjson/rtjson_mod.c

@@ -0,0 +1,170 @@
+/**
+ * Copyright (C) 2015 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+
+#include "rtjson_routing.h"
+
+MODULE_VERSION
+
+
+str _rtjson_xavp_name = str_init("rtjson");
+
+static int  mod_init(void);
+static int  child_init(int);
+static void mod_destroy(void);
+
+static int w_rtjson_init_routes(sip_msg_t *msg, char *rdoc, char *rflags);
+static int w_rtjson_push_routes(sip_msg_t *msg, char *p1, char *p2);
+static int w_rtjson_next_route(sip_msg_t *msg, char *p1, char *p2);
+static int w_rtjson_update_branch(sip_msg_t *msg, char *p1, char *p2);
+
+static cmd_export_t cmds[]={
+	{"rtjson_init_routes", (cmd_function)w_rtjson_init_routes, 1, fixup_spve_null,
+		0, REQUEST_ROUTE},
+	{"rtjson_push_routes", (cmd_function)w_rtjson_push_routes,     0, 0,
+		0, REQUEST_ROUTE},
+	{"rtjson_next_route", (cmd_function)w_rtjson_next_route,       0, 0,
+		0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"rtjson_update_branch", (cmd_function)w_rtjson_update_branch, 0, 0,
+		0, BRANCH_ROUTE},
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]={
+	{"xavp_cfg", PARAM_STR, &_rtjson_xavp_name},
+	{0, 0, 0}
+};
+
+struct module_exports exports = {
+	"rtjson",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,
+	0,              /* exported MI functions */
+	0,              /* exported pseudo-variables */
+	0,              /* extra processes */
+	mod_init,       /* module initialization function */
+	0,              /* response function */
+	mod_destroy,    /* destroy function */
+	child_init      /* per child init function */
+};
+
+/**
+ * init module function
+ */
+static int mod_init(void)
+{
+	if(_rtjson_xavp_name.s==NULL || _rtjson_xavp_name.len<=0) {
+		LM_ERR("invalid xavp name\n");
+		return -1;
+	}
+	if(rtjson_init()<0) {
+		LM_ERR("failed to initialize\n");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * @brief Initialize async module children
+ */
+static int child_init(int rank)
+{
+	return 0;
+}
+/**
+ * destroy module function
+ */
+static void mod_destroy(void)
+{
+}
+
+/**
+ *
+ */
+static int w_rtjson_init_routes(sip_msg_t *msg, char *rdoc, char *rflags)
+{
+	str srdoc = {0};
+
+	if(msg==NULL)
+		return -1;
+
+	if(fixup_get_svalue(msg, (gparam_t*)rdoc, &srdoc)!=0 || srdoc.len<=0) {
+		LM_ERR("no routing information\n");
+		return -1;
+	}
+	if(rtjson_init_routes(msg, &srdoc)<0)
+		return -1;
+
+	return 1;
+}
+
+/**
+ *
+ */
+static int w_rtjson_push_routes(sip_msg_t *msg, char *p1, char *p2)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(rtjson_push_routes(msg)<0)
+		return -1;
+
+	return 1;
+}
+
+/**
+ *
+ */
+static int w_rtjson_next_route(sip_msg_t *msg, char *p1, char *p2)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(rtjson_next_route(msg)<0)
+		return -1;
+
+	return 1;
+}
+
+/**
+ *
+ */
+static int w_rtjson_update_branch(sip_msg_t *msg, char *p1, char *p2)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(rtjson_update_branch(msg)<0)
+		return -1;
+
+	return 1;
+}

+ 611 - 0
modules/rtjson/rtjson_routing.c

@@ -0,0 +1,611 @@
+/**
+ * Copyright (C) 2015 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../dprint.h"
+#include "../../xavp.h"
+#include "../../dset.h"
+#include "../../mem/shm_mem.h"
+#include "../../lib/srutils/srjson.h"
+#include "../../modules/tm/tm_load.h"
+#include "../../modules/uac/api.h"
+
+#include "rtjson_routing.h"
+
+typedef struct rtjson_data {
+	srjson_doc_t *jdoc;
+	int idx;
+} rtjson_data_t;
+
+extern str _rtjson_xavp_name;
+
+int rtjson_init_serial(sip_msg_t *msg, srjson_doc_t *jdoc, sr_xavp_t *iavp);
+int rtjson_init_parallel(sip_msg_t *msg, srjson_doc_t *jdoc, sr_xavp_t *iavp);
+
+/* tm */
+static struct tm_binds tmb;
+/* uac */
+static uac_api_t uacb;
+
+int rtjson_init(void)
+{
+	if (load_tm_api( &tmb ) == -1) {
+		LM_NOTICE("cannot load the TM API - some features are diabled\n");
+		memset(&tmb, 0, sizeof(struct tm_binds));
+	}
+	if (load_uac_api(&uacb) < 0) {
+		LM_ERR("cannot bind to UAC API - some features are diabled\n");
+		memset(&uacb, 0, sizeof(uac_api_t));
+	}
+	return 0;
+}
+
+#ifdef RTJSON_STORE_SHM
+/**
+ *
+ */
+void rtjson_data_free(void *ptr, sr_xavp_sfree_f sfree)
+{
+	rtjson_data_t *rdata;
+
+	rdata = (rtjson_data_t*)ptr;
+
+	if(rdata->jdoc) {
+		rdata->jdoc->free_fn = sfree;
+		srjson_DeleteDoc(rdata->jdoc);
+	}
+	sfree(ptr);
+}
+
+/**
+ *
+ */
+void *rtjson_malloc(size_t sz)
+{
+	return shm_malloc(sz);
+}
+
+/**
+ *
+ */
+void rtjson_free(void *ptr)
+{
+	shm_free(ptr);
+}
+
+/**
+ *
+ */
+int rtjson_init_routes(sip_msg_t *msg, str *rdoc)
+{
+	srjson_Hooks jhooks;
+	srjson_doc_t *tdoc = NULL;
+	sr_data_t *xdata = NULL;
+	rtjson_data_t *rdata = NULL;
+	sr_xavp_t *xavp=NULL;
+	str xname;
+	sr_xval_t xval;
+
+
+	memset(&jhooks, 0, sizeof(srjson_Hooks));
+	jhooks.malloc_fn = rtjson_malloc;
+	jhooks.free_fn = rtjson_free;
+
+	tdoc = srjson_NewDoc(&jhooks);
+
+	if(tdoc==NULL) {
+		LM_ERR("no more shm\n");
+		return -1;
+	}
+	tdoc->root = srjson_Parse(tdoc, rdoc->s);
+	if(tdoc->root == NULL) {
+		LM_ERR("invalid json doc [[%s]]\n", rdoc->s);
+		srjson_DeleteDoc(tdoc);
+		return -1;
+	}
+	xdata = shm_malloc(sizeof(sr_data_t));
+	if(xdata==NULL) {
+		LM_ERR("no more shm\n");
+		srjson_DeleteDoc(tdoc);
+		return -1;
+	}
+	memset(xdata, 0, sizeof(sr_data_t));
+	rdata = shm_malloc(sizeof(rtjson_data_t));
+	if(rdata==NULL) {
+		LM_ERR("no more shm\n");
+		srjson_DeleteDoc(tdoc);
+		shm_free(xdata);
+		return -1;
+	}
+	memset(rdata, 0, sizeof(rtjson_data_t));
+
+	rdata->jdoc = tdoc;
+	xdata->p = rdata;
+	xdata->pfree = rtjson_data_free;
+
+	memset(&xval, 0, sizeof(sr_xval_t));
+	xval.type = SR_XTYPE_STR;
+	xval.v.s = *rdoc;
+	xname.s = "json";
+	xname.len = 4;
+	if(xavp_add_value(&xname, &xval, &xavp)==NULL) {
+		goto error;
+	}
+
+	memset(&xval, 0, sizeof(sr_xval_t));
+	xval.type = SR_XTYPE_DATA;
+	xval.v.data = xdata;
+	xname.s = "data";
+	xname.len = 4;
+	if(xavp_add_value(&xname, &xval, &xavp)==NULL) {
+		goto error;
+	}
+	/* reset pointers - they are linked inside xavp now */
+	tdoc = NULL;
+	xdata = NULL;
+	rdata = NULL;
+
+	memset(&xval, 0, sizeof(sr_xval_t));
+	xval.type = SR_XTYPE_XAVP;
+	xval.v.xavp = xavp;
+	if(xavp_add_value(&_rtjson_xavp_name, &xval, NULL)==NULL) {
+		goto error;
+	}
+
+	return 0;
+error:
+	if(xavp) xavp_destroy_list(&xavp);
+	if(rdata) shm_free(rdata);
+	if(xdata) shm_free(xdata);
+	if(tdoc) srjson_DeleteDoc(tdoc);
+	return -1;
+}
+#else
+
+/**
+ *
+ */
+int rtjson_init_routes(sip_msg_t *msg, str *rdoc)
+{
+	sr_xavp_t *xavp=NULL;
+	str xname;
+	sr_xval_t xval;
+	srjson_doc_t tdoc;
+
+	srjson_InitDoc(&tdoc, NULL);
+
+	tdoc.root = srjson_Parse(&tdoc, rdoc->s);
+	if(tdoc.root == NULL) {
+		LM_ERR("invalid json doc [[%s]]\n", rdoc->s);
+		srjson_DestroyDoc(&tdoc);
+		return -1;
+	}
+
+	/* basic validation */
+
+	srjson_DestroyDoc(&tdoc);
+
+	memset(&xval, 0, sizeof(sr_xval_t));
+	xval.type = SR_XTYPE_INT;
+	xval.v.i = 0;
+	xname.s = "idx";
+	xname.len = 3;
+	if(xavp_add_value(&xname, &xval, &xavp)==NULL) {
+		goto error;
+	}
+
+	memset(&xval, 0, sizeof(sr_xval_t));
+	xval.type = SR_XTYPE_STR;
+	xval.v.s = *rdoc;
+	xname.s = "json";
+	xname.len = 4;
+	if(xavp_add_value(&xname, &xval, &xavp)==NULL) {
+		goto error;
+	}
+
+	memset(&xval, 0, sizeof(sr_xval_t));
+	xval.type = SR_XTYPE_XAVP;
+	xval.v.xavp = xavp;
+	if(xavp_add_value(&_rtjson_xavp_name, &xval, NULL)==NULL) {
+		goto error;
+	}
+
+	return 0;
+
+error:
+	if(xavp) xavp_destroy_list(&xavp);
+	return -1;
+}
+#endif
+
+/**
+ *
+ */
+int rtjson_push_routes(sip_msg_t *msg)
+{
+	sr_xavp_t *javp = NULL;
+	sr_xavp_t *iavp = NULL;
+	srjson_doc_t tdoc;
+	srjson_t *nj = NULL;
+	str val;
+	str xname;
+	int ret;
+
+	xname.s = "json";
+	xname.len = 4;
+	javp = xavp_get_child_with_sval(&_rtjson_xavp_name, &xname);
+	if(javp==NULL || javp->val.v.s.len<=0) {
+		LM_WARN("no json for routing\n");
+		return -1;
+	}
+
+	xname.s = "idx";
+	xname.len = 3;
+	iavp = xavp_get_child_with_ival(&_rtjson_xavp_name, &xname);
+	if(iavp==NULL) {
+		LM_WARN("no idx for routing\n");
+		return -1;
+	}
+
+	srjson_InitDoc(&tdoc, NULL);
+
+	tdoc.root = srjson_Parse(&tdoc, javp->val.v.s.s);
+	if(tdoc.root == NULL) {
+		LM_ERR("invalid json doc [[%s]]\n", javp->val.v.s.s);
+		srjson_DestroyDoc(&tdoc);
+		return -1;
+	}
+
+	nj = srjson_GetObjectItem(&tdoc, tdoc.root, "routing");
+	if(nj==NULL || nj->valuestring==NULL) {
+		LM_ERR("missing or invalid routing field\n");
+		goto error;
+	}
+	val.s = nj->valuestring;
+	val.len = strlen(val.s);
+
+	if(val.len==6 && strncmp(val.s, "serial", 6)==0) {
+		LM_DBG("supported routing [%.*s]\n", val.len, val.s);
+		ret = rtjson_init_serial(msg, &tdoc, iavp);
+	} else if(val.len==8 && strncmp(val.s, "parallel", 8)==0) {
+		LM_DBG("supported routing [%.*s]\n", val.len, val.s);
+		ret = rtjson_init_parallel(msg, &tdoc, iavp);
+	} else {
+		LM_ERR("unsupported routing [%.*s]\n", val.len, val.s);
+		goto error;
+	}
+
+	srjson_DestroyDoc(&tdoc);
+	return ret;
+
+error:
+	srjson_DestroyDoc(&tdoc);
+	return -1;
+}
+
+/**
+ *
+ */
+int rtjson_init_serial(sip_msg_t *msg, srjson_doc_t *jdoc, sr_xavp_t *iavp)
+{
+	srjson_t *nj = NULL;
+	srjson_t *rj = NULL;
+	str val;
+
+	nj = srjson_GetObjectItem(jdoc, jdoc->root, "routes");
+	if(nj==NULL || nj->type!=srjson_Array || nj->child==NULL) {
+		LM_ERR("missing or invalid routes field\n");
+		goto error;
+	}
+
+	clear_branches();
+
+	rj = srjson_GetObjectItem(jdoc, nj, "uri");
+	if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) {
+		val.s = rj->valuestring;
+		val.len = strlen(val.s);
+		if (rewrite_uri(msg, &val) < 0) {
+			LM_ERR("unable to rewrite Request-URI\n");
+			goto error;
+		}
+	}
+
+	reset_dst_uri(msg);
+	reset_path_vector(msg);
+	reset_instance(msg);
+	reset_ruid(msg);
+	reset_ua(msg);
+	reset_force_socket(msg);
+	msg->reg_id = 0;
+	set_ruri_q(0);
+
+	rj = srjson_GetObjectItem(jdoc, nj, "dst_uri");
+	if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) {
+		val.s = rj->valuestring;
+		val.len = strlen(val.s);
+		if (set_dst_uri(msg, &val) < 0) {
+			LM_ERR("unable to set destination uri\n");
+			goto error;
+		}
+	}
+
+	rj = srjson_GetObjectItem(jdoc, nj, "path");
+	if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) {
+		val.s = rj->valuestring;
+		val.len = strlen(val.s);
+		if (set_path_vector(msg, &val) < 0) {
+			LM_ERR("unable to set path\n");
+			goto error;
+		}
+	}
+
+	iavp->val.v.i++;
+
+	return 0;
+
+error:
+	return -1;
+}
+
+/**
+ *
+ */
+int rtjson_prepare_branch(sip_msg_t *msg, srjson_doc_t *jdoc, srjson_t *nj)
+{
+	return 0;
+}
+
+/**
+ *
+ */
+int rtjson_append_branch(sip_msg_t *msg, srjson_doc_t *jdoc, srjson_t *nj)
+{
+	srjson_t *rj = NULL;
+	str uri = {0};
+	str duri = {0};
+	str path = {0};
+	struct socket_info* fsocket = NULL;
+	unsigned int bflags = 0;
+	str val;
+
+	rj = srjson_GetObjectItem(jdoc, nj, "uri");
+	if(rj==NULL || rj->type!=srjson_String || rj->valuestring==NULL) {
+		return -1;
+	}
+
+	uri.s = rj->valuestring;
+	uri.len = strlen(val.s);
+
+	rj = srjson_GetObjectItem(jdoc, nj, "dst_uri");
+	if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) {
+		duri.s = rj->valuestring;
+		duri.len = strlen(val.s);
+	}
+	rj = srjson_GetObjectItem(jdoc, nj, "path");
+	if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) {
+		path.s = rj->valuestring;
+		path.len = strlen(val.s);
+	}
+	
+	if (append_branch(msg, &uri, &duri, &path, 0, bflags,
+					  fsocket, 0 /*instance*/, 0,
+					  0, 0) <0) {
+		LM_ERR("failed to append branch\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	return -1;
+}
+
+/**
+ *
+ */
+int rtjson_init_parallel(sip_msg_t *msg, srjson_doc_t *jdoc, sr_xavp_t *iavp)
+{
+	srjson_t *nj = NULL;
+	int ret;
+
+	nj = srjson_GetObjectItem(jdoc, jdoc->root, "routes");
+	if(nj==NULL || nj->type!=srjson_Array || nj->child==NULL) {
+		LM_ERR("missing or invalid routes field\n");
+		goto error;
+	}
+
+	ret = rtjson_init_serial(msg, jdoc, iavp);
+	if(ret<0)
+		return ret;
+
+	/* skip first - used for r-uri */
+	nj = nj->next;
+
+	while(nj) {
+		rtjson_append_branch(msg, jdoc, nj);
+
+		iavp->val.v.i++;
+		nj = nj->next;
+	}
+
+	return 0;
+
+error:
+	return -1;
+}
+
+/**
+ *
+ */
+int rtjson_next_route(sip_msg_t *msg)
+{
+	sr_xavp_t *javp = NULL;
+	sr_xavp_t *iavp = NULL;
+	srjson_doc_t tdoc;
+	srjson_t *nj = NULL;
+	str val;
+	str xname;
+	int ret;
+	int i;
+
+	xname.s = "json";
+	xname.len = 4;
+	javp = xavp_get_child_with_sval(&_rtjson_xavp_name, &xname);
+	if(javp==NULL || javp->val.v.s.len<=0) {
+		LM_WARN("no json for routing\n");
+		return -1;
+	}
+
+	xname.s = "idx";
+	xname.len = 3;
+	iavp = xavp_get_child_with_ival(&_rtjson_xavp_name, &xname);
+	if(iavp==NULL) {
+		LM_WARN("no idx for routing\n");
+		return -1;
+	}
+
+	srjson_InitDoc(&tdoc, NULL);
+
+	tdoc.root = srjson_Parse(&tdoc, javp->val.v.s.s);
+	if(tdoc.root == NULL) {
+		LM_ERR("invalid json doc [[%s]]\n", javp->val.v.s.s);
+		srjson_DestroyDoc(&tdoc);
+		return -1;
+	}
+
+	nj = srjson_GetObjectItem(&tdoc, tdoc.root, "routing");
+	if(nj==NULL || nj->valuestring==NULL) {
+		LM_ERR("missing or invalid routing field\n");
+		goto error;
+	}
+	val.s = nj->valuestring;
+	val.len = strlen(val.s);
+
+	if(val.len!=6 || strncmp(val.s, "serial", 6)!=0) {
+		LM_DBG("not serial routing [%.*s]\n", val.len, val.s);
+		goto error;
+	}
+
+	nj = srjson_GetObjectItem(&tdoc, tdoc.root, "routes");
+	if(nj==NULL || nj->type!=srjson_Array || nj->child==NULL) {
+		LM_ERR("missing or invalid routes field\n");
+		goto error;
+	}
+
+	while(nj && i<iavp->val.v.i) {
+		nj = nj->next;
+	}
+	if(nj==NULL)
+		goto error;
+
+	iavp->val.v.i++;
+	if(rtjson_append_branch(msg, &tdoc, nj)<0)
+		goto error;
+
+	srjson_DestroyDoc(&tdoc);
+	return 0;
+
+error:
+	srjson_DestroyDoc(&tdoc);
+	return -1;
+}
+
+/**
+ *
+ */
+int rtjson_update_branch(sip_msg_t *msg)
+{
+	sr_xavp_t *javp = NULL;
+	sr_xavp_t *iavp = NULL;
+	srjson_doc_t tdoc;
+	srjson_t *nj = NULL;
+	str val;
+	str xname;
+	int ret;
+	int i;
+
+	xname.s = "json";
+	xname.len = 4;
+	javp = xavp_get_child_with_sval(&_rtjson_xavp_name, &xname);
+	if(javp==NULL || javp->val.v.s.len<=0) {
+		LM_WARN("no json for routing\n");
+		return -1;
+	}
+
+	xname.s = "idx";
+	xname.len = 3;
+	iavp = xavp_get_child_with_ival(&_rtjson_xavp_name, &xname);
+	if(iavp==NULL) {
+		LM_WARN("no idx for routing\n");
+		return -1;
+	}
+
+	srjson_InitDoc(&tdoc, NULL);
+
+	tdoc.root = srjson_Parse(&tdoc, javp->val.v.s.s);
+	if(tdoc.root == NULL) {
+		LM_ERR("invalid json doc [[%s]]\n", javp->val.v.s.s);
+		srjson_DestroyDoc(&tdoc);
+		return -1;
+	}
+
+	nj = srjson_GetObjectItem(&tdoc, tdoc.root, "routing");
+	if(nj==NULL || nj->valuestring==NULL) {
+		LM_ERR("missing or invalid routing field\n");
+		goto error;
+	}
+	val.s = nj->valuestring;
+	val.len = strlen(val.s);
+
+	if(val.len!=6 || strncmp(val.s, "serial", 6)!=0) {
+		LM_DBG("not serial routing [%.*s]\n", val.len, val.s);
+		goto error;
+	}
+
+	nj = srjson_GetObjectItem(&tdoc, tdoc.root, "routes");
+	if(nj==NULL || nj->type!=srjson_Array || nj->child==NULL) {
+		LM_ERR("missing or invalid routes field\n");
+		goto error;
+	}
+
+	while(nj && i<iavp->val.v.i) {
+		nj = nj->next;
+	}
+	if(nj==NULL)
+		goto error;
+
+	if(rtjson_prepare_branch(msg, &tdoc, nj)<0)
+		goto error;
+
+	srjson_DestroyDoc(&tdoc);
+	return 0;
+
+error:
+	srjson_DestroyDoc(&tdoc);
+	return -1;
+
+}
+

+ 34 - 0
modules/rtjson/rtjson_routing.h

@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2015 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _RTJSON_ROUTING_H_
+#define _RTJSON_ROUTING_H_
+
+#include "../../parser/msg_parser.h"
+
+int rtjson_init_routes(sip_msg_t *msg, str *rdoc);
+int rtjson_push_routes(sip_msg_t *msg);
+int rtjson_next_route(sip_msg_t *msg);
+int rtjson_update_branch(sip_msg_t *msg);
+int rtjson_init(void);
+
+#endif