Browse code

Added jsonrpc-c module, providing a client interface to json-rpc services over netstrings.

Matthew Williams authored on 22/08/2011 21:09:01
Showing 16 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+*.d
1
+*.o
2
+*.so
3
+*.lst
4
+*.tar.gz
5
+*.swp
6
+*.swo
7
+tags
8
+TAGS
9
+doc/*.txt
0 10
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+#
1
+# jsonrpc module makefile
2
+#
3
+# 
4
+# WARNING: do not run this directly, it should be run by the master Makefile
5
+
6
+include ../../Makefile.defs
7
+auto_gen=
8
+NAME=jsonrpc-c.so
9
+LIBS=-lm -levent
10
+
11
+DEFS+=-I/usr/include/json -I$(LOCALBASE)/include/json \
12
+       -I$(LOCALBASE)/include
13
+LIBS+=-L$(SYSBASE)/include/lib -L$(LOCALBASE)/lib -ljson
14
+ 
15
+DEFS+=-DOPENSER_MOD_INTERFACE
16
+
17
+SERLIBPATH=../../lib
18
+include ../../Makefile.modules
0 19
new file mode 100644
... ...
@@ -0,0 +1,166 @@
0
+jsonrpc-c (client) Module
1
+
2
+Matthew Williams
3
+
4
+   <matthew@flowroute.com>
5
+
6
+Edited by
7
+
8
+Jordan Levy
9
+
10
+   <jordan@flowroute.com>
11
+
12
+   Copyright © 2011 Flowroute LLC (flowroute.com)
13
+     __________________________________________________________________
14
+
15
+   Table of Contents
16
+
17
+   1. Admin Guide
18
+
19
+        1. Overview
20
+        2. Dependencies
21
+
22
+              2.1. Kamailio Modules
23
+              2.2. External Libraries or Applications
24
+
25
+        3. Exported Parameters
26
+
27
+              3.1. servers (string)
28
+
29
+        4. Exported Functions
30
+
31
+              4.1. jsonrpc_notification(method, parameters)
32
+              4.2. jsonrpc_request(method, parameters, return_route,
33
+                      error_route, result_var)
34
+
35
+   List of Examples
36
+
37
+   1.1. Set servers parameter
38
+   1.2. jsonrpc_notification usage
39
+   1.3. jsonrpc_request usage
40
+
41
+Chapter 1. Admin Guide
42
+
43
+   Table of Contents
44
+
45
+   1. Overview
46
+   2. Dependencies
47
+
48
+        2.1. Kamailio Modules
49
+        2.2. External Libraries or Applications
50
+
51
+   3. Exported Parameters
52
+
53
+        3.1. servers (string)
54
+
55
+   4. Exported Functions
56
+
57
+        4.1. jsonrpc_notification(method, parameters)
58
+        4.2. jsonrpc_request(method, parameters, return_route,
59
+                error_route, result_var)
60
+
61
+1. Overview
62
+
63
+   This module provides access to json-rpc services (operating over
64
+   TCP/Netstrings).
65
+
66
+   This module uses t_suspend() and t_continue() from the TM module.
67
+
68
+   Note that after invoking an asyncronous operation, the processing will
69
+   continue later, in another application process. Therefore, do not rely
70
+   on variables stored in private memory, use shared memory if you want to
71
+   get values after the processing is resumend (e.g., $shv(...) or htable
72
+   $sht(...)).
73
+
74
+2. Dependencies
75
+
76
+   2.1. Kamailio Modules
77
+   2.2. External Libraries or Applications
78
+
79
+2.1. Kamailio Modules
80
+
81
+   The following modules must be loaded before this module:
82
+     * tm - transaction management.
83
+
84
+2.2. External Libraries or Applications
85
+
86
+   The following libraries or applications must be installed before
87
+   running Kamailio with this module loaded:
88
+     * libjson - http://metaparadigm.com/json-c/
89
+
90
+3. Exported Parameters
91
+
92
+   3.1. servers (string)
93
+
94
+3.1. servers (string)
95
+
96
+   The servers providing the remote jsonrpc service. Format is
97
+   "host1:port1,priority1 host2:port2,priority2". Requests to servers of
98
+   the same priority will be distributed evenly (round robin). Server
99
+   groups with higher priority are used first.
100
+
101
+   Example 1.1. Set servers parameter
102
+...
103
+modparam("jsonrpc", "servers", "localhost:9999,2 10.10.0.1:9999,2 backup.server:
104
+9999,1")
105
+...
106
+
107
+4. Exported Functions
108
+
109
+   4.1. jsonrpc_notification(method, parameters)
110
+   4.2. jsonrpc_request(method, parameters, return_route, error_route,
111
+          result_var)
112
+
113
+4.1.  jsonrpc_notification(method, parameters)
114
+
115
+   Invokes the remote 'method' with the given 'parameters' as a
116
+   notification. Unlike jsonrpc_request (below), notifications do not
117
+   receive a response. Script processing continues in the usual fashion as
118
+   soon as the notification has been sent.
119
+
120
+   The method and parameters can be a static string or dynamic string
121
+   value with config variables.
122
+
123
+   Example 1.2. jsonrpc_notification usage
124
+...
125
+jsonrpc_notification("update_user", "{'id': 1234, 'name': 'Petros'}")
126
+...
127
+
128
+4.2.  jsonrpc_request(method, parameters, return_route, error_route,
129
+result_var)
130
+
131
+   Invokes the remote 'method' with the given 'parameters'. When the
132
+   response is received, continues processing of the SIP request with the
133
+   route[return_route]. If a timeout occurs, no servers can be reached, or
134
+   a jsonrpc error message is received, continues process at
135
+   route[error_route]. In this case, the result_var will contain one of
136
+   "timeout", "failure", or the error message received back from the
137
+   jsonrpc server.
138
+
139
+   The method, parameters, return_route, and error_route can be a static
140
+   string or a dynamic string value with config variables.
141
+
142
+   Since the SIP request handling is resumed in another process, the
143
+   config file execution is lost. As mentioned above, only shared
144
+   variables ($shv, etc) should be used for any value that will be needed
145
+   when the script is resumed.
146
+
147
+   The result is stored in the pseudo-variable 'result_var'. Since this
148
+   variable is set after the response is received, it is possible to use a
149
+   $var for this parameter.
150
+
151
+   Example 1.3. jsonrpc_request usage
152
+...
153
+jsonrpc_request("get_user", "{'id': 1234}", "RESPONSE", "ERROR", "$var(result)")
154
+;
155
+...
156
+route[RESPONSE] {
157
+        xlog("Result received: $var(result)");
158
+        ...
159
+}
160
+...
161
+route[ERROR] {
162
+        xlog("Error received: $var(result)");
163
+        ...
164
+}
165
+...
0 166
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+* "Reliable" Notifications (implement using requests, and failover on error; ignore non-error responses) ?
0 1
new file mode 100644
... ...
@@ -0,0 +1,4 @@
0
+docs = jsonrpc.xml
1
+
2
+docbook_dir = ../../../docbook
3
+include $(docbook_dir)/Makefile.module
0 4
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+<?xml version="1.0" encoding='ISO-8859-1'?>
1
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
2
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
3
+
4
+<!-- Include general documentation entities -->
5
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
6
+%docentities;
7
+
8
+]>
9
+
10
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
11
+    <bookinfo>
12
+	<title>jsonrpc-c (client) Module</title>
13
+	<productname class="trade">sip-router.org</productname>
14
+	<authorgroup>
15
+	    <author>
16
+		<firstname>Matthew</firstname>
17
+		<surname>Williams</surname>
18
+		<email>matthew@flowroute.com</email>
19
+	    </author>
20
+	    <editor>
21
+			<firstname>Jordan</firstname>
22
+			<surname>Levy</surname>
23
+			<email>jordan@flowroute.com</email>
24
+	    </editor>
25
+	</authorgroup>
26
+	<copyright>
27
+	    <year>2011</year>
28
+	    <holder>Flowroute LLC (flowroute.com)</holder>
29
+	</copyright>
30
+    </bookinfo>
31
+    <toc></toc>
32
+    
33
+    <xi:include href="jsonrpc_admin.xml"/>
34
+    
35
+    
36
+</book>
0 37
new file mode 100644
... ...
@@ -0,0 +1,154 @@
0
+<?xml version="1.0" encoding='ISO-8859-1'?>
1
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
2
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
3
+
4
+<!-- Include general documentation entities -->
5
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
6
+%docentities;
7
+
8
+]>
9
+<!-- Module User's Guide -->
10
+
11
+<chapter>
12
+
13
+	<title>&adminguide;</title>
14
+
15
+	<section>
16
+		<title>Overview</title>
17
+		<para>
18
+			This module provides access to json-rpc services (operating over TCP/Netstrings).
19
+		</para>
20
+		<para>
21
+			This module uses t_suspend() and t_continue() from the TM module.
22
+		</para>
23
+		<para>
24
+			Note that after invoking an asyncronous operation, the processing
25
+			will continue later, in another application process. Therefore, do not
26
+			rely on variables stored in private memory, use shared memory if you
27
+			want to get values after the processing is resumend (e.g., $shv(...)
28
+			or htable $sht(...)).
29
+		</para>
30
+	</section>
31
+
32
+	<section>
33
+		<title>Dependencies</title>
34
+		<section>
35
+			<title>&kamailio; Modules</title>
36
+			<para>
37
+				The following modules must be loaded before this module:
38
+				<itemizedlist>
39
+					<listitem>
40
+						<para>
41
+							<emphasis>tm</emphasis> - transaction management.
42
+						</para>
43
+					</listitem>
44
+				</itemizedlist>
45
+			</para>
46
+		</section>
47
+		<section>
48
+			<title>External Libraries or Applications</title>
49
+			<para>
50
+				The following libraries or applications must be installed before running
51
+				&kamailio; with this module loaded:
52
+				<itemizedlist>
53
+					<listitem>
54
+						<para>
55
+							<emphasis>libjson</emphasis> - http://metaparadigm.com/json-c/
56
+						</para>
57
+					</listitem>
58
+				</itemizedlist>
59
+			</para>
60
+		</section>
61
+	</section>
62
+	<section>
63
+		<title>Exported Parameters</title>
64
+		<section>
65
+			<title><varname>servers</varname> (string)</title>
66
+			<para>
67
+				The servers providing the remote jsonrpc service. Format is "host1:port1,priority1 host2:port2,priority2". Requests to servers of the same priority will be distributed evenly (round robin). Server groups with higher priority are used first. 
68
+			</para>
69
+			<example>
70
+				<title>Set <varname>servers</varname> parameter</title>
71
+				<programlisting format="linespecific">
72
+...
73
+modparam("jsonrpc", "servers", "localhost:9999,2 10.10.0.1:9999,2 backup.server:9999,1")
74
+...
75
+				</programlisting>
76
+			</example>
77
+		</section>
78
+	</section>
79
+	<section>
80
+		<title>Exported Functions</title>
81
+		<section>
82
+			<title>
83
+				<function moreinfo="none">jsonrpc_notification(method, parameters)</function>
84
+			</title>
85
+			<para>
86
+				Invokes the remote 'method' with the given 'parameters' as a notification.
87
+				Unlike jsonrpc_request (below), notifications do not receive a response. 
88
+				Script processing continues in the usual fashion as soon as the notification
89
+				has been sent.
90
+			</para>
91
+			<para>
92
+				The method and parameters can be a static string or dynamic string value with 
93
+				config variables.
94
+			</para>
95
+			<example>
96
+				<title><function>jsonrpc_notification</function> usage</title>
97
+				<programlisting format="linespecific">
98
+...
99
+jsonrpc_notification("update_user", "{'id': 1234, 'name': 'Petros'}")
100
+...
101
+				</programlisting>
102
+			</example>
103
+		</section>
104
+
105
+		<section>
106
+			<title>
107
+				<function moreinfo="none">jsonrpc_request(method, parameters, return_route, error_route, result_var)</function>
108
+			</title>
109
+			<para>
110
+				Invokes the remote 'method' with the given 'parameters'. 
111
+				When the response is received, continues processing of the SIP request
112
+				with the route[return_route]. If a timeout occurs, no servers can be reached,
113
+				or a jsonrpc error message is received, continues process at route[error_route].
114
+				In this case, the result_var will contain one of "timeout", "failure", or the error
115
+				message received back from the jsonrpc server.
116
+			</para>
117
+			<para>
118
+				The method, parameters, return_route, and error_route can be a static string or 
119
+				a dynamic string value with config variables.
120
+			</para>
121
+			<para>
122
+				Since the SIP request handling is resumed in another process,
123
+				the config file execution is lost. As mentioned above, only 
124
+				shared variables ($shv, etc) should be used for any value that
125
+				will be needed when the script is resumed.
126
+			</para>
127
+			<para>
128
+				The result is stored in the pseudo-variable 'result_var'. Since this 
129
+				variable is set <emphasis>after</emphasis> the response is received,
130
+				it is possible to use a $var for this parameter.
131
+			</para>
132
+			<example>
133
+				<title><function>jsonrpc_request</function> usage</title>
134
+				<programlisting format="linespecific">
135
+...
136
+jsonrpc_request("get_user", "{'id': 1234}", "RESPONSE", "ERROR", "$var(result)");
137
+...
138
+route[RESPONSE] {
139
+	xlog("Result received: $var(result)");
140
+	...
141
+}
142
+...
143
+route[ERROR] {
144
+	xlog("Error received: $var(result)");
145
+	...
146
+}
147
+...
148
+				</programlisting>
149
+			</example>
150
+		</section>
151
+	</section>
152
+</chapter>
153
+
0 154
new file mode 100644
... ...
@@ -0,0 +1,174 @@
0
+/**
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2011 Flowroute LLC (flowroute.com)
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * This file is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ *
13
+ * This file is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ *
22
+ */
23
+
24
+#include <stdio.h>
25
+#include <stdlib.h>
26
+#include <errno.h>
27
+#include <string.h>
28
+
29
+#include "../../sr_module.h"
30
+#include "../../mem/mem.h"
31
+
32
+#include "jsonrpc.h"
33
+
34
+
35
+jsonrpc_request_t * request_table[JSONRPC_DEFAULT_HTABLE_SIZE] = {0};
36
+int next_id = 1;
37
+
38
+jsonrpc_request_t* get_request(int id);
39
+int store_request(jsonrpc_request_t* req);
40
+
41
+
42
+jsonrpc_request_t* build_jsonrpc_request(char *method, json_object *params, char *cbdata, int (*cbfunc)(json_object*, char*, int))
43
+{
44
+	if (next_id>JSONRPC_MAX_ID) {
45
+		next_id = 1;
46
+	} else {
47
+		next_id++;
48
+	}
49
+
50
+	jsonrpc_request_t *req = pkg_malloc(sizeof(jsonrpc_request_t));
51
+	if (!req) {
52
+		LM_ERR("Out of memory!");
53
+		return 0;
54
+	}
55
+	req->id = next_id;
56
+	req->cbfunc = cbfunc;
57
+	req->cbdata = cbdata;
58
+	req->next = NULL;
59
+	req->timer_ev = NULL;
60
+	if (!store_request(req))
61
+		return 0;
62
+
63
+	req->payload = json_object_new_object();
64
+
65
+	json_object_object_add(req->payload, "id", json_object_new_int(next_id));
66
+	json_object_object_add(req->payload, "jsonrpc", json_object_new_string("2.0"));
67
+	json_object_object_add(req->payload, "method", json_object_new_string(method));
68
+	json_object_object_add(req->payload, "params", params);
69
+
70
+	return req;
71
+}
72
+
73
+json_object* build_jsonrpc_notification(char *method, json_object *params) 
74
+{
75
+	json_object *req = json_object_new_object();
76
+	json_object_object_add(req, "jsonrpc", json_object_new_string("2.0"));
77
+	json_object_object_add(req, "method", json_object_new_string(method));
78
+	json_object_object_add(req, "params", params);
79
+
80
+	return req; 
81
+}
82
+
83
+
84
+int handle_jsonrpc_response(json_object *response)
85
+{
86
+	jsonrpc_request_t *req;	
87
+	json_object *_id = json_object_object_get(response, "id");
88
+	int id = json_object_get_int(_id);
89
+	
90
+	if (!(req = get_request(id))) {
91
+		json_object_put(response);
92
+		return -1;
93
+	}
94
+
95
+	json_object *result = json_object_object_get(response, "result");
96
+	
97
+	if (result) {
98
+		req->cbfunc(result, req->cbdata, 0);
99
+	} else {
100
+		json_object *error = json_object_object_get(response, "error");
101
+		if (error) {
102
+			req->cbfunc(error, req->cbdata, 1);
103
+		} else {
104
+			LM_ERR("Response received with neither a result nor an error.\n");
105
+			return -1;
106
+		}
107
+	}
108
+	
109
+	if (req->timer_ev) {
110
+		close(req->timerfd);
111
+		event_del(req->timer_ev);
112
+		pkg_free(req->timer_ev);
113
+	} else {
114
+		LM_ERR("No timer for req id %d\n", id);
115
+	}
116
+	pkg_free(req);
117
+	return 1;
118
+}
119
+
120
+int id_hash(int id) {
121
+	return (id % JSONRPC_DEFAULT_HTABLE_SIZE);
122
+}
123
+
124
+jsonrpc_request_t* get_request(int id) {
125
+	int key = id_hash(id);
126
+	jsonrpc_request_t *req, *prev_req = NULL;
127
+	req = request_table[key];
128
+	
129
+	while (req && req->id != id) {
130
+		prev_req = req;
131
+		if (!(req = req->next)) {
132
+			break;
133
+		};
134
+	}
135
+	
136
+	if (req && req->id == id) {
137
+		if (prev_req != NULL) {
138
+			prev_req-> next = req->next;
139
+		} else {
140
+			request_table[key] = NULL;
141
+		}
142
+		return req;
143
+	}
144
+	return 0;
145
+}
146
+
147
+void void_jsonrpc_request(int id) {
148
+	get_request(id);
149
+}
150
+
151
+int store_request(jsonrpc_request_t* req) {
152
+	int key = id_hash(req->id);
153
+	jsonrpc_request_t* existing;
154
+
155
+	if ((existing = request_table[key])) { /* collision */
156
+		jsonrpc_request_t* i;
157
+		for(i=existing; i; i=i->next) {
158
+			if (i == NULL) {
159
+				i = req;
160
+				LM_ERR("!!!!!!!");
161
+				return 1;
162
+			}
163
+			if (i->next == NULL) {
164
+				i->next = req;
165
+				return 1;
166
+			}
167
+		}
168
+	} else {
169
+		request_table[key] = req;
170
+	}
171
+	return 1;
172
+}
173
+
0 174
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+/**
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2011 Flowroute LLC (flowroute.com)
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * This file is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ *
13
+ * This file is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ *
22
+ */
23
+
24
+#ifndef _JSONRPC_H_
25
+#define _JSONRPC_H_
26
+
27
+#define JSONRPC_DEFAULT_HTABLE_SIZE 500
28
+#define JSONRPC_MAX_ID 1000000
29
+
30
+#define JSONRPC_INTERNAL_SERVER_ERROR -32603
31
+
32
+#include <json.h>
33
+#include <event.h>
34
+
35
+typedef struct jsonrpc_request jsonrpc_request_t;
36
+
37
+struct jsonrpc_request {
38
+	int id, timerfd;
39
+	jsonrpc_request_t *next;
40
+	int (*cbfunc)(json_object*, char*, int);
41
+	char *cbdata;
42
+	json_object *payload;
43
+	struct event *timer_ev; 
44
+};
45
+
46
+json_object* build_jsonrpc_notification(char *method, json_object *params); 
47
+jsonrpc_request_t* build_jsonrpc_request(char *method, json_object *params, char *cbdata, int (*cbfunc)(json_object*, char*, int));
48
+int handle_jsonrpc_response(json_object *response);
49
+void void_jsonrpc_request(int id);
50
+#endif /* _JSONRPC_H_ */
51
+
0 52
new file mode 100644
... ...
@@ -0,0 +1,557 @@
0
+/**
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2011 Flowroute LLC (flowroute.com)
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * This file is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ *
13
+ * This file is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ *
22
+ */
23
+
24
+#include <stdio.h>
25
+#include <stdlib.h>
26
+#include <errno.h>
27
+#include <string.h>
28
+#include <fcntl.h>
29
+#include <event.h>
30
+#include <sys/timerfd.h>
31
+
32
+#include "../../sr_module.h"
33
+#include "../../route.h"
34
+#include "../../route_struct.h"
35
+#include "../../lvalue.h"
36
+#include "../tm/tm_load.h"
37
+
38
+#include "jsonrpc_io.h"
39
+#include "jsonrpc.h"
40
+#include "netstring.h"
41
+
42
+#define CHECK_MALLOC_VOID(p)  if(!p) {LM_ERR("Out of memory!"); return;}
43
+#define CHECK_MALLOC(p)  if(!p) {LM_ERR("Out of memory!"); return -1;}
44
+
45
+struct jsonrpc_server {
46
+	char *host;
47
+	int  port, socket, status;
48
+	struct jsonrpc_server *next;
49
+	struct event *ev;
50
+	struct itimerspec *timer;
51
+};
52
+
53
+struct jsonrpc_server_group {
54
+	struct jsonrpc_server *next_server;
55
+	int    priority;
56
+	struct jsonrpc_server_group *next_group;
57
+};
58
+
59
+struct tm_binds tmb;
60
+
61
+struct jsonrpc_server_group *server_group;
62
+
63
+void socket_cb(int fd, short event, void *arg);
64
+void cmd_pipe_cb(int fd, short event, void *arg);
65
+int  set_non_blocking(int fd);
66
+int  parse_servers(char *_servers, struct jsonrpc_server_group **group_ptr);
67
+int  connect_servers(struct jsonrpc_server_group *group);
68
+int  connect_server(struct jsonrpc_server *server);
69
+int  handle_server_failure(struct jsonrpc_server *server);
70
+
71
+int jsonrpc_io_child_process(int cmd_pipe, char* _servers)
72
+{
73
+	if (parse_servers(_servers, &server_group) != 0)
74
+	{
75
+		LM_ERR("servers parameter could not be parsed\n");
76
+		return -1;
77
+	}
78
+
79
+	event_init();
80
+	
81
+	struct event pipe_ev;
82
+	set_non_blocking(cmd_pipe);
83
+	event_set(&pipe_ev, cmd_pipe, EV_READ | EV_PERSIST, cmd_pipe_cb, &pipe_ev);
84
+	event_add(&pipe_ev, NULL);
85
+
86
+	if (!connect_servers(server_group))
87
+	{
88
+		LM_ERR("failed to connect to any servers\n");
89
+		return -1;
90
+	}
91
+
92
+	event_dispatch();
93
+	return 0;
94
+}
95
+
96
+void timeout_cb(int fd, short event, void *arg) 
97
+{
98
+	LM_ERR("message timeout\n");
99
+	jsonrpc_request_t *req = (jsonrpc_request_t*)arg;
100
+	json_object *error = json_object_new_string("timeout");
101
+	void_jsonrpc_request(req->id);
102
+	close(req->timerfd);
103
+	event_del(req->timer_ev);
104
+	pkg_free(req->timer_ev);
105
+	req->cbfunc(error, req->cbdata, 1);
106
+	pkg_free(req);
107
+}
108
+
109
+int result_cb(json_object *result, char *data, int error) 
110
+{
111
+	struct jsonrpc_pipe_cmd *cmd = (struct jsonrpc_pipe_cmd*)data;
112
+
113
+	pv_spec_t *dst = cmd->cb_pv;
114
+	pv_value_t val;
115
+
116
+	const char* res = json_object_get_string(result);
117
+
118
+	val.rs.s = (char*)res;
119
+	val.rs.len = strlen(res);
120
+	val.flags = PV_VAL_STR;
121
+
122
+	dst->setf(0, &dst->pvp, (int)EQ_T, &val);
123
+
124
+	int n;
125
+	if (error) {
126
+		n = route_get(&main_rt, cmd->err_route);
127
+	} else {
128
+		n = route_get(&main_rt, cmd->cb_route);
129
+	}
130
+
131
+	struct action *a = main_rt.rlist[n];
132
+	tmb.t_continue(cmd->t_hash, cmd->t_label, a);	
133
+
134
+	free_pipe_cmd(cmd);
135
+	return 0;
136
+}
137
+
138
+
139
+int (*res_cb)(json_object*, char*, int) = &result_cb;
140
+
141
+
142
+void cmd_pipe_cb(int fd, short event, void *arg)
143
+{
144
+	struct jsonrpc_pipe_cmd *cmd;
145
+	/* struct event *ev = (struct event*)arg; */
146
+
147
+	if (read(fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
148
+		LM_ERR("failed to read from command pipe: %s\n", strerror(errno));
149
+		return;
150
+	}
151
+
152
+	json_object *params = json_tokener_parse(cmd->params);
153
+	json_object *payload = NULL;
154
+	jsonrpc_request_t *req = NULL;
155
+
156
+	if (cmd->notify_only) {
157
+		payload = build_jsonrpc_notification(cmd->method, params);
158
+	} else {
159
+		req = build_jsonrpc_request(cmd->method, params, (char*)cmd, res_cb);
160
+		if (req)
161
+			payload = req->payload;
162
+	}
163
+
164
+	if (!payload) {
165
+		LM_ERR("Failed to build jsonrpc_request_t (method: %s, params: %s)\n", cmd->method, cmd->params);	
166
+		return;
167
+	}
168
+	char *json = (char*)json_object_get_string(payload);
169
+
170
+	char *ns; size_t bytes;
171
+	bytes = netstring_encode_new(&ns, json, (size_t)strlen(json));
172
+
173
+	struct jsonrpc_server_group *g;
174
+	int sent = 0;
175
+	for (g = server_group; g != NULL; g = g->next_group)
176
+	{
177
+		struct jsonrpc_server *s, *first = NULL;
178
+		for (s = g->next_server; s != first; s = s->next)
179
+		{
180
+			if (first == NULL) first = s;
181
+			if (s->status == JSONRPC_SERVER_CONNECTED) {
182
+				if (send(s->socket, ns, bytes, 0) == bytes)
183
+				{
184
+					sent = 1;
185
+					break;
186
+				} else {
187
+					handle_server_failure(s);
188
+				}
189
+			}
190
+			g->next_server = s->next;
191
+		}
192
+		if (sent) {
193
+			break;
194
+		} else {
195
+			LM_WARN("Failed to send on priority group %d... proceeding to next priority group.\n", g->priority);
196
+		}
197
+	}
198
+
199
+	if (sent && req) {
200
+		int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
201
+
202
+		if (timerfd == -1) {
203
+			LM_ERR("Could not create timerfd.");
204
+			return;
205
+		}
206
+
207
+		req->timerfd = timerfd;
208
+		struct itimerspec *itime = pkg_malloc(sizeof(struct itimerspec));
209
+		CHECK_MALLOC_VOID(itime);
210
+		itime->it_interval.tv_sec = 0;
211
+		itime->it_interval.tv_nsec = 0;
212
+
213
+		itime->it_value.tv_sec = JSONRPC_TIMEOUT/1000;
214
+		itime->it_value.tv_nsec = (JSONRPC_TIMEOUT % 1000) * 1000000;
215
+		if (timerfd_settime(timerfd, 0, itime, NULL) == -1) 
216
+		{
217
+			LM_ERR("Could not set timer.");
218
+			return;
219
+		}
220
+		pkg_free(itime);
221
+		struct event *timer_ev = pkg_malloc(sizeof(struct event));
222
+		CHECK_MALLOC_VOID(timer_ev);
223
+		event_set(timer_ev, timerfd, EV_READ, timeout_cb, req); 
224
+		if(event_add(timer_ev, NULL) == -1) {
225
+			LM_ERR("event_add failed while setting request timer (%s).", strerror(errno));
226
+			return;
227
+		}
228
+		req->timer_ev = timer_ev;
229
+	} else if (!sent) {
230
+		LM_ERR("Request could not be sent... no more failover groups.\n");
231
+		if (req) {
232
+			json_object *error = json_object_new_string("failure");
233
+			void_jsonrpc_request(req->id);
234
+			req->cbfunc(error, req->cbdata, 1);
235
+		}
236
+	}
237
+
238
+	pkg_free(ns);
239
+	json_object_put(payload);
240
+}
241
+
242
+void socket_cb(int fd, short event, void *arg)
243
+{	
244
+	struct jsonrpc_server *server = (struct jsonrpc_server*)arg;
245
+
246
+	if (event != EV_READ) {
247
+		LM_ERR("unexpected socket event (%d)\n", event);
248
+		handle_server_failure(server);	
249
+		return;
250
+	}
251
+
252
+	char *netstring;
253
+
254
+	int retval = netstring_read_fd(fd, &netstring);
255
+
256
+	if (retval != 0) {
257
+		LM_ERR("bad netstring (%d)\n", retval);
258
+		handle_server_failure(server);
259
+		return;
260
+	}	
261
+
262
+	struct json_object *res = json_tokener_parse(netstring);
263
+
264
+	if (res) {
265
+		handle_jsonrpc_response(res);
266
+		json_object_put(res);
267
+	} else {
268
+		LM_ERR("netstring could not be parsed: (%s)\n", netstring);
269
+		handle_server_failure(server);
270
+	}
271
+	pkg_free(netstring);
272
+}
273
+
274
+int set_non_blocking(int fd)
275
+{
276
+	int flags;
277
+
278
+	flags = fcntl(fd, F_GETFL);
279
+	if (flags < 0)
280
+		return flags;
281
+	flags |= O_NONBLOCK;
282
+	if (fcntl(fd, F_SETFL, flags) < 0)
283
+		return -1;
284
+
285
+	return 0;
286
+}
287
+
288
+int parse_servers(char *_servers, struct jsonrpc_server_group **group_ptr)
289
+{
290
+	char cpy[strlen(_servers)+1];
291
+	char *servers = strcpy(cpy, _servers);
292
+
293
+	struct jsonrpc_server_group *group = NULL;
294
+
295
+	/* parse servers string */
296
+	char *token = strtok(servers, ":");
297
+	while (token != NULL) 
298
+	{
299
+		char *host, *port_s, *priority_s, *tail;
300
+		int port, priority;
301
+		host = token;
302
+
303
+		/* validate domain */
304
+		if (!(isalpha(host[0]) || isdigit(host[0]))) {
305
+			LM_ERR("invalid domain (1st char is '%c')\n", host[0]);
306
+			return -1;
307
+		}
308
+		int i;
309
+		for (i=1; i<strlen(host)-1; i++)
310
+		{
311
+			if(!(isalpha(host[i]) || isdigit(host[i]) || host[i] == '-' || host[i] == '.'))
312
+			{
313
+				LM_ERR("invalid domain (char %d is %c)\n", i, host[i]);
314
+				return -1;
315
+			}
316
+		}
317
+		if (!(isalpha(host[i]) || isdigit(host[i]))) {
318
+			LM_ERR("invalid domain (char %d (last) is %c)\n", i, host[i]);
319
+			return -1;
320
+		}
321
+
322
+		/* convert/validate port */
323
+		port_s = strtok(NULL, ",");
324
+		if (port_s == NULL || !(port = strtol(port_s, &tail, 0)) || strlen(tail)) 
325
+		{
326
+			LM_ERR("invalid port: %s\n", port_s);
327
+			return -1;
328
+		}
329
+
330
+		/* convert/validate priority */
331
+		priority_s = strtok(NULL, " ");
332
+		if (priority_s == NULL || !(priority = strtol(priority_s, &tail, 0)) || strlen(tail)) 
333
+		{
334
+			LM_ERR("invalid priority: %s\n", priority_s);
335
+			return -1;
336
+		}
337
+
338
+	
339
+		struct jsonrpc_server *server = pkg_malloc(sizeof(struct jsonrpc_server));
340
+		CHECK_MALLOC(server);
341
+		char *h = pkg_malloc(strlen(host)+1);
342
+		CHECK_MALLOC(h);
343
+
344
+		strcpy(h,host);
345
+		server->host = h;
346
+		server->port = port;
347
+		server->status = JSONRPC_SERVER_DISCONNECTED;
348
+		server->socket = 0;
349
+
350
+		int group_cnt = 0;
351
+
352
+		/* search for a server group with this server's priority */
353
+		struct jsonrpc_server_group *selected_group = NULL;
354
+		for (selected_group=group; selected_group != NULL; selected_group=selected_group->next_group)
355
+		{
356
+			if (selected_group->priority == priority) break;
357
+		}
358
+		
359
+		if (selected_group == NULL) {
360
+			group_cnt++;
361
+			LM_INFO("Creating group for priority %d\n", priority);
362
+
363
+			/* this is the first server for this priority... link it to itself */
364
+			server->next = server;
365
+			
366
+			selected_group = pkg_malloc(sizeof(struct jsonrpc_server_group));
367
+			CHECK_MALLOC(selected_group);
368
+			selected_group->priority = priority;
369
+			selected_group->next_server = server;
370
+			
371
+			/* insert the group properly in the linked list */
372
+			struct jsonrpc_server_group *x, *pg;
373
+			pg = NULL;
374
+			if (group == NULL) 
375
+			{
376
+				group = selected_group;
377
+				group->next_group = NULL;
378
+			} else {
379
+				for (x = group; x != NULL; x = x->next_group) 
380
+				{
381
+					if (priority > x->priority)
382
+					{
383
+						if (pg == NULL)
384
+						{
385
+							group = selected_group;
386
+						} else {
387
+							pg->next_group = selected_group;
388
+						}
389
+						selected_group->next_group = x;
390
+						break;
391
+					} else if (x->next_group == NULL) {
392
+						x->next_group = selected_group;
393
+						break;
394
+					} else {
395
+						pg = x;
396
+					}
397
+				}
398
+			}
399
+		} else {
400
+			LM_ERR("Using existing group for priority %d\n", priority);
401
+			server->next = selected_group->next_server->next;
402
+			selected_group->next_server->next = server;
403
+		}
404
+
405
+		token = strtok(NULL, ":");
406
+	}
407
+
408
+	*group_ptr = group;
409
+	return 0;
410
+}
411
+
412
+int connect_server(struct jsonrpc_server *server) 
413
+{	
414
+	struct sockaddr_in  server_addr;
415
+	struct hostent      *hp;
416
+
417
+	server_addr.sin_family = AF_INET;
418
+	server_addr.sin_port   = htons(server->port);
419
+
420
+	hp = gethostbyname(server->host);
421
+	if (hp == NULL) {
422
+		LM_ERR("gethostbyname(%s) failed with h_errno=%d.\n", server->host, h_errno);
423
+		handle_server_failure(server);
424
+		return -1;
425
+	}
426
+	memcpy(&(server_addr.sin_addr.s_addr), hp->h_addr, hp->h_length);
427
+
428
+	int sockfd = socket(AF_INET,SOCK_STREAM,0);
429
+
430
+	if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in))) {
431
+		LM_WARN("Failed to connect to %s on port %d... %s\n", server->host, server->port, strerror(errno));
432
+		handle_server_failure(server);
433
+		return -1;
434
+	}
435
+
436
+	if (set_non_blocking(sockfd) != 0)
437
+	{
438
+		LM_WARN("Failed to set socket (%s:%d) to non blocking.\n", server->host, server->port);
439
+		handle_server_failure(server);
440
+		return -1;
441
+	}
442
+
443
+	server->socket = sockfd;
444
+	server->status = JSONRPC_SERVER_CONNECTED;
445
+
446
+	struct event *socket_ev = pkg_malloc(sizeof(struct event));
447
+	CHECK_MALLOC(socket_ev);
448
+	event_set(socket_ev, sockfd, EV_READ | EV_PERSIST, socket_cb, server);
449
+	event_add(socket_ev, NULL);
450
+	server->ev = socket_ev;
451
+	return 0;
452
+}
453
+
454
+int  connect_servers(struct jsonrpc_server_group *group)
455
+{
456
+	int connected_servers = 0;
457
+	for (;group != NULL; group = group->next_group)
458
+	{
459
+		struct jsonrpc_server *s, *first = NULL;
460
+		LM_INFO("Connecting to servers for priority %d:\n", group->priority);
461
+		for (s=group->next_server;s!=first;s=s->next)
462
+		{
463
+			if (connect_server(s) == 0) 
464
+			{
465
+				connected_servers++;
466
+				LM_INFO("Connected to host %s on port %d\n", s->host, s->port);
467
+			}
468
+			if (first == NULL) first = s;
469
+		}
470
+	}
471
+	return connected_servers;
472
+}
473
+
474
+void reconnect_cb(int fd, short event, void *arg)
475
+{
476
+	LM_INFO("Attempting to reconnect now.");
477
+	struct jsonrpc_server *server = (struct jsonrpc_server*)arg;
478
+	
479
+	if (server->status == JSONRPC_SERVER_CONNECTED) {
480
+		LM_WARN("Trying to connect an already connected server.");
481
+		return;
482
+	}
483
+
484
+	if (server->ev != NULL) {
485
+		event_del(server->ev);
486
+		pkg_free(server->ev);
487
+		server->ev = NULL;
488
+	}
489
+
490
+	close(fd);
491
+	pkg_free(server->timer);
492
+
493
+	connect_server(server);
494
+}
495
+
496
+int handle_server_failure(struct jsonrpc_server *server)
497
+{
498
+	LM_INFO("Setting timer to reconnect to %s on port %d in %d seconds.\n", server->host, server->port, JSONRPC_RECONNECT_INTERVAL);
499
+
500
+	if (server->socket)
501
+		close(server->socket);
502
+	server->socket = 0;
503
+	if (server->ev != NULL) {
504
+		event_del(server->ev);
505
+		pkg_free(server->ev);
506
+		server->ev = NULL;
507
+	}
508
+	server->status = JSONRPC_SERVER_FAILURE;
509
+	int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
510
+	
511
+	if (timerfd == -1) {
512
+		LM_ERR("Could not create timerfd to reschedule connection. No further attempts will be made to reconnect this server.");
513
+		return -1;
514
+	}
515
+
516
+	struct itimerspec *itime = pkg_malloc(sizeof(struct itimerspec));
517
+	CHECK_MALLOC(itime);
518
+	itime->it_interval.tv_sec = 0;
519
+	itime->it_interval.tv_nsec = 0;
520
+	
521
+	itime->it_value.tv_sec = JSONRPC_RECONNECT_INTERVAL;
522
+	itime->it_value.tv_nsec = 0;
523
+	
524
+	if (timerfd_settime(timerfd, 0, itime, NULL) == -1) 
525
+	{
526
+		LM_ERR("Could not set timer to reschedule connection. No further attempts will be made to reconnect this server.");
527
+		return -1;
528
+	}
529
+	LM_INFO("timerfd value is %d\n", timerfd);
530
+	struct event *timer_ev = pkg_malloc(sizeof(struct event));
531
+	CHECK_MALLOC(timer_ev);
532
+	event_set(timer_ev, timerfd, EV_READ, reconnect_cb, server); 
533
+	if(event_add(timer_ev, NULL) == -1) {
534
+		LM_ERR("event_add failed while rescheduling connection (%s). No further attempts will be made to reconnect this server.", strerror(errno));
535
+		return -1;
536
+	}
537
+	server->ev = timer_ev;
538
+	server->timer = itime;
539
+	return 0;
540
+}
541
+
542
+
543
+void free_pipe_cmd(struct jsonrpc_pipe_cmd *cmd) 
544
+{
545
+	if (cmd->method) 
546
+		shm_free(cmd->method);
547
+	if (cmd->params)
548
+		shm_free(cmd->params);
549
+	if (cmd->cb_route)
550
+		shm_free(cmd->cb_route);
551
+	if (cmd->err_route)
552
+		shm_free(cmd->err_route);
553
+	if (cmd->cb_pv)
554
+		shm_free(cmd->cb_pv);
555
+	shm_free(cmd);
556
+}
0 557
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+/**
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2011 Flowroute LLC (flowroute.com)
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * This file is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ *
13
+ * This file is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ *
22
+ */
23
+
24
+#ifndef _JSONRPC_IO_H_
25
+#define _JSONRPC_IO_H_
26
+
27
+#include "../../route_struct.h"
28
+#include "../../pvar.h"
29
+
30
+#define JSONRPC_SERVER_CONNECTED    1
31
+#define JSONRPC_SERVER_DISCONNECTED 2
32
+#define JSONRPC_SERVER_FAILURE      3
33
+
34
+/* interval (in seconds) at which failed servers are retried */
35
+#define JSONRPC_RECONNECT_INTERVAL  3
36
+
37
+/* time (in ms) after which the error route is called */
38
+#define JSONRPC_TIMEOUT 			500
39
+
40
+struct jsonrpc_pipe_cmd 
41
+{
42
+	char *method, *params, *cb_route, *err_route;
43
+	unsigned int t_hash, t_label, notify_only;
44
+	pv_spec_t *cb_pv;
45
+	struct sip_msg *msg;
46
+};
47
+
48
+int jsonrpc_io_child_process(int data_pipe, char* servers);
49
+void free_pipe_cmd(struct jsonrpc_pipe_cmd *cmd); 
50
+
51
+#endif /* _JSONRPC_IO_H_ */
0 52
new file mode 100644
... ...
@@ -0,0 +1,172 @@
0
+/**
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2011 Flowroute LLC (flowroute.com)
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * This file is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ *
13
+ * This file is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ *
22
+ */
23
+
24
+#include <arpa/inet.h>
25
+#include <sys/types.h>
26
+#include <errno.h>
27
+
28
+#include "../../mod_fix.h"
29
+#include "../../trim.h"
30
+#include "../../sr_module.h"
31
+#include "../tm/tm_load.h"
32
+
33
+#include "jsonrpc_request.h"
34
+#include "jsonrpc_io.h"
35
+#include "jsonrpc.h"
36
+
37
+
38
+MODULE_VERSION
39
+
40
+
41
+static int mod_init(void);
42
+static int child_init(int);
43
+static int fixup_request(void** param, int param_no);
44
+static int fixup_notification(void** param, int param_no);
45
+static int fixup_request_free(void** param, int param_no);
46
+int        fixup_pvar_shm(void** param, int param_no);
47
+
48
+char *servers_param;
49
+int  pipe_fds[2] = {-1,-1};
50
+
51
+struct tm_binds tmb;
52
+
53
+/*
54
+ * Exported Functions
55
+ */
56
+static cmd_export_t cmds[]={
57
+	{"jsonrpc_request", (cmd_function)jsonrpc_request, 5, fixup_request, fixup_request_free, ANY_ROUTE},
58
+	{"jsonrpc_notification", (cmd_function)jsonrpc_notification, 2, fixup_notification, 0, ANY_ROUTE},
59
+	{0, 0, 0, 0, 0, 0}
60
+};
61
+ 
62
+
63
+/*
64
+ * Script Parameters
65
+ */
66
+static param_export_t mod_params[]={
67
+	{"servers", STR_PARAM, &servers_param},
68
+	{ 0,0,0 }
69
+};
70
+
71
+ 
72
+/*
73
+ * Exports
74
+ */
75
+struct module_exports exports = {
76
+		"jsonrpc",           /* module name */
77
+		DEFAULT_DLFLAGS,     /* dlopen flags */
78
+		cmds,                /* Exported functions */
79
+		mod_params,          /* Exported parameters */
80
+		0,                   /* exported statistics */
81
+		0,                   /* exported MI functions */
82
+		0,                   /* exported pseudo-variables */
83
+		0,                   /* extra processes */
84
+		mod_init,            /* module initialization function */
85
+		0,                   /* response function*/
86
+		0,                   /* destroy function */
87
+		child_init           /* per-child init function */
88
+};
89
+
90
+
91
+static int mod_init(void) {
92
+	load_tm_f  load_tm;
93
+
94
+	/* load the tm functions  */
95
+	if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT, 0)))
96
+	{
97
+		LOG(L_ERR, "ERROR:jsonrpc:mod_init: cannot import load_tm\n");
98
+		return -1;
99
+	}
100
+	/* let the auto-loading function load all TM stuff */
101
+	if (load_tm( &tmb )==-1)
102
+		return -1;
103
+
104
+	if (servers_param == NULL) {
105
+		LM_ERR("servers parameter missing.\n");
106
+		return -1;
107
+	}
108
+
109
+	register_procs(1);
110
+
111
+	if (pipe(pipe_fds) < 0) {
112
+		LM_ERR("pipe() failed\n");
113
+		return -1;
114
+	}
115
+	
116
+	return(0);
117
+}
118
+
119
+static int child_init(int rank) 
120
+{
121
+	int pid;
122
+	
123
+	if (rank>PROC_MAIN)
124
+		cmd_pipe = pipe_fds[1];
125
+
126
+	if (rank!=PROC_MAIN)
127
+		return 0;
128
+
129
+	pid=fork_process(PROC_NOCHLDINIT, "jsonrpc io handler", 1);
130
+	if (pid<0)
131
+		return -1; /* error */
132
+	if(pid==0){
133
+		/* child */
134
+		close(pipe_fds[1]);
135
+		return jsonrpc_io_child_process(pipe_fds[0], servers_param);
136
+	}
137
+	return 0;
138
+}
139
+
140
+/* Fixup Functions */
141
+
142
+static int fixup_request(void** param, int param_no)
143
+{
144
+  if (param_no <= 4) {
145
+		return fixup_spve_null(param, 1);
146
+	} else if (param_no == 5) {
147
+		return fixup_pvar_null(param, 1);
148
+	}
149
+	LM_ERR("jsonrpc_request takes exactly 5 parameters.\n");
150
+	return -1;
151
+}
152
+
153
+static int fixup_notification(void** param, int param_no)
154
+{
155
+  if (param_no <= 2) {
156
+		return fixup_spve_null(param, 1);
157
+	}
158
+	LM_ERR("jsonrpc_notification takes exactly 2 parameters.\n");
159
+	return -1;
160
+}
161
+
162
+static int fixup_request_free(void** param, int param_no)
163
+{
164