Procházet zdrojové kódy

jsonrpc-s: implementation of FIFO transport

- JSON-RPC commands can be sent now via a FIFO file, as alternative to (or
  together with) HTTP/S
- it can be useful for using it from terminal with command line/shell
  tools
Daniel-Constantin Mierla před 10 roky
rodič
revize
adde641c3b

+ 174 - 6
modules/jsonrpc-s/README

@@ -29,17 +29,36 @@ Daniel-Constantin Mierla
         3. Parameters
 
               3.1. pretty_format (int)
+              3.2. transport (int)
+              3.3. fifo_name (str)
+              3.4. fifo_mode (int)
+              3.5. fifo_group (int or str)
+              3.6. fifo_user (int or str)
+              3.7. fifo_reply_dir (str)
 
         4. Functions
 
               4.1. jsonrpc_dispatch()
               4.2. jsonrpc_exec(cmd)
 
+        5. JSONRPC Transports
+
+              5.1. JSONRPC Over HTTP
+              5.2. JSONRPC Over FIFO
+
    List of Examples
 
    1.1. Set pretty_format parameter
-   1.2. jsonrpc_dispatch usage
-   1.3. jsonrpc_exec usage
+   1.2. Set transport parameter
+   1.3. Set fifo_name parameter
+   1.4. Set fifo_mode parameter
+   1.5. Set fifo_group parameter
+   1.6. Set fifo_user parameter
+   1.7. Set fifo_reply_dir parameter
+   1.8. jsonrpc_dispatch usage
+   1.9. jsonrpc_exec usage
+   1.10. JSONRPC Over Fifo Command
+   1.11. JSONRPC Over Fifo Command From Termina
 
 Chapter 1. Admin Guide
 
@@ -57,21 +76,35 @@ Chapter 1. Admin Guide
    3. Parameters
 
         3.1. pretty_format (int)
+        3.2. transport (int)
+        3.3. fifo_name (str)
+        3.4. fifo_mode (int)
+        3.5. fifo_group (int or str)
+        3.6. fifo_user (int or str)
+        3.7. fifo_reply_dir (str)
 
    4. Functions
 
         4.1. jsonrpc_dispatch()
         4.2. jsonrpc_exec(cmd)
 
+   5. JSONRPC Transports
+
+        5.1. JSONRPC Over HTTP
+        5.2. JSONRPC Over FIFO
+
 1. Overview
 
    1.1. Limitations
 
-   This module provides a JSON-RPC server over HTTP implementation,
+   This module provides a JSON-RPC v2 server over HTTP implementation,
    tailored for the needs of Kamailio. It implements the Kamailio RPC
    interface over JSON-RPC.
 
-   The JSONRPC-S module uses the xHTTP module to handle HTTP requests.
+   The specification for JSON-RPC is available at:
+   http://www.jsonrpc.org/specification.
+
+   The JSONRPC-S module uses the xHTTP module to handle HTTP/S requests.
    Read the documentation of the xHTTP module for more details.
 
 1.1. Limitations
@@ -102,6 +135,12 @@ Chapter 1. Admin Guide
 3. Parameters
 
    3.1. pretty_format (int)
+   3.2. transport (int)
+   3.3. fifo_name (str)
+   3.4. fifo_mode (int)
+   3.5. fifo_group (int or str)
+   3.6. fifo_user (int or str)
+   3.7. fifo_reply_dir (str)
 
 3.1. pretty_format (int)
 
@@ -114,6 +153,80 @@ Chapter 1. Admin Guide
 modparam("jsonrpc-s", "pretty_format", 1)
 ...
 
+3.2. transport (int)
+
+   Control what transports are enabled. The value can be:
+     * 0 - all transports that can be enabled. For http, the xhttp module
+       must be loaded. For FIFO, the fifo_name parameter must be set.
+     * 1 - only HTTP transport
+     * 2 - only FIFO transport
+
+   Default value is '0'.
+
+   Example 1.2. Set transport parameter
+...
+modparam("jsonrpc-s", "transport", 1)
+...
+
+3.3. fifo_name (str)
+
+   The name of the FIFO file to be created for listening and reading
+   external commands.
+
+   Default value is NONE.
+
+   Example 1.3. Set fifo_name parameter
+...
+modparam("jsonrpc-s", "fifo_name", "/tmp/kamailio_jsonrpc_fifo")
+...
+
+3.4. fifo_mode (int)
+
+   Permission to be used for creating the listening FIFO file. It follows
+   the UNIX conventions.
+
+   Default value is 0660 (rw-rw----).
+
+   Example 1.4. Set fifo_mode parameter
+...
+modparam("jsonrpc-s", "fifo_mode", 0600)
+...
+
+3.5. fifo_group (int or str)
+
+   System Group to be used for creating the listening FIFO file.
+
+   Default value is the inherited one (process group).
+
+   Example 1.5. Set fifo_group parameter
+...
+modparam("jsonrpc-s", "fifo_group", 0)
+modparam("jsonrpc-s", "fifo_group", "root")
+...
+
+3.6. fifo_user (int or str)
+
+   System User to be used for creating the listening FIFO file.
+
+   Default value is the inherited one (process user).
+
+   Example 1.6. Set fifo_user parameter
+...
+modparam("jsonrpc-s", "fifo_user", 0)
+modparam("jsonrpc-s", "fifo_user", "root")
+...
+
+3.7. fifo_reply_dir (str)
+
+   Directory to be used for creating the reply FIFO files.
+
+   Default value is "/tmp/"
+
+   Example 1.7. Set fifo_reply_dir parameter
+...
+modparam("jsonrpc-s", "fifo_reply_dir", "/home/kamailio/tmp/")
+...
+
 4. Functions
 
    4.1. jsonrpc_dispatch()
@@ -123,7 +236,7 @@ modparam("jsonrpc-s", "pretty_format", 1)
 
    Handle the JSONRPC request and generate a response.
 
-   Example 1.2. jsonrpc_dispatch usage
+   Example 1.8. jsonrpc_dispatch usage
 ...
 #!KAMAILIO
 
@@ -174,7 +287,62 @@ event_route[xhttp:request] {
    dynamic string with variables. The result of the command can be
    accessed via $jsonrpl(key) pseudo variables.
 
-   Example 1.3. jsonrpc_exec usage
+   Example 1.9. jsonrpc_exec usage
 ...
 jsonrpc_exec({"jsonrpc": "2.0", "method": "dispatcher.reload", "id": 1}');
 ...
+
+5. JSONRPC Transports
+
+   5.1. JSONRPC Over HTTP
+   5.2. JSONRPC Over FIFO
+
+   JSONRPC specifications do not enforce a specific transport to carry the
+   JSON documents. Very common is JSONRPC over HTTP or HTTPS, and they are
+   supported by Kamailio. In addition, Kamailio supports receiving JSON
+   documents via a local FIFO file.
+
+5.1. JSONRPC Over HTTP
+
+   It requires that XHTTP module is loaded. HTTPS can be used if you
+   enable TLS for Kamailio. The JSONRPC requests have to be sent to the
+   TCP or TLS ports of Kamailio.
+
+   The 'transport' parameter has to be 0 or 1.
+
+   The format of the JSON document must follow the JSONRPC specifications.
+
+5.2. JSONRPC Over FIFO
+
+   This module can retrive JSONRPC requests via a local FIFO file. To
+   enable this feature, 'fifo_name' parameter must be set and 'transport'
+   parameter has to be 0 or 2.
+
+   The format of the JSON document must follow the JSONRPC specifications
+   plus an additional field named 'reply_name'. The value for this field
+   must be the name of the FIFO file were to write the JSONRPC response.
+   The reply FIFO file is created in the folder specified by
+   'fifo_reply_dir'. Next is an example showing a JSONRPC command to be
+   sent via FIFO transport.
+
+   Example 1.10. JSONRPC Over Fifo Command
+...
+{
+ "jsonrpc": "2.0",
+  "method": "core.psx",
+  "reply_name": "kamailio_jsonrpc_reply_fifo",
+  "id": 1
+}
+...
+
+   Next is an example of how to test it from a terminal, assuming that the
+   parameter 'fifo_name' is set to '/tmp/kamailio_jsonrpc_fifo'.
+
+   Example 1.11. JSONRPC Over Fifo Command From Termina
+...
+mkfifo /tmp/kamailio_jsonrpc_reply_fifo
+cat /tmp/kamailio_jsonrpc_reply_fifo &
+echo '{"jsonrpc": "2.0", "method": "core.psx", \
+          "reply_name": "kamailio_jsonrpc_reply_fifo", "id": 1}' \
+     > /tmp/kamailio_jsonrpc_fifo
+rm /tmp/kamailio_jsonrpc_reply_fifo

+ 216 - 3
modules/jsonrpc-s/doc/jsonrpc-s_admin.xml

@@ -16,12 +16,16 @@
 	<section>
 	<title>Overview</title>
 	<para>
-		This module provides a JSON-RPC server over HTTP implementation,
+		This module provides a JSON-RPC v2 server over HTTP implementation,
 		tailored for the needs of &kamailio;. It implements the &kamailio;
 		RPC interface over JSON-RPC.
+	</para>
 	<para>
+		The specification for JSON-RPC is available at:
+		<ulink url="http://www.jsonrpc.org/specification">http://www.jsonrpc.org/specification</ulink>.
 	</para>
-		The JSONRPC-S module uses the xHTTP module to handle HTTP requests.
+	<para>
+		The JSONRPC-S module uses the xHTTP module to handle HTTP/S requests.
 		Read the documentation of the xHTTP module for more details.
 	</para>
 
@@ -78,7 +82,7 @@
 	</section>
 	<section>
 	<title>Parameters</title>
-	<section>
+	<section id="jsonrpc-s.p.pretty_format">
 		<title><varname>pretty_format</varname> (int)</title>
 		<para>
 			Pretty format for JSON-RPC response document. 
@@ -97,6 +101,143 @@ modparam("jsonrpc-s", "pretty_format", 1)
 </programlisting>
 		</example>
 	</section>
+	<section id="jsonrpc-s.p.transport">
+		<title><varname>transport</varname> (int)</title>
+		<para>
+			Control what transports are enabled. The value can be:
+		</para>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>0</emphasis> - all transports that can be enabled.
+				For http, the xhttp module must be loaded. For FIFO, the
+				fifo_name parameter must be set.
+			</para></listitem>
+			<listitem><para>
+				<emphasis>1</emphasis> - only HTTP transport
+			</para></listitem>
+			<listitem><para>
+				<emphasis>2</emphasis> - only FIFO transport
+			</para></listitem>
+		</itemizedlist>
+
+		<para>
+		<emphasis>
+			Default value is '0'.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>transport</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("jsonrpc-s", "transport", 1)
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="jsonrpc-s.p.fifo_name">
+		<title><varname>fifo_name</varname> (str)</title>
+		<para>
+		The name of the FIFO file to be created for listening and 
+		reading external commands.
+		</para>
+		<para>
+		<emphasis>
+			Default value is NONE.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>fifo_name</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("jsonrpc-s", "fifo_name", "/tmp/kamailio_jsonrpc_fifo")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="jsonrpc-s.p.fifo_mode">
+		<title><varname>fifo_mode</varname> (int)</title>
+		<para>
+		Permission to be used for creating the listening FIFO file. It 
+		follows the UNIX conventions.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0660 (rw-rw----).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>fifo_mode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("jsonrpc-s", "fifo_mode", 0600)
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="jsonrpc-s.p.fifo_group">
+		<title><varname>fifo_group</varname> (int or str)</title>
+		<para>
+		System Group to be used for creating the listening FIFO file.
+		</para>
+		<para>
+		<emphasis>
+			Default value is the inherited one (process group).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>fifo_group</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("jsonrpc-s", "fifo_group", 0)
+modparam("jsonrpc-s", "fifo_group", "root")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="jsonrpc-s.p.fifo_user">
+		<title><varname>fifo_user</varname> (int or str)</title>
+		<para>
+		System User to be used for creating the listening FIFO file.
+		</para>
+		<para>
+		<emphasis>
+			Default value is the inherited one (process user).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>fifo_user</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("jsonrpc-s", "fifo_user", 0)
+modparam("jsonrpc-s", "fifo_user", "root")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section id="jsonrpc-s.p.fifo_reply_dir">
+		<title><varname>fifo_reply_dir</varname> (str)</title>
+		<para>
+		Directory to be used for creating the reply FIFO files.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>/tmp/</quote>
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>fifo_reply_dir</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("jsonrpc-s", "fifo_reply_dir", "/home/kamailio/tmp/")
+...
+</programlisting>
+		</example>
+	</section>
+
 	</section>
 
 	<section>
@@ -178,5 +319,77 @@ jsonrpc_exec({"jsonrpc": "2.0", "method": "dispatcher.reload", "id": 1}');
 	</section>
 
 	</section>
+
+	<section>
+	<title>JSONRPC Transports</title>
+	<para>
+	JSONRPC specifications do not enforce a specific transport to carry the
+	JSON documents. Very common is JSONRPC over HTTP or HTTPS, and they are
+	supported by &kamailio;. In addition, &kamailio; supports receiving JSON
+	documents via a local FIFO file. 
+	</para>
+ 	<section>
+	    <title>JSONRPC Over HTTP</title>
+	    <para>
+			It requires that XHTTP module is loaded. HTTPS can be used if
+			you enable TLS for &kamailio;. The JSONRPC requests have to be
+			sent to the TCP or TLS ports of &kamailio;.
+		</para>
+		<para>
+			The 'transport' parameter has to be 0 or 1.
+		</para>
+		<para>
+			The format of the JSON document must follow the JSONRPC
+			specifications.
+		</para>
+	</section>
+ 	<section>
+	    <title>JSONRPC Over FIFO</title>
+	    <para>
+			This module can retrive JSONRPC requests via a local FIFO file. To
+			enable this feature, 'fifo_name' parameter must be set and
+			'transport' parameter has to be 0 or 2.
+		</para>
+		<para>
+			The format of the JSON document must follow the JSONRPC
+			specifications plus an additional field named 'reply_name'. The
+			value for this field must be the name of the FIFO file were to
+			write the JSONRPC response. The reply FIFO file is created in the
+			folder specified by 'fifo_reply_dir'. Next is an example showing
+			a JSONRPC command to be sent via FIFO transport.
+		</para>
+		<example>
+		<title>JSONRPC Over Fifo Command</title>
+		<programlisting format="linespecific">
+...
+{
+ "jsonrpc": "2.0",
+  "method": "core.psx",
+  "reply_name": "kamailio_jsonrpc_reply_fifo",
+  "id": 1
+}
+...
+</programlisting>
+	    </example>
+		<para>
+			Next is an example of how to test it from a terminal, assuming that
+			the parameter 'fifo_name' is set to '/tmp/kamailio_jsonrpc_fifo'.
+		</para>
+		<example>
+		<title>JSONRPC Over Fifo Command From Termina</title>
+		<programlisting format="linespecific">
+...
+mkfifo /tmp/kamailio_jsonrpc_reply_fifo
+cat /tmp/kamailio_jsonrpc_reply_fifo &amp;
+echo '{"jsonrpc": "2.0", "method": "core.psx", \
+          "reply_name": "kamailio_jsonrpc_reply_fifo", "id": 1}' \
+     > /tmp/kamailio_jsonrpc_fifo
+rm /tmp/kamailio_jsonrpc_reply_fifo
+</programlisting>
+	    </example>
+
+	</section>
+	</section>
+
 </chapter>
 

+ 578 - 12
modules/jsonrpc-s/jsonrpc-s_mod.c

@@ -23,12 +23,19 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
 
 #include "../../ver.h"
 #include "../../trim.h"
+#include "../../pt.h"
 #include "../../sr_module.h"
 #include "../../mod_fix.h"
 #include "../../nonsip_hooks.h"
+#include "../../cfg/cfg_struct.h"
 #include "../../modules/xhttp/api.h"
 
 #include "jsonrpc-s_mod.h"
@@ -53,8 +60,19 @@ MODULE_VERSION
 #define jsonrpc_malloc	pkg_malloc
 #define jsonrpc_free	pkg_free
 
-str JSONRPC_REASON_OK = str_init("OK");
-str JSONRPC_CONTENT_TYPE_HTML = str_init("application/json");
+static str JSONRPC_REASON_OK = str_init("OK");
+static str JSONRPC_CONTENT_TYPE_HTML = str_init("application/json");
+
+/* FIFO server vars */
+static char *jsonrpc_fifo = NULL;				/*!< FIFO file name */
+static char *jsonrpc_fifo_reply_dir = "/tmp/"; 	/*!< dir where reply fifos are allowed */
+static int  jsonrpc_fifo_uid = -1;				/*!< Fifo default UID */
+static char *jsonrpc_fifo_uid_s = 0;			/*!< Fifo default User ID name */
+static int  jsonrpc_fifo_gid = -1;				/*!< Fifo default Group ID */
+static char *jsonrpc_fifo_gid_s = 0;			/*!< Fifo default Group ID name */
+static int  jsonrpc_fifo_mode = S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP; /* Default file mode rw-rw---- */
+
+static int  jsonrpc_transport = 0;				/*!< 0 - all available; 1 - http; 2 - fifo */
 
 static int jsonrpc_pretty_format = 0;
 
@@ -62,9 +80,12 @@ static int jsonrpc_register_rpc(void);
 
 static int mod_init(void);
 static int child_init(int rank);
+static void mod_destroy(void);
 static int jsonrpc_dispatch(sip_msg_t* msg, char* s1, char* s2);
 static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2);
 
+static int jsonrpc_init_fifo_file(void);
+static void jsonrpc_fifo_process(int rank);
 
 /** The context of the jsonrpc request being processed.
  *
@@ -95,7 +116,15 @@ static cmd_export_t cmds[] = {
 };
 
 static param_export_t params[] = {
-	{"pretty_format",   PARAM_INT,    &jsonrpc_pretty_format},
+	{"pretty_format",    PARAM_INT,    &jsonrpc_pretty_format},
+	{"fifo_name",        PARAM_STRING, &jsonrpc_fifo},
+	{"fifo_mode",        PARAM_INT,	   &jsonrpc_fifo_mode},
+	{"fifo_group",       PARAM_STRING, &jsonrpc_fifo_gid_s},
+	{"fifo_group",       PARAM_INT,    &jsonrpc_fifo_gid},
+	{"fifo_user",        PARAM_STRING, &jsonrpc_fifo_uid_s},
+	{"fifo_user",        PARAM_INT,    &jsonrpc_fifo_uid},
+	{"fifo_reply_dir",   PARAM_STRING, &jsonrpc_fifo_reply_dir},
+	{"transport",        PARAM_INT,    &jsonrpc_transport},
 	{0, 0, 0}
 };
 
@@ -120,7 +149,7 @@ struct module_exports exports= {
 	0,			/* extra processes */
 	mod_init,	/* module initialization function */
 	0,
-	0,
+	mod_destroy,/* module destroy function */
 	child_init	/* per-child init function */
 };
 
@@ -317,6 +346,7 @@ static int jsonrpc_send(jsonrpc_ctx_t* ctx)
 		} else {
 			jsonrpc_set_plain_reply(ctx->http_code, &ctx->http_text, &rbuf,
 					ctx->jrpl->free_fn);
+			rbuf.s=NULL;
 		}
 	} else {
 		if(ctx->msg) {
@@ -864,9 +894,25 @@ static void jsonrpc_clean_context(jsonrpc_ctx_t* ctx)
 static int mod_init(void)
 {
 	/* bind the XHTTP API */
-	if (xhttp_load_api(&xhttp_api) < 0) {
-		LM_ERR("cannot bind to XHTTP API\n");
-		return -1;
+	if(jsonrpc_transport==0 || jsonrpc_transport==1) {
+		if (xhttp_load_api(&xhttp_api) < 0) {
+			if(jsonrpc_transport==1) {
+				LM_ERR("cannot bind to XHTTP API\n");
+				return -1;
+			} else {
+				memset(&xhttp_api, 0, sizeof(xhttp_api_t));
+			}
+		}
+	}
+	if(jsonrpc_transport==0 || jsonrpc_transport==2) {
+		if(jsonrpc_init_fifo_file()<0) {
+			if(jsonrpc_transport==2) {
+				LM_ERR("cannot initialize fifo transport\n");
+				return -1;
+			} else {
+				jsonrpc_fifo = NULL;
+			}
+		}
 	}
 
 	memset(&func_param, 0, sizeof(func_param));
@@ -892,12 +938,61 @@ static int mod_init(void)
 
 static int child_init(int rank)
 {
+	int pid;
+
+	if (rank==PROC_MAIN) {
+		if(jsonrpc_fifo != NULL) {
+			pid=fork_process(PROC_NOCHLDINIT, "JSONRPC-S FIFO", 1);
+			if (pid<0)
+				return -1; /* error */
+			if(pid==0) {
+				/* child */
+
+				/* initialize the config framework */
+				if (cfg_child_init())
+					return -1;
+
+				jsonrpc_fifo_process(1);
+			}
+		}
+	}
+
 	if(rank==PROC_MAIN || rank==PROC_TCP_MAIN)
+	{
 		return 0; /* do nothing for the main process */
+	}
 
 	return 0;
 }
 
+static void mod_destroy(void)
+{
+	int n;
+	struct stat filestat;
+
+	if(jsonrpc_fifo==NULL)
+		return;
+
+	/* destroying the fifo file */
+	n=stat(jsonrpc_fifo, &filestat);
+	if (n==0){
+		/* FIFO exist, delete it (safer) if not config check */
+		if(config_check==0) {
+			if (unlink(jsonrpc_fifo)<0){
+				LM_ERR("cannot delete the fifo (%s): %s\n",
+					jsonrpc_fifo, strerror(errno));
+				goto error;
+			}
+		}
+	} else if (n<0 && errno!=ENOENT) {
+		LM_ERR("FIFO stat failed: %s\n", strerror(errno));
+		goto error;
+	}
+
+	return;
+error:
+	return;
+}
 
 static int jsonrpc_dispatch(sip_msg_t* msg, char* s1, char* s2)
 {
@@ -979,7 +1074,7 @@ send_reply:
 }
 
 
-static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2)
+static int jsonrpc_exec_ex(str *cmd, str *rpath)
 {
 	rpc_export_t* rpce;
 	jsonrpc_ctx_t* ctx;
@@ -988,10 +1083,7 @@ static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2)
 	str val;
 	str scmd;
 
-	if(fixup_get_svalue(msg, (gparam_t*)cmd, &scmd)<0 || scmd.len<=0) {
-		LM_ERR("cannot get the rpc command parameter\n");
-		return -1;
-	}
+	scmd = *cmd;
 
 	/* initialize jsonrpc context */
 	ctx = &_jsonrpc_ctx;
@@ -1028,6 +1120,27 @@ static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2)
 		LM_ERR("unsupported jsonrpc version [%.*s]\n", val.len, val.s);
 		goto send_reply;
 	}
+	/* reply name */
+	if(rpath!=NULL) {
+		if(rpath->s==NULL || rpath->len<=0) {
+			LM_ERR("empty buffer to store the reply name\n");
+			goto send_reply;
+		}
+		nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "reply_name");
+		if(nj==NULL) {
+			LM_ERR("missing reply_name field in request\n");
+			goto send_reply;
+		}
+		val.s = nj->valuestring;
+		val.len = strlen(val.s);
+		if(val.len>=rpath->len) {
+			LM_ERR("no space to store reply_name field\n");
+			goto send_reply;
+		}
+		strncpy(rpath->s, val.s, val.len);
+		rpath->s[val.len] = 0;
+		rpath->len = val.len;
+	}
 	/* run jsonrpc command */
 	nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "method");
 	if(nj==NULL) {
@@ -1062,6 +1175,16 @@ send_reply:
 	return 1;
 }
 
+static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2)
+{
+	str scmd;
+
+	if(fixup_get_svalue(msg, (gparam_t*)cmd, &scmd)<0 || scmd.len<=0) {
+		LM_ERR("cannot get the rpc command parameter\n");
+		return -1;
+	}
+	return jsonrpc_exec_ex(&scmd, NULL);
+}
 /**
  *
  */
@@ -1153,3 +1276,446 @@ static int jsonrpc_pv_parse_jrpl_name(pv_spec_t *sp, str *in)
 	}
 	return 0;
 }
+
+/* FIFO TRANSPORT */
+
+/*! \brief Initialize fifo transport */
+static int jsonrpc_init_fifo_file(void)
+{
+	int n;
+	struct stat filestat;
+
+	/* checking the jsonrpc_fifo module param */
+	if (jsonrpc_fifo==NULL || *jsonrpc_fifo == 0) {
+		jsonrpc_fifo=NULL;
+		LM_DBG("No fifo configured\n");
+		return 0;
+	}
+
+	LM_DBG("testing if fifo file exists ...\n");
+	n=stat(jsonrpc_fifo, &filestat);
+	if (n==0) {
+		/* FIFO exist, delete it (safer) if no config check */
+		if(config_check==0) {
+			if (unlink(jsonrpc_fifo)<0){
+				LM_ERR("Cannot delete old fifo (%s): %s\n",
+					jsonrpc_fifo, strerror(errno));
+				return -1;
+			}
+		}
+	} else if (n<0 && errno!=ENOENT){
+		LM_ERR("MI FIFO stat failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	/* checking the fifo_reply_dir param */
+	if(!jsonrpc_fifo_reply_dir || *jsonrpc_fifo_reply_dir == 0) {
+		LM_ERR("fifo_reply_dir parameter is empty\n");
+		return -1;
+	}
+
+	/* Check if the directory for the reply fifo exists */
+	n = stat(jsonrpc_fifo_reply_dir, &filestat);
+	if(n < 0){
+		LM_ERR("Directory stat for MI Fifo reply failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	if(S_ISDIR(filestat.st_mode) == 0){
+		LM_ERR("fifo_reply_dir parameter is not a directory\n");
+		return -1;
+	}
+
+	/* check fifo_mode */
+	if(!jsonrpc_fifo_mode){
+		LM_WARN("cannot specify fifo_mode = 0, forcing it to rw-------\n");
+		jsonrpc_fifo_mode = S_IRUSR | S_IWUSR;
+	}
+
+	if (jsonrpc_fifo_uid_s){
+		if (user2uid(&jsonrpc_fifo_uid, &jsonrpc_fifo_gid, jsonrpc_fifo_uid_s)<0){
+			LM_ERR("Bad user name %s\n", jsonrpc_fifo_uid_s);
+			return -1;
+		}
+	}
+
+	if (jsonrpc_fifo_gid_s){
+		if (group2gid(&jsonrpc_fifo_gid, jsonrpc_fifo_gid_s)<0){
+			LM_ERR("Bad group name %s\n", jsonrpc_fifo_gid_s);
+			return -1;
+		}
+	}
+
+	/* add space for one extra process */
+	register_procs(1);
+
+	/* add child to update local config framework structures */
+	cfg_register_child(1);
+
+	return 0;
+}
+
+
+static int  jsonrpc_fifo_read = 0;
+static int  jsonrpc_fifo_write = 0;
+#define JSONRPC_MAX_FILENAME	128
+static char *jsonrpc_reply_fifo_s = NULL;
+static int jsonrpc_reply_fifo_len = 0;
+
+/*! \brief Initialize Fifo server */
+FILE *jsonrpc_init_fifo_server(char *fifo_name, int fifo_mode,
+						int fifo_uid, int fifo_gid, char* fifo_reply_dir)
+{
+	FILE *fifo_stream;
+	long opt;
+
+	/* create FIFO ... */
+	if ((mkfifo(fifo_name, fifo_mode)<0)) {
+		LM_ERR("Can't create FIFO: %s (mode=%d)\n", strerror(errno), fifo_mode);
+		return 0;
+	}
+
+	LM_DBG("FIFO created @ %s\n", fifo_name );
+
+	if ((chmod(fifo_name, fifo_mode)<0)) {
+		LM_ERR("Can't chmod FIFO: %s (mode=%d)\n", strerror(errno), fifo_mode);
+		return 0;
+	}
+
+	if ((fifo_uid!=-1) || (fifo_gid!=-1)){
+		if (chown(fifo_name, fifo_uid, fifo_gid)<0){
+			LM_ERR("Failed to change the owner/group for %s  to %d.%d; %s[%d]\n",
+				fifo_name, fifo_uid, fifo_gid, strerror(errno), errno);
+			return 0;
+		}
+	}
+
+	LM_DBG("fifo %s opened, mode=%o\n", fifo_name, fifo_mode );
+
+	/* open it non-blocking or else wait here until someone
+	 * opens it for writing */
+	jsonrpc_fifo_read=open(fifo_name, O_RDONLY|O_NONBLOCK, 0);
+	if (jsonrpc_fifo_read<0) {
+		LM_ERR("Can't open fifo %s for reading - fifo_read did not open: %s\n", fifo_name, strerror(errno));
+		return 0;
+	}
+
+	fifo_stream = fdopen(jsonrpc_fifo_read, "r");
+	if (fifo_stream==NULL) {
+		LM_ERR("fdopen failed on %s: %s\n", fifo_name, strerror(errno));
+		return 0;
+	}
+
+	/* make sure the read fifo will not close */
+	jsonrpc_fifo_write=open(fifo_name, O_WRONLY|O_NONBLOCK, 0);
+	if (jsonrpc_fifo_write<0) {
+		LM_ERR("fifo_write did not open: %s\n", strerror(errno));
+		return 0;
+	}
+	/* set read fifo blocking mode */
+	if ((opt=fcntl(jsonrpc_fifo_read, F_GETFL))==-1){
+		LM_ERR("fcntl(F_GETFL) failed: %s [%d]\n", strerror(errno), errno);
+		return 0;
+	}
+	if (fcntl(jsonrpc_fifo_read, F_SETFL, opt & (~O_NONBLOCK))==-1){
+		LM_ERR("cntl(F_SETFL) failed: %s [%d]\n", strerror(errno), errno);
+		return 0;
+	}
+
+	jsonrpc_reply_fifo_s = pkg_malloc(JSONRPC_MAX_FILENAME);
+	if (jsonrpc_reply_fifo_s==NULL) {
+		LM_ERR("no more private memory\n");
+		return 0;
+	}
+
+	/* init fifo reply dir buffer */
+	jsonrpc_reply_fifo_len = strlen(fifo_reply_dir);
+	memcpy( jsonrpc_reply_fifo_s, jsonrpc_fifo_reply_dir, jsonrpc_reply_fifo_len);
+
+	return fifo_stream;
+}
+
+/*! \brief Read input on fifo */
+int jsonrpc_read_stream(char *b, int max, FILE *stream, int *lread)
+{
+	int retry_cnt;
+	int len;
+	char *p;
+	int sstate;
+	int pcount;
+	int pfound;
+	int stype;
+
+	sstate = 0;
+	retry_cnt=0;
+
+	*lread = 0;
+	p = b;
+	pcount = 0;
+	pfound = 0;
+	stype = 0;
+
+	while(1) {
+		len = fread (p, 1, 1, stream);
+		if(len==0) {
+			LM_ERR("fifo server fread failed: %s\n", strerror(errno));
+			/* on Linux, sometimes returns ESPIPE -- give
+			   it few more chances
+			*/
+			if (errno==ESPIPE) {
+				retry_cnt++;
+				if (retry_cnt>4)
+					return -1;
+				continue;
+			}
+			/* interrupted by signal or ... */
+			if ((errno==EINTR)||(errno==EAGAIN))
+				continue;
+			return -1;
+		}
+		if(*p=='"' && (sstate==0 || stype==1)) {
+			if(*lread>0) {
+				if(*(p-1)!='\\') {
+					sstate = (sstate+1) % 2;
+					stype = 1;
+				}
+			} else {
+				sstate = (sstate+1) % 2;
+				stype = 1;
+			}
+		} else if(*p=='\'' && (sstate==0 || stype==2)) {
+			if(*lread>0) {
+				if(*(p-1)!='\\') {
+					sstate = (sstate+1) % 2;
+					stype = 2;
+				}
+			} else {
+				sstate = (sstate+1) % 2;
+				stype = 2;
+			}
+		} else if(*p=='{') {
+			if(sstate==0) {
+				pfound = 1;
+				pcount++;
+			}
+		} else if(*p=='}') {
+			if(sstate==0)
+				pcount--;
+		}
+		*lread = *lread + 1;
+		if(*lread>=max-1) {
+			LM_WARN("input data too large (%d)\n", *lread);
+			return -1;
+		}
+		p++;
+		if(pfound==1 && pcount==0) {
+			*p = 0;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/*! \brief reply fifo security checks:
+ *
+ * checks if fd is a fifo, is not hardlinked and it's not a softlink
+ * opened file descriptor + file name (for soft link check)
+ * \return 0 if ok, <0 if not */
+static int jsonrpc_fifo_check(int fd, char* fname)
+{
+	struct stat fst;
+	struct stat lst;
+	
+	if (fstat(fd, &fst)<0){
+		LM_ERR("security: fstat on %s failed: %s\n", fname, strerror(errno));
+		return -1;
+	}
+	/* check if fifo */
+	if (!S_ISFIFO(fst.st_mode)){
+		LM_ERR("security: %s is not a fifo\n", fname);
+		return -1;
+	}
+	/* check if hard-linked */
+	if (fst.st_nlink>1){
+		LM_ERR("security: fifo_check: %s is hard-linked %d times\n", fname, (unsigned)fst.st_nlink);
+		return -1;
+	}
+
+	/* lstat to check for soft links */
+	if (lstat(fname, &lst)<0){
+		LM_ERR("security: lstat on %s failed: %s\n", fname, strerror(errno));
+		return -1;
+	}
+	if (S_ISLNK(lst.st_mode)){
+		LM_ERR("security: fifo_check: %s is a soft link\n", fname);
+		return -1;
+	}
+	/* if this is not a symbolic link, check to see if the inode didn't
+	 * change to avoid possible sym.link, rm sym.link & replace w/ fifo race
+	 */
+	if ((lst.st_dev!=fst.st_dev)||(lst.st_ino!=fst.st_ino)){
+		LM_ERR("security: fifo_check: inode/dev number differ: %d %d (%s)\n",
+			(int)fst.st_ino, (int)lst.st_ino, fname);
+		return -1;
+	}
+	/* success */
+	return 0;
+}
+
+#define JSONRPC_REPLY_RETRIES 4
+FILE *jsonrpc_open_reply_fifo(str *srpath)
+{
+	int retries=JSONRPC_REPLY_RETRIES;
+	int fifofd;
+	FILE *file_handle;
+	int flags;
+
+	if ( memchr(srpath->s, '.', srpath->len)
+			|| memchr(srpath->s, '/', srpath->len)
+			|| memchr(srpath->s, '\\', srpath->len) ) {
+		LM_ERR("Forbidden reply fifo filename: %.*s\n",
+				srpath->len, srpath->s);
+		return 0;
+	}
+
+	if (jsonrpc_reply_fifo_len + srpath->len + 1 > JSONRPC_MAX_FILENAME) {
+		LM_ERR("Reply fifo filename too long %d\n",
+				jsonrpc_reply_fifo_len + srpath->len);
+		return 0;
+	}
+
+	memcpy(jsonrpc_reply_fifo_s + jsonrpc_reply_fifo_len, srpath->s, srpath->len);
+	jsonrpc_reply_fifo_s[jsonrpc_reply_fifo_len + srpath->len]=0;
+
+
+tryagain:
+	/* open non-blocking to make sure that a broken client will not 
+	 * block the FIFO server forever */
+	fifofd=open( jsonrpc_reply_fifo_s, O_WRONLY | O_NONBLOCK );
+	if (fifofd==-1) {
+		/* retry several times if client is not yet ready for getting
+		   feedback via a reply pipe
+		*/
+		if (errno==ENXIO) {
+			/* give up on the client - we can't afford server blocking */
+			if (retries==0) {
+				LM_ERR("no client at %s\n", jsonrpc_reply_fifo_s );
+				return 0;
+			}
+			/* don't be noisy on the very first try */
+			if (retries != JSONRPC_REPLY_RETRIES)
+				LM_DBG("mi_fifo retry countdown: %d\n", retries );
+			sleep_us( 80000 );
+			retries--;
+			goto tryagain;
+		}
+		/* some other opening error */
+		LM_ERR("open error (%s): %s\n", jsonrpc_reply_fifo_s, strerror(errno));
+		return 0;
+	}
+
+	/* security checks: is this really a fifo?, is 
+	 * it hardlinked? is it a soft link? */
+	if (jsonrpc_fifo_check(fifofd, jsonrpc_reply_fifo_s)<0)
+		goto error;
+
+	/* we want server blocking for big writes */
+	if ( (flags=fcntl(fifofd, F_GETFL, 0))<0) {
+		LM_ERR("pipe (%s): getfl failed: %s\n", jsonrpc_reply_fifo_s, strerror(errno));
+		goto error;
+	}
+	flags&=~O_NONBLOCK;
+	if (fcntl(fifofd, F_SETFL, flags)<0) {
+		LM_ERR("pipe (%s): setfl cntl failed: %s\n", jsonrpc_reply_fifo_s, strerror(errno));
+		goto error;
+	}
+
+	/* create an I/O stream */
+	file_handle=fdopen( fifofd, "w");
+	if (file_handle==NULL) {
+		LM_ERR("open error (%s): %s\n",
+			jsonrpc_reply_fifo_s, strerror(errno));
+		goto error;
+	}
+	return file_handle;
+error:
+	close(fifofd);
+	return 0;
+}
+
+#define JSONRPC_BUF_IN_SIZE	4096
+static void jsonrpc_run_fifo_server(FILE *fifo_stream)
+{
+	FILE *reply_stream;
+	char buf_in[JSONRPC_BUF_IN_SIZE];
+	char buf_rpath[128];
+	int lread;
+	str scmd;
+	str srpath;
+	int nw;
+
+	while(1) {
+		/* update the local config framework structures */
+		cfg_update();
+
+		reply_stream = NULL;
+		lread = 0;
+		if(jsonrpc_read_stream(buf_in, JSONRPC_BUF_IN_SIZE,
+					fifo_stream, &lread)<0 || lread<=0) {
+			LM_DBG("failed to get the json document from fifo stream\n");
+			continue;
+		}
+		scmd.s = buf_in;
+		scmd.len = lread;
+		trim(&scmd);
+		LM_DBG("preparing to execute fifo jsonrpc [%.*s]\n", scmd.len, scmd.s);
+		srpath.s = buf_rpath;
+		srpath.len = 128;
+		if(jsonrpc_exec_ex(&scmd, &srpath)<0) {
+			LM_ERR("failed to execute the json document from fifo stream\n");
+			continue;
+		}
+
+		LM_DBG("command executed - result: [%.*s] [%d] [%p] [%.*s]\n",
+				srpath.len, srpath.s,
+				_jsonrpc_plain_reply.rcode,
+				_jsonrpc_plain_reply.rbody.s,
+				_jsonrpc_plain_reply.rbody.len, _jsonrpc_plain_reply.rbody.s);
+		if(srpath.len>0) {
+			reply_stream = jsonrpc_open_reply_fifo(&srpath);
+			if (reply_stream==NULL) {
+				LM_ERR("cannot open reply fifo: %.*s\n", srpath.len, srpath.s);
+				continue;
+			}
+			nw = fwrite(_jsonrpc_plain_reply.rbody.s, 1,
+						_jsonrpc_plain_reply.rbody.len, reply_stream);
+			if(nw < _jsonrpc_plain_reply.rbody.len) {
+				LM_ERR("failed to write the reply to fifo: %d out of %d\n",
+						nw, _jsonrpc_plain_reply.rbody.len);
+			}
+			fclose(reply_stream);
+
+		}
+	}
+	return;
+}
+
+static void jsonrpc_fifo_process(int rank)
+{
+	FILE *fifo_stream;
+
+	LM_DBG("new process with pid = %d created\n",getpid());
+
+	fifo_stream = jsonrpc_init_fifo_server( jsonrpc_fifo, jsonrpc_fifo_mode,
+		jsonrpc_fifo_uid, jsonrpc_fifo_gid, jsonrpc_fifo_reply_dir);
+	if ( fifo_stream==NULL ) {
+		LM_CRIT("The function jsonrpc_init_fifo_server returned with error!!!\n");
+		exit(-1);
+	}
+
+	jsonrpc_run_fifo_server( fifo_stream );
+
+	LM_CRIT("the function jsonroc_fifo_server returned with error!!!\n");
+	exit(-1);
+}