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