Browse code

rpc: added register function and switched to hash table

- rpc switched to hashtable
- added rpc register function, that can be called from modules not
using ser module interface (e.g. kamailio or future sip-router
module interface).

Andrei Pelinescu-Onciul authored on 11/05/2009 22:39:03
Showing 6 changed files
... ...
@@ -31,6 +31,7 @@
31 31
 #include "mem/mem.h"
32 32
 #include "mem/shm_mem.h"
33 33
 #include "sr_module.h"
34
+#include "rpc_lookup.h"
34 35
 #include "dprint.h"
35 36
 #include "core_cmd.h"
36 37
 #include "globals.h"
... ...
@@ -229,18 +230,10 @@ static const char* system_listMethods_doc[] = {
229 229
 
230 230
 static void system_listMethods(rpc_t* rpc, void* c)
231 231
 {
232
-	struct sr_module* t;
233
-	rpc_export_t* ptr;
234
-
235
-	for(ptr = core_rpc_methods; ptr && ptr->name; ptr++) {
236
-		if (rpc->add(c, "s", ptr->name) < 0) return;
237
-	}
238
-
239
-	for(t = modules; t; t = t->next) {
240
-		if (t->mod_interface_ver!=0) continue;
241
-		for(ptr = t->exports->v0.rpc_methods; ptr && ptr->name; ptr++) {
242
-			if (rpc->add(c, "s", ptr->name) < 0) return;
243
-		}
232
+	int i;
233
+	
234
+	for(i=0; i<rpc_sarray_crt_size; i++){
235
+		if (rpc->add(c, "s", rpc_sarray[i]->name) < 0) return;
244 236
 	}
245 237
 }
246 238
 
... ...
@@ -262,40 +255,25 @@ static const char* system_methodHelp_doc[] = {
262 262
 
263 263
 static void system_methodHelp(rpc_t* rpc, void* c)
264 264
 {
265
-	struct sr_module* t;
266
-	rpc_export_t* ptr;
265
+	rpc_export_t* r;
267 266
 	char* name;
268 267
 
269 268
 	if (rpc->scan(c, "s", &name) < 1) {
270 269
 		rpc->fault(c, 400, "Method Name Expected");
271 270
 		return;
272 271
 	}
273
-
274
-	for(t = modules; t; t = t->next) {
275
-		if (t->mod_interface_ver!=0) continue;
276
-		for(ptr = t->exports->v0.rpc_methods; ptr && ptr->name; ptr++) {
277
-			if (strcmp(name, ptr->name) == 0) {
278
-				if (ptr->doc_str && ptr->doc_str[0]) {
279
-					rpc->add(c, "s", ptr->doc_str[0]);
280
-				} else {
281
-					rpc->add(c, "s", "undocumented");
282
-				}
283
-				return;
284
-			}
272
+	
273
+	r=rpc_lookup(name, strlen(name));
274
+	if (r==0){
275
+		rpc->fault(c, 400, "command not found");
276
+	}else{
277
+		if (r->doc_str && r->doc_str[0]) {
278
+			rpc->add(c, "s", r->doc_str[0]);
279
+		} else {
280
+			rpc->add(c, "s", "undocumented");
285 281
 		}
286 282
 	}
287
-	/* try the core methods too */
288
-	for (ptr=core_rpc_methods;ptr && ptr->name; ptr++){
289
-			if (strcmp(name, ptr->name) == 0) {
290
-				if (ptr->doc_str && ptr->doc_str[0]) {
291
-					rpc->add(c, "s", ptr->doc_str[0]);
292
-				} else {
293
-					rpc->add(c, "s", "undocumented");
294
-				}
295
-				return;
296
-			}
297
-	}
298
-	rpc->fault(c, 400, "command not found");
283
+	return;
299 284
 }
300 285
 
301 286
 
... ...
@@ -701,7 +679,7 @@ static void core_sctpinfo(rpc_t* rpc, void* c)
701 701
 /*
702 702
  * RPC Methods exported by this module
703 703
  */
704
-rpc_export_t core_rpc_methods[] = {
704
+static rpc_export_t core_rpc_methods[] = {
705 705
 	{"system.listMethods",     system_listMethods,     system_listMethods_doc,     RET_ARRAY},
706 706
 	{"system.methodSignature", system_methodSignature, system_methodSignature_doc, 0        },
707 707
 	{"system.methodHelp",      system_methodHelp,      system_methodHelp_doc,      0        },
... ...
@@ -785,6 +763,28 @@ rpc_export_t core_rpc_methods[] = {
785 785
 	{0, 0, 0, 0}
786 786
 };
787 787
 
788
+
789
+
790
+int register_core_rpcs(void)
791
+{
792
+	int i;
793
+	
794
+	i=rpc_register_array(core_rpc_methods);
795
+	if (i<0){
796
+		BUG("failed to register core RPCs\n");
797
+		goto error;
798
+	}else if (i>0){
799
+		ERR("%d duplicate RPCs name detected while registering core RPCs\n",
800
+			 i);
801
+		goto error;
802
+	}
803
+	return 0;
804
+error:
805
+	return -1;
806
+}
807
+
808
+
809
+
788 810
 int rpc_init_time(void)
789 811
 {
790 812
 	char *t;
... ...
@@ -30,8 +30,7 @@
30 30
 
31 31
 #include "rpc.h"
32 32
 
33
-extern rpc_export_t core_rpc_methods[];
34
-
33
+int register_core_rpcs(void);
35 34
 int rpc_init_time(void);
36 35
 
37 36
 #endif /* _CORE_CMD_H */
... ...
@@ -153,6 +153,7 @@
153 153
 #include "sctp_server.h"
154 154
 #endif
155 155
 #include "usr_avp.h"
156
+#include "rpc_lookup.h"
156 157
 #include "core_cmd.h"
157 158
 #include "flags.h"
158 159
 #include "lock_ops_init.h"
... ...
@@ -1630,6 +1631,8 @@ int main(int argc, char** argv)
1630 1630
 	}
1631 1631
 	if (init_routes()<0) goto error;
1632 1632
 	if (init_nonsip_hooks()<0) goto error;
1633
+	if (init_rpcs()<0) goto error;
1634
+	if (register_core_rpcs()!=0) goto error;
1633 1635
 
1634 1636
 	/* Fix the value of cfg_file variable.*/
1635 1637
 	if (fix_cfg_file() < 0) goto error;
1636 1638
new file mode 100644
... ...
@@ -0,0 +1,220 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2009 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * SER RPC lookup and register functions
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2009-05-11  initial version (andrei)
24
+*/
25
+
26
+#include "rpc.h"
27
+#include "str_hash.h"
28
+#include "ut.h"
29
+
30
+#define RPC_HASH_SIZE	32
31
+#define RPC_SARRAY_SIZE	32 /* initial size */
32
+
33
+#define RPC_COPY_EXPORT
34
+
35
+static struct str_hash_table rpc_hash_table;
36
+
37
+/* array of pointer to rpc exports, sorted after their name
38
+ *  (used by listMethods) */
39
+rpc_export_t** rpc_sarray;
40
+int rpc_sarray_crt_size; /* used */
41
+static int rpc_sarray_max_size; /* number of entries alloc'ed */
42
+
43
+/** init the rpc hash table.
44
+  * @return 0 on success, -1 on error
45
+  */
46
+int init_rpcs()
47
+{
48
+	if (str_hash_alloc(&rpc_hash_table, RPC_HASH_SIZE)<0)
49
+		return -1;
50
+	str_hash_init(&rpc_hash_table);
51
+	rpc_sarray_max_size=RPC_SARRAY_SIZE;
52
+	rpc_sarray=pkg_malloc(sizeof(*rpc_sarray)* rpc_sarray_max_size);
53
+	rpc_sarray_crt_size=0;
54
+	return 0;
55
+}
56
+
57
+
58
+
59
+void destroy_rpcs()
60
+{
61
+	int r;
62
+	struct str_hash_entry* e;
63
+	struct str_hash_entry* bak;
64
+	for (r=0; r<rpc_hash_table.size; r++){
65
+		clist_foreach_safe(&rpc_hash_table.table[r], e, bak, next){
66
+			pkg_free(e);
67
+		}
68
+	}
69
+	pkg_free(rpc_hash_table.table);
70
+	pkg_free(rpc_sarray);
71
+	rpc_hash_table.table=0;
72
+	rpc_hash_table.size=0;
73
+	rpc_sarray=0;
74
+	rpc_sarray_crt_size=0;
75
+	rpc_sarray_max_size=0;
76
+}
77
+
78
+
79
+
80
+/** adds a new rpc to the hash table (no checks).
81
+ * @return 0 on success, -1 on error, 1 on duplicate
82
+ */
83
+static int rpc_hash_add(struct rpc_export* rpc)
84
+{
85
+	struct str_hash_entry* e;
86
+	int name_len;
87
+	int doc0_len, doc1_len;
88
+	struct rpc_export* n_rpc;
89
+	struct rpc_export** r;
90
+	
91
+	name_len=strlen(rpc->name);
92
+	doc0_len=rpc->doc_str[0]?strlen(rpc->doc_str[0]):0;
93
+	doc1_len=rpc->doc_str[1]?strlen(rpc->doc_str[1]):0;
94
+	/* alloc everything into one block */
95
+	e=pkg_malloc(ROUND_POINTER(sizeof(struct str_hash_entry))
96
+#ifdef RPC_COPY_EXPORT
97
+								+ROUND_POINTER(sizeof(*rpc))+2*sizeof(char*)+
98
+								+name_len+1+doc0_len+(rpc->doc_str[0]!=0)
99
+								+doc1_len+(rpc->doc_str[1]!=0)
100
+#endif /* RPC_COPY_EXPORT */
101
+								);
102
+	if (e==0){
103
+		ERR("out of memory\n");
104
+		goto error;
105
+	}
106
+#ifdef RPC_COPY_EXPORT
107
+	n_rpc=(rpc_export_t*)((char*)e+
108
+			ROUND_POINTER(sizeof(struct str_hash_entry)));
109
+	/* copy rpc into n_rpc */
110
+	*n_rpc=*rpc;
111
+	n_rpc->doc_str=(const char**)((char*)n_rpc+ROUND_POINTER(sizeof(*rpc)));
112
+	n_rpc->name=(char*)n_rpc->doc_str+2*sizeof(char*);
113
+	memcpy((char*)n_rpc->name, rpc->name, name_len);
114
+	*((char*)&n_rpc->name[name_len])=0;
115
+	if (rpc->doc_str[0]){
116
+		n_rpc->doc_str[0]=&n_rpc->name[name_len+1];
117
+		memcpy((char*)n_rpc->doc_str[0], rpc->doc_str[0], doc0_len);
118
+		*(char*)&(n_rpc->doc_str[0][doc0_len])=0;
119
+	}else{
120
+		n_rpc->doc_str[0]=0;
121
+	}
122
+	if (rpc->doc_str[1]){
123
+		n_rpc->doc_str[1]=n_rpc->doc_str[0]?&n_rpc->doc_str[0][doc0_len+1]:
124
+							&n_rpc->name[name_len+1];;
125
+		memcpy((char*)n_rpc->doc_str[1], rpc->doc_str[1], doc1_len);
126
+		*(char*)&(n_rpc->doc_str[1][doc1_len])=0;
127
+	}else{
128
+		n_rpc->doc_str[1]=0;
129
+	}
130
+#else /* RPC_COPY_EXPORT */
131
+	n_rpc=rpc;
132
+#endif /* RPC_COPY_EXPORT */
133
+	
134
+	e->key.s=(char*)n_rpc->name;
135
+	e->key.len=name_len;
136
+	e->flags=0;
137
+	e->u.p=n_rpc;
138
+	str_hash_add(&rpc_hash_table, e);
139
+	
140
+	/* insert it into the sorted array */
141
+	if (rpc_sarray_max_size<=rpc_sarray_crt_size){
142
+		/* array must be increased */
143
+		r=pkg_realloc(rpc_sarray, 2*rpc_sarray_max_size*sizeof(*rpc_sarray));
144
+		if (r==0){
145
+			ERR("out of memory while adding RPC to the sorted list\n");
146
+			goto error;
147
+		}
148
+		rpc_sarray=r;
149
+		rpc_sarray_max_size*=2;
150
+	};
151
+	/* insert into array, sorted */
152
+	for (r=rpc_sarray;r<(rpc_sarray+rpc_sarray_crt_size); r++){
153
+		if (strcmp(n_rpc->name, (*r)->name)<0)
154
+			break;
155
+	}
156
+	if (r!=(rpc_sarray+rpc_sarray_crt_size))
157
+		memmove(r+1, r, (int)(long)((char*)(rpc_sarray+rpc_sarray_crt_size)-
158
+											(char*)r));
159
+	rpc_sarray_crt_size++;
160
+	*r=n_rpc;
161
+	return 0;
162
+error:
163
+	return -1;
164
+}
165
+
166
+
167
+
168
+/** lookup an rpc export after its name.
169
+ * @return pointer to rpc export on success, 0 on error
170
+ */
171
+rpc_export_t* rpc_lookup(const char* name, int len)
172
+{
173
+	struct str_hash_entry* e;
174
+	
175
+	e=str_hash_get(&rpc_hash_table, (char*)name, len);
176
+	return e?(rpc_export_t*)e->u.p:0;
177
+}
178
+
179
+
180
+
181
+/** register a new rpc.
182
+ * @return 0 on success, -1 on error, 1 on duplicate
183
+ */
184
+int rpc_register(rpc_export_t* rpc)
185
+{
186
+	
187
+	/* check if the entry is already registered */
188
+	if (rpc_lookup(rpc->name, strlen(rpc->name)))
189
+		return 1;
190
+	if (rpc_hash_add(rpc)!=0) return -1;
191
+	return 0;
192
+}
193
+
194
+
195
+
196
+/** register all the rpc in a null-terminated array.
197
+  * @return 0 on success, >0 if duplicates were found (number of 
198
+  * duplicates), -1 on error
199
+  */
200
+int rpc_register_array(rpc_export_t* rpc_array)
201
+{
202
+	rpc_export_t* rpc;
203
+	int ret,i;
204
+	
205
+	ret=0;
206
+	for (rpc=rpc_array; rpc && rpc->name; rpc++){
207
+		i=rpc_register(rpc);
208
+		if (i!=0){
209
+			if (i<0) goto error;
210
+			ret++;
211
+		}
212
+	}
213
+	return ret;
214
+error:
215
+	return -1;
216
+}
217
+
218
+
219
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
0 220
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2009 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * SER RPC lookup and register functions
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2009-05-11  initial version (andrei)
24
+*/
25
+
26
+#ifndef __rpc_lookup_h
27
+#define __rpc_lookup_h
28
+
29
+#include "rpc.h"
30
+/* must be exported for listing the rpcs */
31
+extern rpc_export_t** rpc_sarray;
32
+extern int rpc_sarray_crt_size;
33
+
34
+int init_rpcs();
35
+int destroy_rpcs();
36
+
37
+rpc_export_t* rpc_lookup(const char* name, int len);
38
+int rpc_register(rpc_export_t* rpc);
39
+int rpc_register_array(rpc_export_t* rpc_array);
40
+
41
+
42
+
43
+#endif /*__rpc_lookup_h*/
44
+
45
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
... ...
@@ -53,6 +53,7 @@
53 53
 #include "flags.h"
54 54
 #include "trim.h"
55 55
 #include "globals.h"
56
+#include "rpc_lookup.h"
56 57
 
57 58
 #include <sys/stat.h>
58 59
 #include <regex.h>
... ...
@@ -147,7 +148,7 @@ int register_builtin_modules()
147 147
 static int register_module(unsigned ver, union module_exports_u* e,
148 148
 					char* path, void* handle)
149 149
 {
150
-	int ret;
150
+	int ret, i;
151 151
 	struct sr_module* mod;
152 152
 
153 153
 	ret=-1;
... ...
@@ -166,8 +167,8 @@ static int register_module(unsigned ver, union module_exports_u* e,
166 166
 	mod->next=modules;
167 167
 	modules=mod;
168 168
 
169
-	/* register module pseudo-variables */
170 169
 	if (ver==1 && e->v1.items) {
170
+		/* register module pseudo-variables for kamailio modules */
171 171
 		LM_DBG("register PV from: %s\n", e->c.name);
172 172
 		if (register_pvars_mod(e->c.name, e->v1.items)!=0) {
173 173
 			LM_ERR("failed to register pseudo-variables for module %s\n",
... ...
@@ -175,6 +176,18 @@ static int register_module(unsigned ver, union module_exports_u* e,
175 175
 			pkg_free(mod);
176 176
 			return -1;
177 177
 		}
178
+	}else if (ver==0 && e->v0.rpc_methods){
179
+		/* register rpcs for ser modules */
180
+		i=rpc_register_array(e->v0.rpc_methods);
181
+		if (i<0){
182
+			ERR("failed to register RPCs for module %s\n", e->c.name);
183
+			goto error;
184
+		}else if (i>0){
185
+			ERR("%d duplicate RPCs name detected while registering RPCs"
186
+					" declared in modules %s\n", i, e->c.name);
187
+			goto error;
188
+		}
189
+		/* i==0 => success */
178 190
 	}
179 191
 
180 192
 	return 0;
... ...
@@ -489,31 +502,7 @@ cmd_function find_export(char* name, int param_no, int flags)
489 489
 
490 490
 rpc_export_t* find_rpc_export(char* name, int flags)
491 491
 {
492
-	struct sr_module* t;
493
-	rpc_export_t* rpc;
494
-
495
-	     /* Scan the list of core methods first, they are always
496
-	      * present
497
-	      */
498
-	for(rpc = core_rpc_methods; rpc && rpc->name; rpc++) {
499
-		if ((strcmp(name, rpc->name) == 0) &&
500
-		    ((rpc->flags & flags) == flags)
501
-		    ) {
502
-			return rpc;
503
-		}
504
-	}
505
-	     /* Continue with modules if not found */
506
-	for(t = modules; t; t = t->next) {
507
-		if (t->mod_interface_ver!=0) continue;
508
-		for(rpc = t->exports->v0.rpc_methods; rpc && rpc->name; rpc++) {
509
-			if ((strcmp(name, rpc->name) == 0) &&
510
-			    ((rpc->flags & flags) == flags)
511
-			   ) {
512
-				return rpc;
513
-			}
514
-		}
515
-	}
516
-	return 0;
492
+	return rpc_lookup((char*)name, strlen(name));
517 493
 }
518 494
 
519 495