1 /**
2  * Copyright (C) 2013 Flowroute LLC (flowroute.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <fcntl.h>
29 
30 #include "../../core/sr_module.h"
31 #include "../../core/route.h"
32 #include "../../core/route_struct.h"
33 #include "../../core/resolve.h"
34 #include "../../core/parser/parse_param.h"
35 #include "../../core/mem/mem.h"
36 #include "../../core/lvalue.h"
37 #include "../../core/str.h"
38 
39 #include "janssonrpc.h"
40 #include "janssonrpc_srv.h"
41 #include "janssonrpc_request.h"
42 #include "janssonrpc_io.h"
43 #include "janssonrpc_server.h"
44 
45 jsonrpc_srv_t* global_srv_list = NULL;
46 
47 unsigned int jsonrpc_min_srv_ttl;
48 
refresh_srv(jsonrpc_srv_t * srv_obj)49 int refresh_srv(jsonrpc_srv_t* srv_obj)
50 {
51 	DEBUG("Refreshing SRV for %.*s\n", STR(srv_obj->srv));
52 	int retval = 0;
53 
54 	if(!srv_obj) {
55 		ERR("Trying to refresh NULL SRV\n");
56 		return -1;
57 	}
58 
59 	unsigned int ttl = ABSOLUTE_MIN_SRV_TTL;
60 	str srv = srv_obj->srv;
61 	jsonrpc_server_group_t* conn_group = srv_obj->cgroup;
62 
63 	if(!conn_group) {
64 		ERR("SRV (%.*s) has no connections\n", STR(srv));
65 		return -1;
66 	}
67 
68 	struct rdata *l, *head;
69 	struct srv_rdata *srv_record;
70 	str name;
71 
72 	jsonrpc_server_group_t* new_grp = NULL;
73 
74 	// dns lookup
75 	head = get_record(srv.s, T_SRV, RES_AR);
76 	if (head == NULL) {
77 		ERR("No SRV record returned for %.*s\n", STR(srv));
78 		return -1;
79 	}
80 
81 	// get all the servers from the srv record
82 	server_list_t* new_servers = NULL;
83 	jsonrpc_server_t* new_server = NULL;
84 	server_list_t* rm_servers = NULL;
85 	jsonrpc_server_t* rm_server = NULL;
86 	int iter = 0;
87 	for (l=head, iter=0; l; l=l->next, iter++) {
88 		if (l->type != T_SRV)
89 			continue;
90 		srv_record = (struct srv_rdata*)l->rdata;
91 		if (srv_record == NULL) {
92 			ERR("BUG: null rdata\n");
93 			return -1;
94 		}
95 
96 		if (l->ttl < jsonrpc_min_srv_ttl) {
97 			ttl = jsonrpc_min_srv_ttl;
98 		} else {
99 			ttl = l->ttl;
100 		}
101 
102 		srv_obj->ttl = ttl;
103 
104 		name.s = srv_record->name;
105 		name.len = srv_record->name_len;
106 
107 		DBG("server %s\n", srv_record->name);
108 
109 		jsonrpc_server_group_t* cgroup = NULL;
110 		for(cgroup=conn_group; cgroup!=NULL; cgroup=cgroup->next) {
111 			new_server = create_server();
112 			CHECK_MALLOC(new_server);
113 
114 			shm_str_dup(&new_server->conn, &cgroup->conn);
115 			CHECK_MALLOC(new_server->conn.s);
116 
117 			shm_str_dup(&new_server->addr, &name);
118 			CHECK_MALLOC(new_server->addr.s);
119 
120 			shm_str_dup(&new_server->srv, &srv);
121 			CHECK_MALLOC(new_server->srv.s);
122 
123 			new_server->port = srv_record->port;
124 			new_server->priority = srv_record->priority;
125 			new_server->weight = srv_record->weight;
126 			new_server->ttl = ttl;
127 			new_server->added = false;
128 
129 			addto_server_list(new_server, &new_servers);
130 		}
131 	}
132 
133 	if(iter <= 0) goto end;
134 
135 	/* aquire global_server_group lock */
136 	/* this lock is only released when the old global_server_group
137 	 * is freed in the IO process */
138 	lock_get(jsonrpc_server_group_lock); /* blocking */
139 	//print_group(global_server_group); /* debug */
140 
141 
142 	INIT_SERVER_LOOP
143 
144 	// copy existing servers
145 	server_list_t* node;
146 	FOREACH_SERVER_IN(global_server_group)
147 		server->added = false;
148 		if(STR_EQ(server->srv, srv)) {
149 			for(node=new_servers; node!=NULL; node=node->next) {
150 				new_server = node->server;
151 				if(server_eq(new_server, server)) {
152 					new_server->added = true;
153 					server->added = true;
154 					server->ttl = srv_obj->ttl;
155 					jsonrpc_add_server(server, &new_grp);
156 				}
157 			}
158 		} else {
159 			server->added = true;
160 			jsonrpc_add_server(server, &new_grp);
161 		}
162 	ENDFOR
163 
164 	FOREACH_SERVER_IN(global_server_group)
165 		if(server->added == false) {
166 			addto_server_list(server, &rm_servers);
167 		}
168 	ENDFOR
169 
170 	// add and connect new servers
171 	for(node=new_servers; node!=NULL; node=node->next) {
172 		new_server = node->server;
173 		if(new_server->added == false) {
174 
175 			jsonrpc_add_server(new_server, &new_grp);
176 
177 			if(send_pipe_cmd(CMD_CONNECT, new_server) <0) {
178 				print_server(new_server);
179 			}
180 
181 		} else {
182 			free_server(new_server);
183 		}
184 	}
185 
186 	// close old servers
187 	for(node=rm_servers; node!=NULL; node=node->next) {
188 
189 		rm_server = node->server;
190 
191 		if(send_pipe_cmd(CMD_CLOSE, rm_server) <0) {
192 			print_server(rm_server);
193 		}
194 	}
195 
196 	if(send_pipe_cmd(CMD_UPDATE_SERVER_GROUP, new_grp)<0) {
197 		free_server_group(&new_grp);
198 		lock_release(jsonrpc_server_group_lock);
199 	}
200 
201 end:
202 	// free server lists
203 	free_server_list(new_servers);
204 	free_server_list(rm_servers);
205 
206 	return retval;
207 }
208 
free_srv(jsonrpc_srv_t * srv)209 void free_srv(jsonrpc_srv_t* srv)
210 {
211 	if(!srv)
212 		return;
213 
214 	CHECK_AND_FREE(srv->srv.s);
215 
216 	free_server_group(&(srv->cgroup));
217 }
218 
create_srv(str srv,str conn,unsigned int ttl)219 jsonrpc_srv_t* create_srv(str srv, str conn, unsigned int ttl)
220 {
221 	jsonrpc_srv_t* new_srv = shm_malloc(sizeof(jsonrpc_srv_t));
222 	if(!new_srv) goto error;
223 	shm_str_dup(&new_srv->srv, &srv);
224 
225 	if (ttl < jsonrpc_min_srv_ttl) {
226 		new_srv->ttl = jsonrpc_min_srv_ttl;
227 	} else {
228 		new_srv->ttl = ttl;
229 	}
230 
231 	if(create_server_group(CONN_GROUP, &(new_srv->cgroup))<0) goto error;
232 	shm_str_dup(&new_srv->cgroup->conn, &conn);
233 	if(!(new_srv->cgroup->conn.s)) return NULL;
234 
235 	return new_srv;
236 error:
237 	ERR("create_srv failed\n");
238 	free_srv(new_srv);
239 	return NULL;
240 }
241 
refresh_srv_cb(unsigned int ticks,void * params)242 void refresh_srv_cb(unsigned int ticks, void* params)
243 {
244 	if(!params) {
245 		ERR("params is (null)\n");
246 		return;
247 	}
248 
249 	if(!global_srv_list) {
250 		return;
251 	}
252 
253 	srv_cb_params_t* p = (srv_cb_params_t*)params;
254 
255 	cmd_pipe = p->cmd_pipe;
256 	jsonrpc_min_srv_ttl = p->srv_ttl;
257 
258 	if(cmd_pipe == 0) {
259 		ERR("cmd_pipe is not set\n");
260 		return;
261 	}
262 
263 	jsonrpc_srv_t* srv;
264 	for(srv=global_srv_list; srv!=NULL; srv=srv->next) {
265 		if(ticks % srv->ttl == 0) {
266 			refresh_srv(srv);
267 		}
268 	}
269 
270 }
271 
addto_srv_list(jsonrpc_srv_t * srv,jsonrpc_srv_t ** list)272 void addto_srv_list(jsonrpc_srv_t* srv, jsonrpc_srv_t** list)
273 {
274 	if (*list == NULL) {
275 		*list = srv;
276 		return;
277 	}
278 
279 	jsonrpc_srv_t* node = *list;
280 	jsonrpc_srv_t* prev = *list;
281 	jsonrpc_server_group_t* cgroup;
282 	jsonrpc_server_group_t* cprev;
283 	for(node=*list; node!=NULL; prev=node, node=node->next) {
284 		if(STR_EQ(srv->srv, node->srv)) {
285 			for(cgroup=node->cgroup, cprev=node->cgroup;
286 					cgroup!=NULL;
287 					cprev=cgroup, cgroup=cgroup->next) {
288 				if(STR_EQ(cgroup->conn, srv->cgroup->conn)) {
289 					INFO("Trying to add identical srv\n");
290 					goto clean;
291 				}
292 			}
293 			if(create_server_group(CONN_GROUP, &(cprev->next))<0) goto clean;
294 			shm_str_dup(&cprev->next->conn, &srv->cgroup->conn);
295 			CHECK_MALLOC_GOTO(cprev->next->conn.s, clean);
296 			node->ttl = srv->ttl;
297 			goto clean;
298 		}
299 	}
300 
301 	prev->next = srv;
302 	return;
303 clean:
304 	free_srv(srv);
305 }
306 
print_srv(jsonrpc_srv_t * list)307 void print_srv(jsonrpc_srv_t* list)
308 {
309 	INFO("------SRV list------\n");
310 	jsonrpc_srv_t* node = NULL;
311 	for(node=list; node!=NULL; node=node->next) {
312 		INFO("-----------------\n");
313 		INFO("| srv: %.*s\n", STR(node->srv));
314 		INFO("| ttl: %d\n", node->ttl);
315 		print_group(&(node->cgroup));
316 		INFO("-----------------\n");
317 	}
318 }
319 
320