1 /*
2  * Various lcr related functions :: RPC API
3  *
4  * Copyright (C) 2009-2010 Juha Heinanen
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio 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  * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 /*!
24  * \file
25  * \brief Kamailio lcr :: rpc API interface
26  * \ingroup lcr
27  * Module: \ref lcr
28  */
29 
30 #include "lcr_rpc.h"
31 
32 #include "lcr_mod.h"
33 #include "../../core/ip_addr.h"
34 
35 
36 static const char *reload_doc[2] = {"Reload lcr tables from database.", 0};
37 
38 
reload(rpc_t * rpc,void * c)39 static void reload(rpc_t *rpc, void *c)
40 {
41 	lock_get(reload_lock);
42 	if(reload_tables() != 1)
43 		rpc->fault(c, 500, "LCR Module Reload Failed");
44 	lock_release(reload_lock);
45 }
46 
47 
48 static const char *dump_gws_doc[2] = {"Dump the contents of lcr_gws table.", 0};
49 
50 
dump_gw(rpc_t * rpc,void * st,struct gw_info * gw,unsigned int gw_index,unsigned int lcr_id)51 static void dump_gw(rpc_t *rpc, void *st, struct gw_info *gw, unsigned int gw_index, unsigned int lcr_id)
52 {
53 	str scheme, gw_name, hostname, params, transport;
54 	str prefix, tag;
55 	char buf[INT2STR_MAX_LEN], *start;
56 	int len;
57 
58 	rpc->struct_add(st, "d", "lcr_id", lcr_id);
59 	rpc->struct_add(st, "d", "gw_index", gw_index);
60 	rpc->struct_add(st, "d", "gw_id", gw->gw_id);
61 	gw_name.s = gw->gw_name;
62 	gw_name.len = gw->gw_name_len;
63 	rpc->struct_add(st, "S", "gw_name", &gw_name);
64 	scheme.s = gw->scheme;
65 	scheme.len = gw->scheme_len;
66 	rpc->struct_add(st, "S", "scheme", &scheme);
67 	switch(gw->ip_addr.af) {
68 		case AF_INET:
69 			rpc->struct_printf(st, "ip_addr", "%d.%d.%d.%d",
70 					gw->ip_addr.u.addr[0], gw->ip_addr.u.addr[1],
71 					gw->ip_addr.u.addr[2], gw->ip_addr.u.addr[3]);
72 			break;
73 		case AF_INET6:
74 			rpc->struct_printf(st, "ip_addr", "%x:%x:%x:%x:%x:%x:%x:%x",
75 					gw->ip_addr.u.addr16[0],
76 					gw->ip_addr.u.addr16[1],
77 					gw->ip_addr.u.addr16[2],
78 					gw->ip_addr.u.addr16[3],
79 					gw->ip_addr.u.addr16[4],
80 					gw->ip_addr.u.addr16[5],
81 					gw->ip_addr.u.addr16[6],
82 					gw->ip_addr.u.addr16[7]);
83 			break;
84 		case 0:
85 			rpc->struct_add(st, "s", "ip_addr", "0.0.0.0");
86 			break;
87 	}
88 	hostname.s = gw->hostname;
89 	hostname.len = gw->hostname_len;
90 	rpc->struct_add(st, "S", "hostname", &hostname);
91 	rpc->struct_add(st, "d", "port", gw->port);
92 	params.s = gw->params;
93 	params.len = gw->params_len;
94 	rpc->struct_add(st, "S", "params", &params);
95 	transport.s = gw->transport;
96 	transport.len = gw->transport_len;
97 	rpc->struct_add(st, "S", "transport", &transport);
98 	prefix.s = gw->prefix;
99 	prefix.len = gw->prefix_len;
100 	tag.s = gw->tag;
101 	tag.len = gw->tag_len;
102 	start = int2strbuf(
103 			gw->defunct_until, &(buf[0]), INT2STR_MAX_LEN, &len);
104 	rpc->struct_add(st, "dSSdds", "strip", gw->strip, "prefix",
105 			&prefix, "tag", &tag, "flags", gw->flags, "state",
106 			gw->state, "defunct_until", start);
107 }
108 
dump_gws(rpc_t * rpc,void * c)109 static void dump_gws(rpc_t *rpc, void *c)
110 {
111 	void *st;
112 	void *rec = NULL;
113 	void *srec = NULL;
114 	unsigned int i, j;
115 	struct gw_info *gws;
116 
117 	for(j = 1; j <= lcr_count_param; j++) {
118 
119 		gws = gw_pt[j];
120 
121 		for(i = 1; i <= gws[0].ip_addr.u.addr32[0]; i++) {
122 			if (srec==NULL) {
123 				/* We create one array per lcr_id */
124 				if(rpc->add(c, "{", &rec) < 0)
125 					return;
126 				if(rpc->struct_add(rec, "[", "gw", &srec) < 0)
127 					return;
128 			}
129 			if(rpc->array_add(srec, "{", &st) < 0)
130 				return;
131 			dump_gw(rpc, st, &gws[i], i, j);
132 		}
133 	}
134 }
135 
136 
137 static const char *dump_rules_doc[2] = {
138 		"Dump the contents of the lcr_rules table.", 0};
139 
140 
dump_rules(rpc_t * rpc,void * c)141 static void dump_rules(rpc_t *rpc, void *c)
142 {
143 	int i, j;
144 	int _filter_by_prefix = 0;
145 	int _lcr_id = 0;
146 	str _prefix = {NULL,0};
147 	struct rule_info **rules, *rule;
148 	struct target *t;
149 	void *rec = NULL;
150 	void *srec = NULL;
151 	void *st, *sst, *ssst;
152 	str prefix, from_uri, request_uri;
153 
154 	if (rpc->scan(c, "d", &_lcr_id)>0) {
155 		if (rpc->scan(c, ".S", &_prefix)>0) {
156 			_filter_by_prefix = 1;
157 		}
158 	}
159 
160 	for(j = 1; j <= lcr_count_param; j++) {
161 
162 		if (_lcr_id && _lcr_id!=j) continue;
163 
164 		rules = rule_pt[j];
165 
166 		for(i = 0; i < lcr_rule_hash_size_param; i++) {
167 			rule = rules[i];
168 			while(rule) {
169 				if (_filter_by_prefix && _prefix.len && _prefix.s) {
170 					if (_prefix.len < rule->prefix_len ||
171 						strncmp(_prefix.s, rule->prefix,  rule->prefix_len)!=0) {
172 						rule = rule->next;
173 						continue;
174 					}
175 				}
176 				if (srec==NULL) {
177 					/* We create one array per lcr_id */
178 					if(rpc->add(c, "{", &rec) < 0)
179 						return;
180 					if(rpc->struct_add(rec, "[", "rule", &srec) < 0)
181 						return;
182 				}
183 				if(rpc->array_add(srec, "{", &st) < 0)
184 					return;
185 				prefix.s = rule->prefix;
186 				prefix.len = rule->prefix_len;
187 				from_uri.s = rule->from_uri;
188 				from_uri.len = rule->from_uri_len;
189 				request_uri.s = rule->request_uri;
190 				request_uri.len = rule->request_uri_len;
191 				rpc->struct_add(st, "ddSSSd", "lcr_id", j, "rule_id",
192 						rule->rule_id, "prefix", &prefix, "from_uri", &from_uri,
193 						"request_uri", &request_uri, "stopper", rule->stopper);
194 				t = rule->targets;
195 				if (t) {
196 					if (rpc->struct_add(st, "[", "gw", &sst) < 0)
197 						return;
198 					while(t) {
199 						if (rpc->array_add(sst, "{", &ssst) < 0)
200 							return;
201 						rpc->struct_add(ssst, "ddd", "gw_index", t->gw_index,
202 								"priority", t->priority, "weight", t->weight);
203 						t = t->next;
204 					}
205 				}
206 				rule = rule->next;
207 			}
208 		}
209 
210 		/* Mark the end of rule array */
211 		srec = NULL;
212 
213 		if (_filter_by_prefix)
214 			continue;
215 		rule = rules[lcr_rule_hash_size_param];
216 		if (rule) {
217 			if(rpc->struct_add(rec, "[", "prefix_len", &st) < 0)
218 				return;
219 			while(rule) {
220 				rpc->array_add(st, "d", rule->prefix_len);
221 				rule = rule->next;
222 			}
223 		}
224 	}
225 	if (rec==NULL) rpc->fault(c, 404, "Empty reply");
226 }
227 
228 
229 static const char *defunct_gw_doc[2] = {
230 		"Defunct gateway until specified time (Unix timestamp).", 0};
231 
232 
defunct_gw(rpc_t * rpc,void * c)233 static void defunct_gw(rpc_t *rpc, void *c)
234 {
235 	unsigned int lcr_id, gw_id, until;
236 
237 	if(rpc->scan(c, "ddd", &lcr_id, &gw_id, &until) < 3) {
238 		rpc->fault(c, 400, "lcr_id, gw_id, and timestamp parameters required");
239 		return;
240 	}
241 
242 	if(rpc_defunct_gw(lcr_id, gw_id, until) == 0) {
243 		rpc->fault(c, 400, "parameter value error (see syslog)");
244 	}
245 
246 	return;
247 }
248 
249 static const char *load_gws_doc[2] = {
250 		"Load matching gateways and prints their info in priority order.  "
251 		"Mandatory parameters are lcr_id and uri_user followed by optional "
252 		"parameters caller_uri and request_uri.  Error is reported if an "
253 		"lcr_rule with matching prefix and from_uri has non-null request_uri "
254 		"and request_uri parameter has not been given.",
255 		0};
256 
257 
load_gws(rpc_t * rpc,void * c)258 static void load_gws(rpc_t *rpc, void *c)
259 {
260 	unsigned int lcr_id, i, j;
261 	int gw_count, ret;
262 	str uri_user;
263 	str caller_uri;
264 	str request_uri;
265 	unsigned int gw_indexes[MAX_NO_OF_GWS];
266 	struct gw_info *gws;
267 	void *rec = NULL;
268 	void *st = NULL;
269 
270 	ret = rpc->scan(c, "dS*SS", &lcr_id, &uri_user, &caller_uri, &request_uri);
271 	if(ret == -1) {
272 		rpc->fault(c, 400, "parameter error; if using cli, remember to prefix "
273 						   "numeric uri_user param value with 's:'");
274 		return;
275 	}
276 
277 	if(ret < 4)
278 		request_uri.len = 0;
279 	if(ret < 3)
280 		caller_uri.len = 0;
281 
282 	gw_count = load_gws_dummy(
283 			lcr_id, &uri_user, &caller_uri, &request_uri, &(gw_indexes[0]));
284 
285 	if(gw_count < 0) {
286 		rpc->fault(c, 400, "load_gws excution error (see syslog)");
287 		return;
288 	}
289 
290 	gws = gw_pt[lcr_id];
291 	for(j = 0; j < gw_count; j++) {
292 		if (rec==NULL) {
293 			if(rpc->add(c, "[", &rec) < 0)
294 				return;
295 		}
296 		if(rpc->array_add(rec, "{", &st) < 0)
297 			return;
298 		i = gw_indexes[j];
299 		dump_gw(rpc, st, &gws[i], i, lcr_id);
300 	}
301 
302 	return;
303 }
304 
305 /* clang-format off */
306 rpc_export_t lcr_rpc[] = {
307     {"lcr.reload", reload, reload_doc, 0},
308     {"lcr.dump_gws", dump_gws, dump_gws_doc, 0},
309     {"lcr.dump_rules", dump_rules, dump_rules_doc, 0},
310     {"lcr.defunct_gw", defunct_gw, defunct_gw_doc, 0},
311     {"lcr.load_gws", load_gws, load_gws_doc, 0},
312     {0, 0, 0, 0}
313 };
314 /* clang-format on */
315