1 /**
2  * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio 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  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <time.h>
26 
27 #include "../../lib/srdb1/db_op.h"
28 #include "../../core/sr_module.h"
29 #include "../../lib/srdb1/db.h"
30 #include "../../core/mem/shm_mem.h"
31 #include "../../core/mem/mem.h"
32 #include "../../core/dprint.h"
33 #include "../../core/parser/parse_uri.h"
34 #include "../../core/timer.h"
35 #include "../../core/ut.h"
36 #include "../../core/locking.h"
37 #include "../../core/action.h"
38 #include "../../core/mod_fix.h"
39 #include "../../core/parser/parse_from.h"
40 #include "../../core/rpc.h"
41 #include "../../core/rpc_lookup.h"
42 #include "../../core/kemi.h"
43 
44 #include "mtree.h"
45 #include "api.h"
46 
47 MODULE_VERSION
48 
49 
50 #define NR_KEYS			3
51 
52 int mt_fetch_rows = 1000;
53 
54 /** database connection */
55 static db1_con_t *db_con = NULL;
56 static db_func_t mt_dbf;
57 
58 #if 0
59 INSERT INTO version (table_name, table_version) values ('mtree','1');
60 CREATE TABLE mtree (
61 		id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
62 		tprefix VARCHAR(32) NOT NULL,
63 		tvalue VARCHAR(128) DEFAULT '' NOT NULL,
64 		CONSTRAINT tprefix_idx UNIQUE (tprefix)
65 		) ENGINE=MyISAM;
66 INSERT INTO version (table_name, table_version) values ('mtrees','1');
67 CREATE TABLE mtrees (
68 		id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
69 		tname VARCHAR(128) NOT NULL,
70 		tprefix VARCHAR(32) NOT NULL,
71 		tvalue VARCHAR(128) DEFAULT '' NOT NULL,
72 		CONSTRAINT tname_tprefix_idx UNIQUE (tname, tprefix)
73 		) ENGINE=MyISAM;
74 #endif
75 
76 /** parameters */
77 static str db_url = str_init(DEFAULT_DB_URL);
78 /* default name created by sql scripts is 'mtrees'
79  * - don't set it here with default value, only via config param */
80 static str db_table = str_init("");
81 static str tname_column   = str_init("tname");
82 static str tprefix_column = str_init("tprefix");
83 static str tvalue_column  = str_init("tvalue");
84 
85 /* List of allowed chars for a prefix*/
86 str mt_char_list = str_init("0123456789");
87 
88 static str value_param = str_init("$avp(s:tvalue)");
89 static str values_param = str_init("$avp(s:tvalues)");
90 static str dstid_param = str_init("$avp(s:tdstid)");
91 static str weight_param = str_init("$avp(s:tweight)");
92 static str count_param = str_init("$avp(s:tcount)");
93 pv_spec_t pv_value;
94 pv_spec_t pv_values;
95 pv_spec_t pv_dstid;
96 pv_spec_t pv_weight;
97 pv_spec_t pv_count;
98 int _mt_tree_type = MT_TREE_SVAL;
99 int _mt_ignore_duplicates = 0;
100 int _mt_allow_duplicates = 0;
101 
102 /* lock, ref counter and flag used for reloading the date */
103 static gen_lock_t *mt_lock = 0;
104 static volatile int mt_tree_refcnt = 0;
105 static volatile int mt_reload_flag = 0;
106 
107 int mt_param(modparam_t type, void *val);
108 static int fixup_mt_match(void** param, int param_no);
109 static int w_mt_match(struct sip_msg* msg, char* str1, char* str2,
110 		char* str3);
111 
112 static int  mod_init(void);
113 static void mod_destroy(void);
114 static int  child_init(int rank);
115 static int mtree_init_rpc(void);
116 static int bind_mtree(mtree_api_t* api);
117 
118 static int mt_match(sip_msg_t *msg, str *tname, str *tomatch,
119 		int mval);
120 
121 static int mt_load_db(m_tree_t *pt);
122 static int mt_load_db_trees();
123 
124 static cmd_export_t cmds[]={
125 	{"mt_match", (cmd_function)w_mt_match, 3, fixup_mt_match,
126 		0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE},
127 	{"bind_mtree", (cmd_function)bind_mtree, 0, 0, 0},
128 	{0, 0, 0, 0, 0, 0}
129 };
130 
131 static param_export_t params[]={
132 	{"mtree",          PARAM_STRING|USE_FUNC_PARAM, (void*)mt_param},
133 	{"db_url",         PARAM_STR, &db_url},
134 	{"db_table",       PARAM_STR, &db_table},
135 	{"tname_column",   PARAM_STR, &tname_column},
136 	{"tprefix_column", PARAM_STR, &tprefix_column},
137 	{"tvalue_column",  PARAM_STR, &tvalue_column},
138 	{"char_list",      PARAM_STR, &mt_char_list},
139 	{"fetch_rows",     INT_PARAM, &mt_fetch_rows},
140 	{"pv_value",       PARAM_STR, &value_param},
141 	{"pv_values",      PARAM_STR, &values_param},
142 	{"pv_dstid",       PARAM_STR, &dstid_param},
143 	{"pv_weight",      PARAM_STR, &weight_param},
144 	{"pv_count",       PARAM_STR, &count_param},
145 	{"mt_tree_type",   INT_PARAM, &_mt_tree_type},
146 	{"mt_ignore_duplicates", INT_PARAM, &_mt_ignore_duplicates},
147 	{"mt_allow_duplicates", INT_PARAM, &_mt_allow_duplicates},
148 	{0, 0, 0}
149 };
150 
151 struct module_exports exports = {
152 	"mtree",
153 	DEFAULT_DLFLAGS,/* dlopen flags */
154 	cmds,		/*·exported·functions·*/
155 	params,		/*·exported·functions·*/
156 	0,		/*·exported·RPC·methods·*/
157 	0,		/* exported pseudo-variables */
158 	0,		/* response·function */
159 	mod_init,	/* module initialization function */
160 	child_init,	/* per child init function */
161 	mod_destroy	/* destroy function */
162 };
163 
164 
165 /**
166  * init module function
167  */
mod_init(void)168 static int mod_init(void)
169 {
170 	m_tree_t *pt = NULL;
171 
172 	if(mtree_init_rpc()!=0)
173 	{
174 		LM_ERR("failed to register RPC commands\n");
175 		return -1;
176 	}
177 
178 	if(pv_parse_spec(&value_param, &pv_value)<00
179 			|| !(pv_is_w(&pv_value)))
180 	{
181 		LM_ERR("cannot parse value pv or is read only\n");
182 		return -1;
183 	}
184 
185 	if (pv_parse_spec(&values_param, &pv_values) <0
186 			|| pv_values.type != PVT_AVP) {
187 		LM_ERR("cannot parse values avp\n");
188 		return -1;
189 	}
190 
191 	if(pv_parse_spec(&dstid_param, &pv_dstid)<0
192 			|| pv_dstid.type!=PVT_AVP)
193 	{
194 		LM_ERR("cannot parse dstid avp\n");
195 		return -1;
196 	}
197 
198 	if(pv_parse_spec(&weight_param, &pv_weight)<0
199 			|| pv_weight.type!=PVT_AVP)
200 	{
201 		LM_ERR("cannot parse dstid avp\n");
202 		return -1;
203 	}
204 
205 	if(pv_parse_spec(&count_param, &pv_count)<0
206 			|| !(pv_is_w(&pv_weight)))
207 	{
208 		LM_ERR("cannot parse count pv or is read-only\n");
209 		return -1;
210 	}
211 
212 	if(mt_fetch_rows<=0)
213 		mt_fetch_rows = 1000;
214 
215 	if(mt_char_list.len<=0)
216 	{
217 		LM_ERR("invalid prefix char list\n");
218 		return -1;
219 	}
220 	LM_DBG("mt_char_list=%s \n", mt_char_list.s);
221 	mt_char_table_init();
222 
223 	/* binding to mysql module */
224 	if(db_bind_mod(&db_url, &mt_dbf))
225 	{
226 		LM_ERR("database module not found\n");
227 		return -1;
228 	}
229 
230 	if (!DB_CAPABILITY(mt_dbf, DB_CAP_ALL))
231 	{
232 		LM_ERR("database module does not "
233 				"implement all functions needed by the module\n");
234 		return -1;
235 	}
236 
237 	/* open a connection with the database */
238 	db_con = mt_dbf.init(&db_url);
239 	if(db_con==NULL)
240 	{
241 		LM_ERR("failed to connect to the database\n");
242 		return -1;
243 	}
244 
245 	LM_DBG("database connection opened successfully\n");
246 
247 	if ( (mt_lock=lock_alloc())==0) {
248 		LM_CRIT("failed to alloc lock\n");
249 		goto error1;
250 	}
251 	if (lock_init(mt_lock)==0 ) {
252 		LM_CRIT("failed to init lock\n");
253 		goto error1;
254 	}
255 
256 	if(mt_defined_trees())
257 	{
258 		LM_DBG("static trees defined\n");
259 
260 		pt = mt_get_first_tree();
261 
262 		while(pt!=NULL)
263 		{
264 			LM_DBG("loading from tree <%.*s>\n",
265 					pt->tname.len, pt->tname.s);
266 
267 			/* loading all information from database */
268 			if(mt_load_db(pt)!=0)
269 			{
270 				LM_ERR("cannot load info from database\n");
271 				goto error1;
272 			}
273 			pt = pt->next;
274 		}
275 		/* reset db_table value */
276 		db_table.s = "";
277 		db_table.len = 0;
278 	} else {
279 		if(db_table.len<=0)
280 		{
281 			LM_ERR("no trees table defined\n");
282 			goto error1;
283 		}
284 		if(mt_init_list_head()<0)
285 		{
286 			LM_ERR("unable to init trees list head\n");
287 			goto error1;
288 		}
289 		/* loading all information from database */
290 		if(mt_load_db_trees()!=0)
291 		{
292 			LM_ERR("cannot load trees from database\n");
293 			goto error1;
294 		}
295 	}
296 	mt_dbf.close(db_con);
297 	db_con = 0;
298 
299 #if 0
300 	mt_print_tree(mt_get_first_tree());
301 #endif
302 
303 	/* success code */
304 	return 0;
305 
306 error1:
307 	if (mt_lock)
308 	{
309 		lock_destroy( mt_lock );
310 		lock_dealloc( mt_lock );
311 		mt_lock = 0;
312 	}
313 	mt_destroy_trees();
314 
315 	if(db_con!=NULL)
316 		mt_dbf.close(db_con);
317 	db_con = 0;
318 	return -1;
319 }
320 
mt_child_init(void)321 static int mt_child_init(void)
322 {
323 	db_con = mt_dbf.init(&db_url);
324 	if(db_con==NULL)
325 	{
326 		LM_ERR("failed to connect to database\n");
327 		return -1;
328 	}
329 
330 	return 0;
331 }
332 
333 
334 /* each child get a new connection to the database */
child_init(int rank)335 static int child_init(int rank)
336 {
337 	/* skip child init for non-worker process ranks */
338 	if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
339 		return 0;
340 
341 	if ( mt_child_init()!=0 )
342 		return -1;
343 
344 	LM_DBG("#%d: database connection opened successfully\n", rank);
345 
346 	return 0;
347 }
348 
349 
mod_destroy(void)350 static void mod_destroy(void)
351 {
352 	LM_DBG("cleaning up\n");
353 	mt_destroy_trees();
354 	if (db_con!=NULL && mt_dbf.close!=NULL)
355 		mt_dbf.close(db_con);
356 	/* destroy lock */
357 	if (mt_lock)
358 	{
359 		lock_destroy( mt_lock );
360 		lock_dealloc( mt_lock );
361 		mt_lock = 0;
362 	}
363 
364 }
365 
fixup_mt_match(void ** param,int param_no)366 static int fixup_mt_match(void** param, int param_no)
367 {
368 	if(param_no==1 || param_no==2) {
369 		return fixup_spve_null(param, 1);
370 	}
371 	if (param_no != 3)	{
372 		LM_ERR("invalid parameter number %d\n", param_no);
373 		return E_UNSPEC;
374 	}
375 	return fixup_igp_null(param, 1);
376 }
377 
378 
379 /* use tree tn, match var, by mode, output in avp params */
mt_match(sip_msg_t * msg,str * tname,str * tomatch,int mval)380 static int mt_match(sip_msg_t *msg, str *tname, str *tomatch,
381 		int mval)
382 {
383 	m_tree_t *tr = NULL;
384 
385 	if(msg==NULL) {
386 		LM_ERR("received null msg\n");
387 		return -1;
388 	}
389 
390 again:
391 	lock_get( mt_lock );
392 	if (mt_reload_flag) {
393 		lock_release( mt_lock );
394 		sleep_us(5);
395 		goto again;
396 	}
397 	mt_tree_refcnt++;
398 	lock_release( mt_lock );
399 
400 	tr = mt_get_tree(tname);
401 	if(tr==NULL) {
402 		/* no tree with such name*/
403 		goto error;
404 	}
405 
406 	if(mt_match_prefix(msg, tr, tomatch, mval)<0)
407 	{
408 		LM_DBG("no prefix found in [%.*s] for [%.*s]\n",
409 				tname->len, tname->s,
410 				tomatch->len, tomatch->s);
411 		goto error;
412 	}
413 
414 	lock_get( mt_lock );
415 	mt_tree_refcnt--;
416 	lock_release( mt_lock );
417 	return 1;
418 
419 error:
420 	lock_get( mt_lock );
421 	mt_tree_refcnt--;
422 	lock_release( mt_lock );
423 	return -1;
424 }
425 
w_mt_match(struct sip_msg * msg,char * ptn,char * pvar,char * pmode)426 static int w_mt_match(struct sip_msg* msg, char* ptn, char* pvar,
427 		char* pmode)
428 {
429 	str tname;
430 	str tomatch;
431 	int mval;
432 
433 	if(msg==NULL)
434 	{
435 		LM_ERR("received null msg\n");
436 		return -1;
437 	}
438 
439 	if(fixup_get_svalue(msg, (gparam_t*)ptn, &tname)<0)
440 	{
441 		LM_ERR("cannot get the tree name\n");
442 		return -1;
443 	}
444 	if(fixup_get_svalue(msg, (gparam_t*)pvar, &tomatch)<0)
445 	{
446 		LM_ERR("cannot get the match var\n");
447 		return -1;
448 	}
449 	if(fixup_get_ivalue(msg, (gparam_t*)pmode, &mval)<0)
450 	{
451 		LM_ERR("cannot get the mode\n");
452 		return -1;
453 	}
454 
455 	return mt_match(msg, &tname, &tomatch, mval);
456 }
457 
mt_param(modparam_t type,void * val)458 int mt_param(modparam_t type, void *val)
459 {
460 	if(val==NULL)
461 		goto error;
462 
463 	return mt_table_spec((char*)val);
464 error:
465 	return -1;
466 
467 }
468 
mt_pack_values(m_tree_t * pt,db1_res_t * db_res,int row,int cols,str * tvalue)469 static int mt_pack_values(m_tree_t *pt, db1_res_t* db_res,
470 		int row, int cols, str *tvalue)
471 {
472 	static char vbuf[4096];
473 	int c;
474 	int len;
475 	char *p;
476 	str iv;
477 
478 	len = 0;
479 	for(c=1; c<cols; c++) {
480 		if(VAL_NULL(&RES_ROWS(db_res)[row].values[c])) {
481 			len += 1;
482 		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STRING) {
483 			len += strlen(RES_ROWS(db_res)[row].values[c].val.string_val);
484 		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STR) {
485 			len += RES_ROWS(db_res)[row].values[c].val.str_val.len;
486 		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_INT) {
487 			len += 12;
488 		} else {
489 			LM_ERR("unsupported data type for column %d\n", c);
490 			return -1;
491 		}
492 	}
493 	if(len + c>=4096) {
494 		LM_ERR("too large values (need %d)\n", len+c);
495 		return -1;
496 	}
497 	p = vbuf;
498 	for(c=1; c<cols; c++) {
499 		if(VAL_NULL(&RES_ROWS(db_res)[row].values[c])) {
500 			*p = pt->pack[2];
501 			p++;
502 		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STRING) {
503 			strcpy(p, RES_ROWS(db_res)[row].values[c].val.string_val);
504 			p += strlen(RES_ROWS(db_res)[row].values[c].val.string_val);
505 		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STR) {
506 			strncpy(p, RES_ROWS(db_res)[row].values[c].val.str_val.s,
507 				RES_ROWS(db_res)[row].values[c].val.str_val.len);
508 			p += RES_ROWS(db_res)[row].values[c].val.str_val.len;
509 		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_INT) {
510 			iv.s = sint2str(RES_ROWS(db_res)[row].values[c].val.int_val, &iv.len);
511 			strncpy(p, iv.s, iv.len);
512 			p += iv.len;
513 		}
514 		if(c+1<cols) {
515 			*p = pt->pack[1];
516 			p++;
517 		}
518 	}
519 	tvalue->s = vbuf;
520 	tvalue->len = p - vbuf;
521 	LM_DBG("packed: [%.*s]\n", tvalue->len, tvalue->s);
522 	return 0;
523 }
524 
mt_load_db(m_tree_t * pt)525 static int mt_load_db(m_tree_t *pt)
526 {
527 	db_key_t db_cols[MT_MAX_COLS] = {&tprefix_column, &tvalue_column};
528 	db_key_t key_cols[1];
529 	db_op_t op[1] = {OP_EQ};
530 	db_val_t vals[1];
531 	str tprefix, tvalue;
532 	db1_res_t* db_res = NULL;
533 	int i, ret, c;
534 	m_tree_t new_tree;
535 	m_tree_t *old_tree = NULL;
536 	mt_node_t *bk_head = NULL;
537 
538 	if(pt->ncols>0) {
539 		for(c=0; c<pt->ncols; c++) {
540 			db_cols[c] = &pt->scols[c];
541 		}
542 	} else {
543 		db_cols[0] = &tprefix_column;
544 		db_cols[1] = &tvalue_column;
545 		c = 2;
546 	}
547 	key_cols[0] = &tname_column;
548 	VAL_TYPE(vals) = DB1_STRING;
549 	VAL_NULL(vals) = 0;
550 	VAL_STRING(vals) = pt->tname.s;
551 
552 	if(db_con==NULL)
553 	{
554 		LM_ERR("no db connection\n");
555 		return -1;
556 	}
557 
558 	old_tree = mt_get_tree(&(pt->tname));
559 	if(old_tree==NULL)
560 	{
561 		LM_ERR("tree definition not found [%.*s]\n", pt->tname.len,
562 				pt->tname.s);
563 		return -1;
564 	}
565 	memcpy(&new_tree, old_tree, sizeof(m_tree_t));
566 	new_tree.head = 0;
567 	new_tree.next = 0;
568 	new_tree.nrnodes = 0;
569 	new_tree.nritems = 0;
570 	new_tree.memsize = 0;
571 	new_tree.reload_count++;
572 	new_tree.reload_time = (unsigned int)time(NULL);
573 
574 
575 	if (mt_dbf.use_table(db_con, &old_tree->dbtable) < 0)
576 	{
577 		LM_ERR("failed to use_table\n");
578 		return -1;
579 	}
580 
581 	if (DB_CAPABILITY(mt_dbf, DB_CAP_FETCH)) {
582 		if(mt_dbf.query(db_con, key_cols, op, vals, db_cols, pt->multi,
583 				c, 0, 0) < 0)
584 		{
585 			LM_ERR("Error while querying db\n");
586 			return -1;
587 		}
588 		if(mt_dbf.fetch_result(db_con, &db_res, mt_fetch_rows)<0)
589 		{
590 			LM_ERR("Error while fetching result\n");
591 			goto error;
592 		} else {
593 			if(RES_ROW_N(db_res)==0)
594 			{
595 				goto dbreloaded;
596 			}
597 		}
598 	} else {
599 		if((ret=mt_dbf.query(db_con, key_cols, op, vals, db_cols,
600 						pt->multi, 2, 0, &db_res))!=0
601 				|| RES_ROW_N(db_res)<=0 )
602 		{
603 			if(ret==0)
604 			{
605 				goto dbreloaded;
606 			} else {
607 				goto error;
608 			}
609 		}
610 	}
611 
612 	if(RES_ROW_N(db_res)>0)
613 	{
614 		if(RES_ROWS(db_res)[0].values[0].type != DB1_STRING
615 				|| RES_ROWS(db_res)[0].values[1].type != DB1_STRING)
616 		{
617 			LM_ERR("wrond column types in db table (%d / %d)\n",
618 					RES_ROWS(db_res)[0].values[0].type,
619 					RES_ROWS(db_res)[0].values[1].type);
620 			goto error;
621 		}
622 	}
623 
624 	do {
625 		for(i=0; i<RES_ROW_N(db_res); i++)
626 		{
627 			/* check for NULL values ?!?! */
628 			tprefix.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
629 			tprefix.len = strlen(ZSW(tprefix.s));
630 
631 			if(c>2) {
632 				if(mt_pack_values(&new_tree, db_res, i, c, &tvalue)<0) {
633 					LM_ERR("Error packing values\n");
634 					goto error;
635 				}
636 			} else {
637 				tvalue.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val);
638 				tvalue.len = strlen(ZSW(tvalue.s));
639 			}
640 
641 			if(tprefix.s==NULL || tvalue.s==NULL
642 					|| tprefix.len<=0 || tvalue.len<=0)
643 			{
644 				LM_ERR("Error - bad record in db"
645 						" (prefix: %p/%d - value: %p/%d)\n",
646 						tprefix.s, tprefix.len, tvalue.s, tvalue.len);
647 				continue;
648 			}
649 
650 			if(mt_add_to_tree(&new_tree, &tprefix, &tvalue)<0)
651 			{
652 				LM_ERR("Error adding info to tree\n");
653 				goto error;
654 			}
655 		}
656 		if (DB_CAPABILITY(mt_dbf, DB_CAP_FETCH)) {
657 			if(mt_dbf.fetch_result(db_con, &db_res, mt_fetch_rows)<0) {
658 				LM_ERR("Error while fetching!\n");
659 				if (db_res)
660 					mt_dbf.free_result(db_con, db_res);
661 				goto error;
662 			}
663 		} else {
664 			break;
665 		}
666 	}  while(RES_ROW_N(db_res)>0);
667 
668 dbreloaded:
669 	mt_dbf.free_result(db_con, db_res);
670 
671 
672 	/* block all readers */
673 	lock_get( mt_lock );
674 	mt_reload_flag = 1;
675 	lock_release( mt_lock );
676 
677 	while (mt_tree_refcnt) {
678 		sleep_us(10);
679 	}
680 
681 	bk_head = old_tree->head;
682 	old_tree->head = new_tree.head;
683 	old_tree->nrnodes = new_tree.nrnodes;
684 	old_tree->nritems = new_tree.nritems;
685 	old_tree->memsize = new_tree.memsize;
686 	old_tree->reload_count = new_tree.reload_count;
687 	old_tree->reload_time  = new_tree.reload_time;
688 
689 	mt_reload_flag = 0;
690 
691 	/* free old data */
692 	if (bk_head!=NULL)
693 		mt_free_node(bk_head, new_tree.type);
694 
695 	return 0;
696 
697 error:
698 	mt_dbf.free_result(db_con, db_res);
699 	if (new_tree.head!=NULL)
700 		mt_free_node(new_tree.head, new_tree.type);
701 	return -1;
702 }
703 
mt_load_db_trees()704 static int mt_load_db_trees()
705 {
706 	db_key_t db_cols[3] = {&tname_column, &tprefix_column, &tvalue_column};
707 	str tprefix, tvalue, tname;
708 	db1_res_t* db_res = NULL;
709 	int i, ret;
710 	m_tree_t *new_head = NULL;
711 	m_tree_t *new_tree = NULL;
712 	m_tree_t *old_head = NULL;
713 
714 	if(db_con==NULL)
715 	{
716 		LM_ERR("no db connection\n");
717 		return -1;
718 	}
719 
720 	if (mt_dbf.use_table(db_con, &db_table) < 0)
721 	{
722 		LM_ERR("failed to use_table\n");
723 		return -1;
724 	}
725 
726 	if (DB_CAPABILITY(mt_dbf, DB_CAP_FETCH))
727 	{
728 		if(mt_dbf.query(db_con,0,0,0,db_cols,0,3,&tname_column,0) < 0)
729 		{
730 			LM_ERR("Error while querying db\n");
731 			return -1;
732 		}
733 		if(mt_dbf.fetch_result(db_con, &db_res, mt_fetch_rows)<0)
734 		{
735 			LM_ERR("Error while fetching result\n");
736 			if (db_res)
737 				mt_dbf.free_result(db_con, db_res);
738 			goto error;
739 		} else {
740 			if(RES_ROW_N(db_res)==0)
741 			{
742 				return 0;
743 			}
744 		}
745 	} else {
746 		if((ret=mt_dbf.query(db_con, NULL, NULL, NULL, db_cols,
747 						0, 3, &tname_column, &db_res))!=0
748 				|| RES_ROW_N(db_res)<=0 )
749 		{
750 			mt_dbf.free_result(db_con, db_res);
751 			if( ret==0)
752 			{
753 				return 0;
754 			} else {
755 				goto error;
756 			}
757 		}
758 	}
759 
760 	do {
761 		for(i=0; i<RES_ROW_N(db_res); i++)
762 		{
763 			/* check for NULL values ?!?! */
764 			tname.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
765 			tprefix.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val);
766 			tvalue.s = (char*)(RES_ROWS(db_res)[i].values[2].val.string_val);
767 
768 			if(tprefix.s==NULL || tvalue.s==NULL || tname.s==NULL)
769 			{
770 				LM_ERR("Error - null fields in db\n");
771 				continue;
772 			}
773 
774 			tname.len = strlen(tname.s);
775 			tprefix.len = strlen(tprefix.s);
776 			tvalue.len = strlen(tvalue.s);
777 
778 			if(tname.len<=0 || tprefix.len<=0 || tvalue.len<=0)
779 			{
780 				LM_ERR("Error - bad values in db\n");
781 				continue;
782 			}
783 			new_tree = mt_add_tree(&new_head, &tname, &db_table, NULL,
784 							_mt_tree_type, 0);
785 			if(new_tree==NULL)
786 			{
787 				LM_ERR("New tree cannot be initialized\n");
788 				goto error;
789 			}
790 			if(mt_add_to_tree(new_tree, &tprefix, &tvalue)<0)
791 			{
792 				LM_ERR("Error adding info to tree\n");
793 				goto error;
794 			}
795 		}
796 		if (DB_CAPABILITY(mt_dbf, DB_CAP_FETCH)) {
797 			if(mt_dbf.fetch_result(db_con, &db_res, mt_fetch_rows)<0) {
798 				LM_ERR("Error while fetching!\n");
799 				if (db_res)
800 					mt_dbf.free_result(db_con, db_res);
801 				goto error;
802 			}
803 		} else {
804 			break;
805 		}
806 	} while(RES_ROW_N(db_res)>0);
807 	mt_dbf.free_result(db_con, db_res);
808 
809 	/* block all readers */
810 	lock_get( mt_lock );
811 	mt_reload_flag = 1;
812 	lock_release( mt_lock );
813 
814 	while (mt_tree_refcnt) {
815 		sleep_us(10);
816 	}
817 
818 	old_head = mt_swap_list_head(new_head);
819 
820 	mt_reload_flag = 0;
821 	/* free old data */
822 	if (old_head!=NULL)
823 		mt_free_tree(old_head);
824 
825 	return 0;
826 
827 error:
828 	mt_dbf.free_result(db_con, db_res);
829 	if (new_head!=NULL)
830 		mt_free_tree(new_head);
831 	return -1;
832 }
833 
834 
835 /* RPC commands */
rpc_mtree_summary(rpc_t * rpc,void * c)836 void rpc_mtree_summary(rpc_t* rpc, void* c)
837 {
838 	str tname = {0, 0};
839 	m_tree_t *pt;
840 	void* th;
841 	void* ih;
842 	int found;
843 
844 	if(!mt_defined_trees())
845 	{
846 		rpc->fault(c, 500, "Empty tree list");
847 		return;
848 	}
849 
850 	/* read optional tree name */
851 	if(rpc->scan(c, "*S", &tname)==0)
852 	{
853 		tname.s = NULL;
854 		tname.len = 0;
855 	}
856 
857 	pt = mt_get_first_tree();
858 	if(pt==NULL)
859 	{
860 		rpc->fault(c, 404, "No tree");
861 		return;
862 	}
863 
864 	found = 0;
865 	while(pt!=NULL)
866 	{
867 		if(tname.s==NULL
868 				|| (tname.s!=NULL && pt->tname.len>=tname.len
869 					&& strncmp(pt->tname.s, tname.s, tname.len)==0))
870 		{
871 			found = 1;
872 			if (rpc->add(c, "{", &th) < 0)
873 			{
874 				rpc->fault(c, 500, "Internal error creating rpc");
875 				return;
876 			}
877 			if(rpc->struct_add(th, "s{",
878 						"table", pt->tname.s,
879 						"item", &ih) < 0)
880 			{
881 				rpc->fault(c, 500, "Internal error creating rpc ih");
882 				return;
883 			}
884 			if(rpc->struct_add(ih, "d", "ttype", pt->type) < 0 ) {
885 				rpc->fault(c, 500, "Internal error adding type");
886 				return;
887 			}
888 			if(rpc->struct_add(ih, "d", "memsize", pt->memsize) < 0 ) {
889 				rpc->fault(c, 500, "Internal error adding memsize");
890 				return;
891 			}
892 			if(rpc->struct_add(ih, "d", "nrnodes", pt->nrnodes) < 0 ) {
893 				rpc->fault(c, 500, "Internal error adding nodes");
894 				return;
895 			}
896 			if(rpc->struct_add(ih, "d", "nritems", pt->nritems) < 0 ) {
897 				rpc->fault(c, 500, "Internal error adding items");
898 				return;
899 			}
900 			if(rpc->struct_add(ih, "d", "reload_count",
901 						(int)pt->reload_count) < 0 ) {
902 				rpc->fault(c, 500, "Internal error adding items");
903 				return;
904 			}
905 			if(rpc->struct_add(ih, "d", "reload_time",
906 						(int)pt->reload_time) < 0 ) {
907 				rpc->fault(c, 500, "Internal error adding items");
908 				return;
909 			}
910 		}
911 		pt = pt->next;
912 	}
913 
914 	if(found==0)
915 	{
916 		rpc->fault(c, 404, "Tree not found");
917 		return;
918 	}
919 
920 	return;
921 }
922 
923 static const char* rpc_mtree_summary_doc[2] = {
924 	"Print summary of loaded mtree tables",
925 	0
926 };
927 
rpc_mtree_reload(rpc_t * rpc,void * c)928 void rpc_mtree_reload(rpc_t* rpc, void* c)
929 {
930 	str tname = {0, 0};
931 	m_tree_t *pt = NULL;
932 	int treloaded = 0;
933 
934 	if(db_table.len>0)
935 	{
936 		/* re-loading all information from database */
937 		if(mt_load_db_trees()!=0)
938 		{
939 			LM_ERR("cannot re-load mtrees from database\n");
940 			goto error;
941 		}
942 	} else {
943 		if(!mt_defined_trees())
944 		{
945 			LM_ERR("empty mtree list\n");
946 			goto error;
947 		}
948 
949 		/* read tree name */
950 		if (rpc->scan(c, "S", &tname) != 1) {
951 			tname.s = 0;
952 			tname.len = 0;
953 		} else {
954 			if(*tname.s=='.') {
955 				tname.s = 0;
956 				tname.len = 0;
957 			}
958 		}
959 
960 		pt = mt_get_first_tree();
961 
962 		while(pt!=NULL)
963 		{
964 			if(tname.s==NULL
965 					|| (tname.s!=NULL && pt->tname.len>=tname.len
966 						&& strncmp(pt->tname.s, tname.s, tname.len)==0))
967 			{
968 				/* re-loading table from database */
969 				if(mt_load_db(pt)!=0)
970 				{
971 					LM_ERR("cannot re-load mtree from database\n");
972 					goto error;
973 				}
974 				treloaded = 1;
975 			}
976 			pt = pt->next;
977 		}
978 		if(treloaded == 0) {
979 			rpc->fault(c, 500, "No Mtree Name Matching");
980 		}
981 	}
982 
983 	return;
984 
985 error:
986 	rpc->fault(c, 500, "Mtree Reload Failed");
987 }
988 
989 static const char* rpc_mtree_reload_doc[2] = {
990 	"Reload mtrees from database to memory",
991 	0
992 };
993 
rpc_mtree_match(rpc_t * rpc,void * ctx)994 void rpc_mtree_match(rpc_t* rpc, void* ctx)
995 {
996 	str tname = STR_NULL;
997 	str tomatch = STR_NULL;
998 	int mode = -1;
999 
1000 	m_tree_t *tr;
1001 
1002 	if(!mt_defined_trees())
1003 	{
1004 		rpc->fault(ctx, 500, "Empty tree list.");
1005 		return;
1006 	}
1007 
1008 	if (rpc->scan(ctx, ".SSd", &tname, &tomatch, &mode) < 3) {
1009 		rpc->fault(ctx, 500, "Invalid Parameters");
1010 		return;
1011 	}
1012 
1013 	if (mode !=0 && mode != 2) {
1014 		rpc->fault(ctx, 500, "Invalid parameter 'mode'");
1015 		return;
1016 	}
1017 
1018 again:
1019 	lock_get( mt_lock );
1020 	if (mt_reload_flag) {
1021 		lock_release( mt_lock );
1022 		sleep_us(5);
1023 		goto again;
1024 	}
1025 	mt_tree_refcnt++;
1026 	lock_release( mt_lock );
1027 
1028 	tr = mt_get_tree(&tname);
1029 	if(tr==NULL)
1030 	{
1031 		/* no tree with such name*/
1032 		rpc->fault(ctx, 404, "Not found tree");
1033 		goto error;
1034 	}
1035 
1036 	if(mt_rpc_match_prefix(rpc, ctx, tr, &tomatch, mode)<0)
1037 	{
1038 		LM_DBG("no prefix found in [%.*s] for [%.*s]\n",
1039 				tname.len, tname.s,
1040 				tomatch.len, tomatch.s);
1041 		rpc->fault(ctx, 404, "Not found");
1042 	}
1043 
1044 error:
1045 	lock_get( mt_lock );
1046 	mt_tree_refcnt--;
1047 	lock_release( mt_lock );
1048 
1049 }
1050 
1051 static const char* rpc_mtree_match_doc[6] = {
1052 	"Match prefix value against mtree",
1053 	"uses three required parameters",
1054 	"tname - tree name",
1055 	"prefix - prefix for matching",
1056 	"mode - mode for matching (0 or 2)",
1057 	0
1058 };
1059 
1060 
rpc_mtree_print_node(rpc_t * rpc,void * ctx,m_tree_t * tree,mt_node_t * pt,char * code,int len)1061 int rpc_mtree_print_node(rpc_t* rpc, void* ctx, m_tree_t *tree, mt_node_t *pt,
1062 		char *code, int len)
1063 {
1064 	int i;
1065 	mt_is_t *tvalues;
1066 	str val;
1067 	void* th = NULL;
1068 	void* ih = NULL;
1069 
1070 	if(pt==NULL || len>=MT_MAX_DEPTH)
1071 		return 0;
1072 
1073 	for(i=0; i<MT_NODE_SIZE; i++)
1074 	{
1075 		code[len]=mt_char_list.s[i];
1076 		tvalues = pt[i].tvalues;
1077 		if (tvalues != NULL)
1078 		{
1079 			/* add structure node */
1080 			if (rpc->add(ctx, "{", &th) < 0)
1081 			{
1082 				rpc->fault(ctx, 500, "Internal error - node structure");
1083 				return -1;
1084 			}
1085 
1086 			val.s = code;
1087 			val.len = len+1;
1088 			if(rpc->struct_add(th, "SS[",
1089 				"tname",	&tree->tname,
1090 				"tprefix", 	&val,
1091 				"tvalue",	&ih)<0)
1092 			{
1093 				rpc->fault(ctx, 500, "Internal error - attribute fields");
1094 				return -1;
1095 			}
1096 
1097 			while (tvalues != NULL) {
1098 				if (tree->type == MT_TREE_IVAL) {
1099 					if(rpc->array_add(ih, "u",
1100 								(unsigned long)tvalues->tvalue.n)<0) {
1101 						rpc->fault(ctx, 500, "Internal error - int val");
1102 						return -1;
1103 					}
1104 				} else {
1105 					if(rpc->array_add(ih, "S", &tvalues->tvalue.s)<0) {
1106 						rpc->fault(ctx, 500, "Internal error - str val");
1107 						return -1;
1108 					}
1109 				}
1110 				tvalues = tvalues->next;
1111 			}
1112 		}
1113 		if(rpc_mtree_print_node(rpc, ctx, tree, pt[i].child, code, len+1)<0)
1114 			goto error;
1115 	}
1116 	return 0;
1117 error:
1118 	return -1;
1119 }
1120 
1121 /**
1122  * "mtree.list" syntax :
1123  *    tname
1124  *
1125  * 	- '.' (dot) means NULL value and will match anything
1126  */
rpc_mtree_list(rpc_t * rpc,void * ctx)1127 void rpc_mtree_list(rpc_t* rpc, void* ctx)
1128 {
1129 	str tname = {0, 0};
1130 	m_tree_t *pt;
1131 	static char code_buf[MT_MAX_DEPTH+1];
1132 	int len;
1133 
1134 	if(!mt_defined_trees())
1135 	{
1136 		rpc->fault(ctx, 500, "Empty tree list.");
1137 		return;
1138 	}
1139 
1140 	if(rpc->scan(ctx, "*.S", &tname)!=1) {
1141 		tname.s = NULL;
1142 		tname.len = 0;
1143 	}
1144 
1145 	pt = mt_get_first_tree();
1146 
1147 	while(pt!=NULL)
1148 	{
1149 		if(tname.s==NULL ||
1150 				(tname.s!=NULL && pt->tname.len>=tname.len &&
1151 					strncmp(pt->tname.s, tname.s, tname.len)==0))
1152 		{
1153 			len = 0;
1154 			code_buf[0] = '\0';
1155 			if(rpc_mtree_print_node(rpc, ctx, pt, pt->head, code_buf, len)<0) {
1156 				goto error;
1157 			}
1158 		}
1159 		pt = pt->next;
1160 	}
1161 
1162 	return;
1163 
1164 error:
1165 	LM_ERR("failed to build rpc response\n");
1166 	return;
1167 }
1168 
1169 static const char* rpc_mtree_list_doc[6] = {
1170 	"List the content of one or all trees",
1171 	"Parameters:",
1172 	"tname - tree name (optional)",
1173 	0
1174 };
1175 
1176 
1177 rpc_export_t mtree_rpc[] = {
1178 	{"mtree.summary", rpc_mtree_summary, rpc_mtree_summary_doc, RET_ARRAY},
1179 	{"mtree.reload", rpc_mtree_reload, rpc_mtree_reload_doc, 0},
1180 	{"mtree.match", rpc_mtree_match, rpc_mtree_match_doc, 0},
1181 	{"mtree.list", rpc_mtree_list, rpc_mtree_list_doc, RET_ARRAY},
1182 	{0, 0, 0, 0}
1183 };
1184 
mtree_init_rpc(void)1185 static int mtree_init_rpc(void)
1186 {
1187 	if (rpc_register_array(mtree_rpc) != 0)
1188 	{
1189 		LM_ERR("failed to register RPC commands\n");
1190 		return -1;
1191 	}
1192 	return 0;
1193 }
1194 
1195 
1196 /**
1197  *
1198  */
1199 /* clang-format off */
1200 static sr_kemi_t sr_kemi_mtree_exports[] = {
1201 	{ str_init("mtree"), str_init("mt_match"),
1202 		SR_KEMIP_INT, mt_match,
1203 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
1204 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1205 	},
1206 
1207 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1208 };
1209 /* clang-format on */
1210 
1211 /**
1212  * load mtree module API
1213  */
bind_mtree(mtree_api_t * api)1214 static int bind_mtree(mtree_api_t* api)
1215 {
1216 	if (!api) {
1217 		LM_ERR("Invalid parameter value\n");
1218 		return -1;
1219 	}
1220 	api->mt_match = mt_match;
1221 
1222 	return 0;
1223 }
1224 
1225 
1226 /**
1227  *
1228  */
mod_register(char * path,int * dlflags,void * p1,void * p2)1229 int mod_register(char *path, int *dlflags, void *p1, void *p2)
1230 {
1231 	sr_kemi_modules_add(sr_kemi_mtree_exports);
1232 	return 0;
1233 }
1234