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