Browse Source

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 10 years ago
parent
commit
adde641c3b
3 changed files with 968 additions and 21 deletions
  1. 174 6
      modules/jsonrpc-s/README
  2. 216 3
      modules/jsonrpc-s/doc/jsonrpc-s_admin.xml
  3. 578 12
      modules/jsonrpc-s/jsonrpc-s_mod.c

+ 174 - 6
modules/jsonrpc-s/README

@@ -29,17 +29,36 @@ Daniel-Constantin Mierla
         3. Parameters
         3. Parameters
 
 
               3.1. pretty_format (int)
               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. Functions
 
 
               4.1. jsonrpc_dispatch()
               4.1. jsonrpc_dispatch()
               4.2. jsonrpc_exec(cmd)
               4.2. jsonrpc_exec(cmd)
 
 
+        5. JSONRPC Transports
+
+              5.1. JSONRPC Over HTTP
+              5.2. JSONRPC Over FIFO
+
    List of Examples
    List of Examples
 
 
    1.1. Set pretty_format parameter
    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
 Chapter 1. Admin Guide
 
 
@@ -57,21 +76,35 @@ Chapter 1. Admin Guide
    3. Parameters
    3. Parameters
 
 
         3.1. pretty_format (int)
         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. Functions
 
 
         4.1. jsonrpc_dispatch()
         4.1. jsonrpc_dispatch()
         4.2. jsonrpc_exec(cmd)
         4.2. jsonrpc_exec(cmd)
 
 
+   5. JSONRPC Transports
+
+        5.1. JSONRPC Over HTTP
+        5.2. JSONRPC Over FIFO
+
 1. Overview
 1. Overview
 
 
    1.1. Limitations
    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
    tailored for the needs of Kamailio. It implements the Kamailio RPC
    interface over JSON-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.
    Read the documentation of the xHTTP module for more details.
 
 
 1.1. Limitations
 1.1. Limitations
@@ -102,6 +135,12 @@ Chapter 1. Admin Guide
 3. Parameters
 3. Parameters
 
 
    3.1. pretty_format (int)
    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)
 3.1. pretty_format (int)
 
 
@@ -114,6 +153,80 @@ Chapter 1. Admin Guide
 modparam("jsonrpc-s", "pretty_format", 1)
 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. Functions
 
 
    4.1. jsonrpc_dispatch()
    4.1. jsonrpc_dispatch()
@@ -123,7 +236,7 @@ modparam("jsonrpc-s", "pretty_format", 1)
 
 
    Handle the JSONRPC request and generate a response.
    Handle the JSONRPC request and generate a response.
 
 
-   Example 1.2. jsonrpc_dispatch usage
+   Example 1.8. jsonrpc_dispatch usage
 ...
 ...
 #!KAMAILIO
 #!KAMAILIO
 
 
@@ -174,7 +287,62 @@ event_route[xhttp:request] {
    dynamic string with variables. The result of the command can be
    dynamic string with variables. The result of the command can be
    accessed via $jsonrpl(key) pseudo variables.
    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}');
 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>
 	<section>
 	<title>Overview</title>
 	<title>Overview</title>
 	<para>
 	<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;
 		tailored for the needs of &kamailio;. It implements the &kamailio;
 		RPC interface over JSON-RPC.
 		RPC interface over JSON-RPC.
+	</para>
 	<para>
 	<para>
+		The specification for JSON-RPC is available at:
+		<ulink url="http://www.jsonrpc.org/specification">http://www.jsonrpc.org/specification</ulink>.
 	</para>
 	</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.
 		Read the documentation of the xHTTP module for more details.
 	</para>
 	</para>
 
 
@@ -78,7 +82,7 @@
 	</section>
 	</section>
 	<section>
 	<section>
 	<title>Parameters</title>
 	<title>Parameters</title>
-	<section>
+	<section id="jsonrpc-s.p.pretty_format">
 		<title><varname>pretty_format</varname> (int)</title>
 		<title><varname>pretty_format</varname> (int)</title>
 		<para>
 		<para>
 			Pretty format for JSON-RPC response document. 
 			Pretty format for JSON-RPC response document. 
@@ -97,6 +101,143 @@ modparam("jsonrpc-s", "pretty_format", 1)
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</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>
 
 
 	<section>
 	<section>
@@ -178,5 +319,77 @@ jsonrpc_exec({"jsonrpc": "2.0", "method": "dispatcher.reload", "id": 1}');
 	</section>
 	</section>
 
 
 	</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>
 </chapter>
 
 

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

@@ -23,12 +23,19 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <stdarg.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 "../../ver.h"
 #include "../../trim.h"
 #include "../../trim.h"
+#include "../../pt.h"
 #include "../../sr_module.h"
 #include "../../sr_module.h"
 #include "../../mod_fix.h"
 #include "../../mod_fix.h"
 #include "../../nonsip_hooks.h"
 #include "../../nonsip_hooks.h"
+#include "../../cfg/cfg_struct.h"
 #include "../../modules/xhttp/api.h"
 #include "../../modules/xhttp/api.h"
 
 
 #include "jsonrpc-s_mod.h"
 #include "jsonrpc-s_mod.h"
@@ -53,8 +60,19 @@ MODULE_VERSION
 #define jsonrpc_malloc	pkg_malloc
 #define jsonrpc_malloc	pkg_malloc
 #define jsonrpc_free	pkg_free
 #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;
 static int jsonrpc_pretty_format = 0;
 
 
@@ -62,9 +80,12 @@ static int jsonrpc_register_rpc(void);
 
 
 static int mod_init(void);
 static int mod_init(void);
 static int child_init(int rank);
 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_dispatch(sip_msg_t* msg, char* s1, char* s2);
 static int jsonrpc_exec(sip_msg_t* msg, char* cmd, 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.
 /** The context of the jsonrpc request being processed.
  *
  *
@@ -95,7 +116,15 @@ static cmd_export_t cmds[] = {
 };
 };
 
 
 static param_export_t params[] = {
 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}
 	{0, 0, 0}
 };
 };
 
 
@@ -120,7 +149,7 @@ struct module_exports exports= {
 	0,			/* extra processes */
 	0,			/* extra processes */
 	mod_init,	/* module initialization function */
 	mod_init,	/* module initialization function */
 	0,
 	0,
-	0,
+	mod_destroy,/* module destroy function */
 	child_init	/* per-child init function */
 	child_init	/* per-child init function */
 };
 };
 
 
@@ -317,6 +346,7 @@ static int jsonrpc_send(jsonrpc_ctx_t* ctx)
 		} else {
 		} else {
 			jsonrpc_set_plain_reply(ctx->http_code, &ctx->http_text, &rbuf,
 			jsonrpc_set_plain_reply(ctx->http_code, &ctx->http_text, &rbuf,
 					ctx->jrpl->free_fn);
 					ctx->jrpl->free_fn);
+			rbuf.s=NULL;
 		}
 		}
 	} else {
 	} else {
 		if(ctx->msg) {
 		if(ctx->msg) {
@@ -864,9 +894,25 @@ static void jsonrpc_clean_context(jsonrpc_ctx_t* ctx)
 static int mod_init(void)
 static int mod_init(void)
 {
 {
 	/* bind the XHTTP API */
 	/* 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));
 	memset(&func_param, 0, sizeof(func_param));
@@ -892,12 +938,61 @@ static int mod_init(void)
 
 
 static int child_init(int rank)
 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)
 	if(rank==PROC_MAIN || rank==PROC_TCP_MAIN)
+	{
 		return 0; /* do nothing for the main process */
 		return 0; /* do nothing for the main process */
+	}
 
 
 	return 0;
 	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)
 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;
 	rpc_export_t* rpce;
 	jsonrpc_ctx_t* ctx;
 	jsonrpc_ctx_t* ctx;
@@ -988,10 +1083,7 @@ static int jsonrpc_exec(sip_msg_t* msg, char* cmd, char* s2)
 	str val;
 	str val;
 	str scmd;
 	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 */
 	/* initialize jsonrpc context */
 	ctx = &_jsonrpc_ctx;
 	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);
 		LM_ERR("unsupported jsonrpc version [%.*s]\n", val.len, val.s);
 		goto send_reply;
 		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 */
 	/* run jsonrpc command */
 	nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "method");
 	nj = srjson_GetObjectItem(ctx->jreq, ctx->jreq->root, "method");
 	if(nj==NULL) {
 	if(nj==NULL) {
@@ -1062,6 +1175,16 @@ send_reply:
 	return 1;
 	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;
 	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);
+}