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