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 * This file 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 *
14 * This file is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include "../../core/dprint.h"
32 #include "../../core/mem/shm_mem.h"
33 #include "../../core/parser/parse_param.h"
34 #include "../../core/ut.h"
35 #include "../../core/pvar.h"
36 #include "../../core/lvalue.h"
37 #include "../../core/shm_init.h"
38
39 #include "mtree.h"
40
41 //extern str mt_char_list = {"1234567890*",11};
42 extern str mt_char_list;
43 extern pv_spec_t pv_value;
44 extern pv_spec_t pv_values;
45 extern pv_spec_t pv_dstid;
46 extern pv_spec_t pv_weight;
47 extern int _mt_tree_type;
48 extern int _mt_ignore_duplicates;
49 extern int _mt_allow_duplicates;
50
51 /** structures containing prefix-value pairs */
52 static m_tree_t **_ptree = NULL;
53
54 /* quick translation table */
55 #define MT_CHAR_TABLE_SIZE 256
56 #define MT_CHAR_TABLE_NOTSET 255
57 static unsigned char _mt_char_table[MT_CHAR_TABLE_SIZE];
58
59 /**
60 *
61 */
mt_char_table_init(void)62 void mt_char_table_init(void)
63 {
64 unsigned int i;
65 for(i=0; i<MT_CHAR_TABLE_SIZE; i++) {
66 _mt_char_table[i] = MT_CHAR_TABLE_NOTSET;
67 }
68 for(i=0; i<mt_char_list.len; i++) {
69 unsigned char ch = mt_char_list.s[i];
70 _mt_char_table[ch] = (unsigned char)i;
71 }
72 }
73
74
75 /**
76 *
77 */
mt_swap_list_head(m_tree_t * ntree)78 m_tree_t *mt_swap_list_head(m_tree_t *ntree)
79 {
80 m_tree_t *otree;
81
82 otree = *_ptree;
83 *_ptree = ntree;
84
85 return otree;
86 }
87
88 /**
89 *
90 */
mt_init_list_head(void)91 int mt_init_list_head(void)
92 {
93 if(_ptree!=NULL)
94 return 0;
95 _ptree = (m_tree_t**)shm_malloc( sizeof(m_tree_t*) );
96 if (_ptree==0) {
97 LM_ERR("out of shm mem for pdtree\n");
98 return -1;
99 }
100 *_ptree=0;
101 return 0;
102 }
103
104 /**
105 *
106 */
mt_init_tree(str * tname,str * dbtable,str * scols,int type,int multi)107 m_tree_t* mt_init_tree(str* tname, str *dbtable, str *scols, int type,
108 int multi)
109 {
110 m_tree_t *pt = NULL;
111 int i;
112 int c;
113
114 pt = (m_tree_t*)shm_malloc(sizeof(m_tree_t));
115 if(pt==NULL)
116 {
117 LM_ERR("no more shm memory\n");
118 return NULL;
119 }
120 memset(pt, 0, sizeof(m_tree_t));
121
122 pt->type = type;
123 pt->multi = multi;
124 pt->reload_time = (unsigned int)time(NULL);
125 pt->tname.s = (char*)shm_malloc((1+tname->len)*sizeof(char));
126 if(pt->tname.s==NULL)
127 {
128 shm_free(pt);
129 LM_ERR("no more shm memory\n");
130 return NULL;
131 }
132 memset(pt->tname.s, 0, 1+tname->len);
133 memcpy(pt->tname.s, tname->s, tname->len);
134 pt->tname.len = tname->len;
135
136 pt->dbtable.s = (char*)shm_malloc((1+dbtable->len)*sizeof(char));
137 if(pt->dbtable.s==NULL)
138 {
139 shm_free(pt->tname.s);
140 shm_free(pt);
141 LM_ERR("no more shm memory\n");
142 return NULL;
143 }
144 memset(pt->dbtable.s, 0, 1+dbtable->len);
145 memcpy(pt->dbtable.s, dbtable->s, dbtable->len);
146 pt->dbtable.len = dbtable->len;
147
148 if(scols!=NULL && scols->s!=NULL && scols->len>0) {
149 pt->scols[0].s = (char*)shm_malloc((1+scols->len)*sizeof(char));
150 if(pt->scols[0].s==NULL) {
151 shm_free(pt->tname.s);
152 shm_free(pt->dbtable.s);
153 shm_free(pt);
154 LM_ERR("no more shm memory\n");
155 return NULL;
156 }
157 memset(pt->scols[0].s, 0, (1+scols->len)*sizeof(char));
158 memcpy(pt->scols[0].s, scols->s, scols->len);
159 pt->scols[0].len = scols->len;
160 c = 0;
161 for(i=0; i<scols->len; i++) {
162 if(pt->scols[0].s[i]==',') {
163 pt->scols[c].len = (pt->scols[0].s + i - pt->scols[c].s);
164 LM_DBG("db table column[%d]='%.*s'\n", c,
165 pt->scols[c].len, pt->scols[c].s);
166 c++;
167 if(c>=MT_MAX_COLS) {
168 LM_ERR("too many columns %d\n", c);
169 shm_free(pt->scols[0].s);
170 shm_free(pt->tname.s);
171 shm_free(pt->dbtable.s);
172 shm_free(pt);
173 return NULL;
174 }
175 pt->scols[c].s = pt->scols[0].s + i + 1;
176 pt->scols[c].len = pt->scols[0].s + scols->len - pt->scols[c].s;
177 }
178 }
179 LM_DBG("db table column[%d]='%.*s'\n", c,
180 pt->scols[c].len, pt->scols[c].s);
181 if(c==0) {
182 LM_ERR("there must be at least two columns (prefix, value)\n");
183 shm_free(pt->scols[0].s);
184 shm_free(pt->tname.s);
185 shm_free(pt->dbtable.s);
186 shm_free(pt);
187 return NULL;
188 }
189 pt->ncols = c + 1;
190 pt->pack[0] = 'l';
191 pt->pack[1] = ',';
192 pt->pack[2] = '*';
193 }
194
195 return pt;
196 }
197
mt_add_to_tree(m_tree_t * pt,str * sp,str * svalue)198 int mt_add_to_tree(m_tree_t *pt, str *sp, str *svalue)
199 {
200 int l, ivalue = 0;
201 mt_node_t *itn, *itn0;
202 mt_is_t *tvalues;
203 unsigned char mtch;
204
205 if(pt==NULL || sp==NULL || sp->s==NULL
206 || svalue==NULL || svalue->s==NULL)
207 {
208 LM_ERR("bad parameters\n");
209 return -1;
210 }
211
212 if(sp->len>=MT_MAX_DEPTH)
213 {
214 LM_ERR("max prefix len exceeded\n");
215 return -1;
216 }
217
218 LM_DBG("adding to tree <%.*s> of type <%d>\n", pt->tname.len,
219 pt->tname.s, pt->type);
220
221 if ((pt->type == MT_TREE_IVAL) && (str2sint(svalue, &ivalue) != 0)) {
222 LM_ERR("bad integer string <%.*s>\n", svalue->len, svalue->s);
223 return -1;
224 }
225
226 l = 0;
227 if(pt->head == NULL)
228 {
229 pt->head = (mt_node_t*)shm_malloc(MT_NODE_SIZE*sizeof(mt_node_t));
230 if(pt->head == NULL)
231 {
232 LM_ERR("no more shm memory for tree head\n");
233 return -1;
234 }
235 memset(pt->head, 0, MT_NODE_SIZE*sizeof(mt_node_t));
236 pt->nrnodes++;
237 pt->memsize += MT_NODE_SIZE*sizeof(mt_node_t);
238 }
239
240 itn0 = pt->head;
241
242 mtch = _mt_char_table[(unsigned char)sp->s[l]];
243 if(mtch==MT_CHAR_TABLE_NOTSET)
244 {
245 LM_ERR("invalid char at %d in [%.*s] [%c (0x%x)]\n",
246 l, sp->len, sp->s, sp->s[l], sp->s[l]);
247 return -1;
248 }
249 itn = itn0[mtch].child;
250
251 while(l < sp->len-1)
252 {
253 if(itn == NULL)
254 {
255 itn = (mt_node_t*)shm_malloc(MT_NODE_SIZE*sizeof(mt_node_t));
256 if(itn == NULL)
257 {
258 LM_ERR("no more shm mem\n");
259 return -1;
260 }
261 memset(itn, 0, MT_NODE_SIZE*sizeof(mt_node_t));
262 pt->nrnodes++;
263 pt->memsize += MT_NODE_SIZE*sizeof(mt_node_t);
264 itn0[mtch].child = itn;
265 }
266
267 l++;
268 mtch = _mt_char_table[(unsigned char)sp->s[l]];
269 if(mtch==MT_CHAR_TABLE_NOTSET)
270 {
271 LM_ERR("invalid char at %d in [%.*s]\n",
272 l, sp->len, sp->s);
273 return -1;
274 }
275 itn0 = itn;
276 itn = itn0[mtch].child;
277 }
278
279 if(itn0[mtch].tvalues != NULL) {
280 if(_mt_ignore_duplicates != 0) {
281 LM_NOTICE("prefix already allocated [%.*s/%.*s]\n",
282 sp->len, sp->s, svalue->len, svalue->s);
283 return 1;
284 } else if (_mt_allow_duplicates == 0) {
285 LM_ERR("prefix already allocated [%.*s/%.*s]\n",
286 sp->len, sp->s, svalue->len, svalue->s);
287 return -1;
288 }
289 }
290
291 tvalues = (mt_is_t *)shm_malloc(sizeof(mt_is_t));
292 if (tvalues == NULL) {
293 LM_ERR("no more shm mem for tvalue\n");
294 return -1;
295 }
296 memset(tvalues, 0, sizeof(mt_is_t));
297
298 if (pt->type == MT_TREE_IVAL) {
299 tvalues->tvalue.n = ivalue;
300 } else { /* pt->type == MT_TREE_SVAL or MT_TREE_DW */
301 tvalues->tvalue.s.s = (char*)shm_malloc((svalue->len+1)*sizeof(char));
302 if (tvalues->tvalue.s.s == NULL) {
303 LM_ERR("no more shm mem for string\n");
304 return -1;
305 }
306 tvalues->tvalue.s.len = svalue->len;
307 pt->memsize += (svalue->len+1)*sizeof(char);
308 pt->nritems++;
309 strncpy(tvalues->tvalue.s.s, svalue->s, svalue->len);
310 tvalues->tvalue.s.s[svalue->len] = '\0';
311 }
312 tvalues->next = itn0[mtch].tvalues;
313 itn0[mtch].tvalues = tvalues;
314 mt_node_set_payload(&itn0[mtch], pt->type);
315 return 0;
316 }
317
mt_get_tree(str * tname)318 m_tree_t* mt_get_tree(str *tname)
319 {
320 m_tree_t *it;
321 int ret;
322
323 if(_ptree==NULL || *_ptree==NULL)
324 return NULL;
325
326 if( tname==NULL || tname->s==NULL)
327 {
328 LM_ERR("bad parameters\n");
329 return NULL;
330 }
331
332 it = *_ptree;
333 /* search the tree for the asked tname */
334 while(it!=NULL)
335 {
336 ret = str_strcmp(&it->tname, tname);
337 if(ret>0)
338 return NULL;
339 if(ret==0)
340 return it;
341 it = it->next;
342 }
343
344 return it;
345 }
346
mt_get_first_tree()347 m_tree_t* mt_get_first_tree()
348 {
349 if(_ptree==NULL || *_ptree==NULL)
350 return NULL;
351 return *_ptree;
352 }
353
354
mt_get_tvalue(m_tree_t * pt,str * tomatch,int * len)355 is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch, int *len)
356 {
357 int l;
358 mt_node_t *itn;
359 is_t *tvalue;
360
361 if(pt==NULL || tomatch==NULL || tomatch->s==NULL || len == NULL)
362 {
363 LM_ERR("bad parameters\n");
364 return NULL;
365 }
366
367 l = 0;
368 itn = pt->head;
369 tvalue = NULL;
370
371 while(itn!=NULL && l < tomatch->len && l < MT_MAX_DEPTH)
372 {
373 unsigned char mtch = _mt_char_table[(unsigned char)tomatch->s[l]];
374
375 /* check validity */
376 if(mtch==MT_CHAR_TABLE_NOTSET)
377 {
378 LM_DBG("not matching char at %d in [%.*s]\n",
379 l, tomatch->len, tomatch->s);
380 return NULL;
381 }
382
383 if(itn[mtch].tvalues!=NULL)
384 {
385 tvalue = &itn[mtch].tvalues->tvalue;
386 }
387
388 itn = itn[mtch].child;
389 l++;
390 }
391
392 *len = l;
393
394 return tvalue;
395 }
396
mt_add_tvalues(struct sip_msg * msg,m_tree_t * pt,str * tomatch)397 int mt_add_tvalues(struct sip_msg *msg, m_tree_t *pt, str *tomatch)
398 {
399 int l, n;
400 mt_node_t *itn;
401 int_str val, values_avp_name;
402 unsigned short values_name_type;
403 mt_is_t *tvalues;
404
405 if (pt == NULL || tomatch == NULL || tomatch->s == NULL) {
406 LM_ERR("bad parameters\n");
407 return -1;
408 }
409
410 if (pv_get_avp_name(msg, &pv_values.pvp, &values_avp_name,
411 &values_name_type) < 0) {
412 LM_ERR("cannot get values avp name\n");
413 return -1;
414 }
415
416 destroy_avps(values_name_type, values_avp_name, 1);
417
418 l = n = 0;
419 itn = pt->head;
420
421 while (itn != NULL && l < tomatch->len && l < MT_MAX_DEPTH) {
422 unsigned char mtch = _mt_char_table[(unsigned char)tomatch->s[l]];
423
424 /* check validity */
425 if(mtch==MT_CHAR_TABLE_NOTSET) {
426 LM_ERR("invalid char at %d in [%.*s]\n",
427 l, tomatch->len, tomatch->s);
428 return -1;
429 }
430 tvalues = itn[mtch].tvalues;
431 while (tvalues != NULL) {
432 if (pt->type == MT_TREE_IVAL) {
433 val.n = tvalues->tvalue.n;
434 LM_DBG("adding avp <%.*s> with value <i:%d>\n",
435 values_avp_name.s.len, values_avp_name.s.s, val.n);
436 add_avp(values_name_type, values_avp_name, val);
437 } else { /* pt->type == MT_TREE_SVAL */
438 val.s = tvalues->tvalue.s;
439 LM_DBG("adding avp <%.*s> with value <s:%.*s>\n",
440 values_avp_name.s.len, values_avp_name.s.s, val.s.len,
441 val.s.s);
442 add_avp(values_name_type|AVP_VAL_STR, values_avp_name, val);
443 }
444 n++;
445 tvalues = tvalues->next;
446 }
447
448 itn = itn[mtch].child;
449 l++;
450 }
451
452 if (n > 0)
453 return 0;
454 else
455 return -1;
456 }
457
mt_match_prefix(struct sip_msg * msg,m_tree_t * it,str * tomatch,int mode)458 int mt_match_prefix(struct sip_msg *msg, m_tree_t *it,
459 str *tomatch, int mode)
460 {
461 int l, len, n;
462 int i, j, k = 0;
463 mt_node_t *itn;
464 is_t *tvalue;
465 int_str dstid_avp_name;
466 unsigned short dstid_name_type;
467 int_str weight_avp_name;
468 unsigned short weight_name_type;
469 int_str avp_value;
470 mt_dw_t *dw;
471 pv_value_t val;
472
473 #define MT_MAX_DST_LIST 64
474 unsigned int tmp_list[2*(MT_MAX_DST_LIST+1)];
475
476 if(it==NULL || tomatch == NULL
477 || tomatch->s == NULL)
478 {
479 LM_ERR("bad parameters\n");
480 return -1;
481 }
482
483 l = len = 0;
484 n = 0;
485 if ((it->type==MT_TREE_SVAL) || (it->type==MT_TREE_IVAL)) {
486 if (mode == 2)
487 return mt_add_tvalues(msg, it, tomatch);
488 tvalue = mt_get_tvalue(it, tomatch, &k);
489 if (tvalue == NULL) {
490 LM_DBG("no match for: %.*s\n", tomatch->len, tomatch->s);
491 return -1;
492 }
493 memset(&val, 0, sizeof(pv_value_t));
494 if (it->type==MT_TREE_SVAL) {
495 val.flags = PV_VAL_STR;
496 val.rs = tvalue->s;
497 if(pv_value.setf(msg, &pv_value.pvp, (int)EQ_T, &val)<0) {
498 LM_ERR("setting PV failed\n");
499 return -2;
500 }
501 } else {
502 val.flags = PV_VAL_INT;
503 val.ri = tvalue->n;
504 if(pv_value.setf(msg, &pv_value.pvp, (int)EQ_T, &val)<0) {
505 LM_ERR("setting PV failed\n");
506 return -2;
507 }
508 }
509 return 0;
510 }
511
512 if(it->type!=MT_TREE_DW)
513 return -1; /* wrong tree type */
514
515 if(pv_get_avp_name(msg, &pv_dstid.pvp, &dstid_avp_name,
516 &dstid_name_type)<0)
517 {
518 LM_ERR("cannot get dstid avp name\n");
519 return -1;
520 }
521 if(pv_get_avp_name(msg, &pv_weight.pvp, &weight_avp_name,
522 &weight_name_type)<0)
523 {
524 LM_ERR("cannot get weight avp name\n");
525 return -1;
526 }
527
528 itn = it->head;
529 memset(tmp_list, 0, sizeof(unsigned int)*2*(MT_MAX_DST_LIST+1));
530
531 while(itn!=NULL && l < tomatch->len && l < MT_MAX_DEPTH)
532 {
533 unsigned char mtch = _mt_char_table[(unsigned char)tomatch->s[l]];
534
535 /* check validity */
536 if(mtch==MT_CHAR_TABLE_NOTSET)
537 {
538 LM_ERR("invalid char at %d in [%.*s]\n",
539 l, tomatch->len, tomatch->s);
540 return -1;
541 }
542
543 if(itn[mtch].tvalues!=NULL)
544 {
545 dw = (mt_dw_t*)itn[mtch].data;
546 while(dw) {
547 tmp_list[2*n]=dw->dstid;
548 tmp_list[2*n+1]=dw->weight;
549 n++;
550 if(n==MT_MAX_DST_LIST)
551 break;
552 dw = dw->next;
553 }
554 len = l+1;
555 }
556 if(n==MT_MAX_DST_LIST)
557 break;
558
559 itn = itn[mtch].child;
560 l++;
561 }
562
563 if(n==0)
564 return -1; /* no match */
565 /* invalidate duplicated dstid, keeping longest match */
566 for(i=(n-1); i>0; i--)
567 {
568 if (tmp_list[2*i]!=0)
569 {
570 for(j=0; j<i; j++)
571 if(tmp_list[2*i]==tmp_list[2*j])
572 tmp_list[2*j] = 0;
573 }
574 }
575 /* sort the table -- bubble sort -- reverse order */
576 for (i = (n - 1); i >= 0; i--)
577 {
578 for (j = 1; j <= i; j++)
579 {
580 if (tmp_list[2*(j-1)+1] < tmp_list[2*j+1])
581 {
582 tmp_list[2*MT_MAX_DST_LIST] = tmp_list[2*(j-1)];
583 tmp_list[2*MT_MAX_DST_LIST+1] = tmp_list[2*(j-1)+1];
584 tmp_list[2*(j-1)] = tmp_list[2*j];
585 tmp_list[2*(j-1)+1] = tmp_list[2*j+1];
586 tmp_list[2*j] = tmp_list[2*MT_MAX_DST_LIST];
587 tmp_list[2*j+1] = tmp_list[2*MT_MAX_DST_LIST+1];
588 }
589 }
590 }
591 /* add as avp */
592 for(i=0; i<n; i++)
593 {
594 if(tmp_list[2*i]!=0)
595 {
596 avp_value.n = (int)tmp_list[2*i+1];
597 add_avp(weight_name_type, weight_avp_name, avp_value);
598 avp_value.n = (int)tmp_list[2*i];
599 add_avp(dstid_name_type, dstid_avp_name, avp_value);
600 }
601 }
602
603 return 0;
604 }
605
mt_free_node(mt_node_t * pn,int type)606 void mt_free_node(mt_node_t *pn, int type)
607 {
608 int i;
609 mt_is_t *tvalues, *next;
610
611 if(pn==NULL)
612 return;
613
614 for(i=0; i<MT_NODE_SIZE; i++) {
615 tvalues = pn[i].tvalues;
616 while (tvalues != NULL) {
617 if ((type == MT_TREE_SVAL) && (tvalues->tvalue.s.s != NULL)) {
618 shm_free(tvalues->tvalue.s.s);
619 tvalues->tvalue.s.s = NULL;
620 tvalues->tvalue.s.len = 0;
621 }
622 next = tvalues->next;
623 shm_free(tvalues);
624 tvalues = next;
625 }
626 if(type==MT_TREE_DW)
627 mt_node_unset_payload(&pn[i], type);
628 if(pn[i].child!=NULL) {
629 mt_free_node(pn[i].child, type);
630 pn[i].child = NULL;
631 }
632 }
633 shm_free(pn);
634 pn = NULL;
635
636 return;
637 }
638
mt_free_tree(m_tree_t * pt)639 void mt_free_tree(m_tree_t *pt)
640 {
641 if(pt == NULL)
642 return;
643
644 if(pt->head!=NULL)
645 mt_free_node(pt->head, pt->type);
646 if(pt->next!=NULL)
647 mt_free_tree(pt->next);
648 if(pt->dbtable.s!=NULL)
649 shm_free(pt->dbtable.s);
650 if(pt->tname.s!=NULL)
651 shm_free(pt->tname.s);
652
653 shm_free(pt);
654 pt = NULL;
655 return;
656 }
657
mt_print_node(mt_node_t * pn,char * code,int len,int type)658 int mt_print_node(mt_node_t *pn, char *code, int len, int type)
659 {
660 int i;
661 mt_is_t *tvalues;
662
663 if(pn==NULL || code==NULL || len>=MT_MAX_DEPTH)
664 return 0;
665
666 for(i=0; i<MT_NODE_SIZE; i++)
667 {
668 code[len]=mt_char_list.s[i];
669 tvalues = pn[i].tvalues;
670 while (tvalues != NULL) {
671 if (type == MT_TREE_IVAL) {
672 LM_INFO("[%.*s] [i:%d]\n", len+1, code, tvalues->tvalue.n);
673 } else if (tvalues->tvalue.s.s != NULL) {
674 LM_INFO("[%.*s] [s:%.*s]\n",
675 len+1, code, tvalues->tvalue.s.len, tvalues->tvalue.s.s);
676 }
677 tvalues = tvalues->next;
678 }
679 mt_print_node(pn[i].child, code, len+1, type);
680 }
681
682 return 0;
683 }
684
685 static char mt_code_buf[MT_MAX_DEPTH+1];
mt_print_tree(m_tree_t * pt)686 int mt_print_tree(m_tree_t *pt)
687 {
688 int len;
689
690 if(pt == NULL)
691 {
692 LM_DBG("tree is empty\n");
693 return 0;
694 }
695
696 LM_INFO("[%.*s]\n", pt->tname.len, pt->tname.s);
697 len = 0;
698 mt_print_node(pt->head, mt_code_buf, len, pt->type);
699 return mt_print_tree(pt->next);
700 }
701
mt_node_set_payload(mt_node_t * node,int type)702 int mt_node_set_payload(mt_node_t *node, int type)
703 {
704 param_t *list;
705 param_t *it;
706 param_hooks_t hooks;
707 str s;
708 mt_dw_t *dwl;
709 mt_dw_t *dw;
710
711 if(type!=MT_TREE_DW)
712 return 0;
713 s = node->tvalues->tvalue.s;
714 if(s.s[s.len-1]==';')
715 s.len--;
716 if(parse_params(&s, CLASS_ANY, &hooks, &list)<0)
717 {
718 LM_ERR("cannot parse tvalue payload [%.*s]\n", s.len, s.s);
719 return -1;
720 }
721 dwl = NULL;
722 for(it=list; it; it=it->next)
723 {
724 dw = (mt_dw_t*)shm_malloc(sizeof(mt_dw_t));
725 if(dw==NULL)
726 {
727 LM_ERR("no more shm\n");
728 goto error;
729 }
730 memset(dw, 0, sizeof(mt_dw_t));
731 str2int(&it->name, &dw->dstid);
732 str2int(&it->body, &dw->weight);
733 dw->next = dwl;
734 dwl = dw;
735 }
736 node->data = (void*)dwl;
737 free_params(list);
738 return 0;
739 error:
740 while(dwl)
741 {
742 dw=dwl;
743 dwl=dwl->next;
744 shm_free(dwl);
745 }
746 free_params(list);
747 return -1;
748 }
749
mt_node_unset_payload(mt_node_t * node,int type)750 int mt_node_unset_payload(mt_node_t *node, int type)
751 {
752 mt_dw_t *dwl;
753 mt_dw_t *dw;
754
755 if(type!=MT_TREE_DW)
756 return 0;
757 dwl = (mt_dw_t*)node->data;
758 while(dwl)
759 {
760 dw=dwl;
761 dwl=dwl->next;
762 shm_free(dw);
763 }
764 node->data = NULL;
765 return 0;
766 }
767
mt_table_spec(char * val)768 int mt_table_spec(char* val)
769 {
770 param_t* params_list = NULL;
771 param_hooks_t phooks;
772 param_t *pit=NULL;
773 m_tree_t tmp;
774 m_tree_t *it, *prev, *ndl;
775 str s;
776
777 if(val==NULL)
778 return -1;
779
780 if(!shm_initialized())
781 {
782 LM_ERR("shm not initialized - cannot define mtree now\n");
783 return 0;
784 }
785
786 s.s = val;
787 s.len = strlen(s.s);
788 if(s.s[s.len-1]==';')
789 s.len--;
790 LM_DBG("parsing [%.*s]\n", s.len, s.s);
791 if (parse_params(&s, CLASS_ANY, &phooks, ¶ms_list)<0)
792 return -1;
793 memset(&tmp, 0, sizeof(m_tree_t));
794 for (pit = params_list; pit; pit=pit->next)
795 {
796 LM_DBG("parm: %.*s=%.*s\n", pit->name.len, pit->name.s,
797 pit->body.len, pit->body.s);
798 if (pit->name.len==4
799 && strncasecmp(pit->name.s, "name", 4)==0) {
800 tmp.tname = pit->body;
801 } else if(pit->name.len==4
802 && strncasecmp(pit->name.s, "type", 4)==0) {
803 str2sint(&pit->body, &tmp.type);
804 } else if(pit->name.len==5
805 && strncasecmp(pit->name.s, "multi", 5)==0) {
806 str2sint(&pit->body, &tmp.multi);
807 } else if(pit->name.len==7
808 && strncasecmp(pit->name.s, "dbtable", 7)==0) {
809 tmp.dbtable = pit->body;
810 } else if(pit->name.len==4
811 && strncasecmp(pit->name.s, "cols", 4)==0) {
812 tmp.ncols = 1;
813 tmp.scols[0] = pit->body;
814 }
815 }
816 if(tmp.tname.s==NULL)
817 {
818 LM_ERR("invalid mtree name\n");
819 goto error;
820 }
821 if(tmp.dbtable.s==NULL)
822 {
823 LM_INFO("no table name - default mtree\n");
824 tmp.dbtable.s = "mtree";
825 tmp.dbtable.len = 5;
826 }
827 if ((tmp.type != 0) && (tmp.type != 1) && (tmp.type != 2)) {
828 LM_ERR("unknown tree type <%d>\n", tmp.type);
829 goto error;
830 }
831 if ((tmp.multi != 0) && (tmp.multi != 1)) {
832 LM_ERR("unknown multi value <%d>\n", tmp.multi);
833 goto error;
834 }
835
836 /* check for same tree */
837 if(_ptree == 0)
838 {
839 /* tree list head in shm */
840 _ptree = (m_tree_t**)shm_malloc( sizeof(m_tree_t*) );
841 if (_ptree==0)
842 {
843 LM_ERR("out of shm mem for ptree\n");
844 goto error;
845 }
846 *_ptree=0;
847 }
848 it = *_ptree;
849 prev = NULL;
850 /* search the it position before which to insert new tvalue */
851 while(it!=NULL && str_strcmp(&it->tname, &tmp.tname)<0)
852 {
853 prev = it;
854 it = it->next;
855 }
856
857 /* found */
858 if(it!=NULL && str_strcmp(&it->tname, &tmp.tname)==0)
859 {
860 LM_ERR("duplicate tree with name [%s]\n", tmp.tname.s);
861 goto error;
862 }
863 /* add new tname*/
864 if(it==NULL || str_strcmp(&it->tname, &tmp.tname)>0)
865 {
866 LM_DBG("adding new tname [%s]\n", tmp.tname.s);
867
868 ndl = mt_init_tree(&tmp.tname, &tmp.dbtable, &tmp.scols[0], tmp.type,
869 tmp.multi);
870 if(ndl==NULL)
871 {
872 LM_ERR("cannot init the tree [%.*s]\n",
873 tmp.tname.len, tmp.tname.s);
874 goto error;
875 }
876
877 ndl->next = it;
878
879 /* new tvalue must be added as first element */
880 if(prev==NULL)
881 *_ptree = ndl;
882 else
883 prev->next=ndl;
884
885 }
886
887 free_params(params_list);
888 return 0;
889 error:
890 free_params(params_list);
891 return -1;
892 }
893
mt_add_tree(m_tree_t ** dpt,str * tname,str * dbtable,str * cols,int type,int multi)894 m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable, str *cols,
895 int type, int multi)
896 {
897 m_tree_t *it = NULL;
898 m_tree_t *prev = NULL;
899 m_tree_t *ndl = NULL;
900
901 if(dpt==NULL)
902 return NULL;
903
904 it = *dpt;
905 prev = NULL;
906 /* search the it position before which to insert new tvalue */
907 while(it!=NULL && str_strcmp(&it->tname, tname)<0)
908 {
909 prev = it;
910 it = it->next;
911 }
912
913 if(it!=NULL && str_strcmp(&it->tname, tname)==0)
914 {
915 return it;
916 }
917 /* add new tname*/
918 if(it==NULL || str_strcmp(&it->tname, tname)>0)
919 {
920 LM_DBG("adding new tname [%s]\n", tname->s);
921
922 ndl = mt_init_tree(tname, dbtable, cols, type, multi);
923 if(ndl==NULL)
924 {
925 LM_ERR("no more shm memory\n");
926 return NULL;
927 }
928
929 ndl->next = it;
930
931 /* new tvalue must be added as first element */
932 if(prev==NULL)
933 *dpt = ndl;
934 else
935 prev->next=ndl;
936 }
937 return ndl;
938 }
939
mt_destroy_trees(void)940 void mt_destroy_trees(void)
941 {
942 if (_ptree!=NULL)
943 {
944 if (*_ptree!=NULL)
945 mt_free_tree(*_ptree);
946 shm_free(_ptree);
947 _ptree = NULL;
948 }
949 }
950
mt_defined_trees(void)951 int mt_defined_trees(void)
952 {
953 if (_ptree!=NULL && *_ptree!=NULL)
954 return 1;
955 return 0;
956 }
957
mt_rpc_add_tvalues(rpc_t * rpc,void * ctx,m_tree_t * pt,str * tomatch)958 int mt_rpc_add_tvalues(rpc_t* rpc, void* ctx, m_tree_t *pt, str *tomatch)
959 {
960 int l;
961 mt_node_t *itn;
962 mt_is_t *tvalues;
963 void *vstruct = NULL;
964 str prefix = STR_NULL;
965
966 if (pt == NULL || tomatch == NULL || tomatch->s == NULL) {
967 LM_ERR("bad parameters\n");
968 return -1;
969 }
970 prefix = *tomatch;
971
972 l = 0;
973 itn = pt->head;
974
975 while (itn != NULL && l < tomatch->len && l < MT_MAX_DEPTH) {
976 unsigned char mtch = _mt_char_table[(unsigned char)tomatch->s[l]];
977
978 /* check validity */
979 if(mtch==MT_CHAR_TABLE_NOTSET) {
980 LM_ERR("invalid char at %d in [%.*s]\n",
981 l, tomatch->len, tomatch->s);
982 return -1;
983 }
984 tvalues = itn[mtch].tvalues;
985 while (tvalues != NULL) {
986 prefix.len = l+1;
987 if (rpc->add(ctx, "{", &vstruct) < 0) {
988 rpc->fault(ctx, 500, "Internal error adding struct");
989 return -1;
990 }
991 if(rpc->struct_add(vstruct, "S", "PREFIX", &prefix) < 0) {
992 rpc->fault(ctx, 500, "Internal error adding prefix");
993 return -1;
994 }
995 if (pt->type == MT_TREE_IVAL) {
996 if(rpc->struct_add(vstruct, "d", "TVALUE", tvalues->tvalue.n) < 0 ) {
997 rpc->fault(ctx, 500, "Internal error adding tvalue");
998 return -1;
999 }
1000 } else { /* pt->type == MT_TREE_SVAL */
1001 if(rpc->struct_add(vstruct, "S", "TVALUE", &tvalues->tvalue.s) < 0 ) {
1002 rpc->fault(ctx, 500, "Internal error adding tvalue");
1003 return -1;
1004 }
1005 }
1006 tvalues = tvalues->next;
1007 }
1008
1009 itn = itn[mtch].child;
1010 l++;
1011 }
1012
1013 if (vstruct == NULL) return -1;
1014
1015 return 0;
1016 }
1017
mt_rpc_match_prefix(rpc_t * rpc,void * ctx,m_tree_t * it,str * tomatch,int mode)1018 int mt_rpc_match_prefix(rpc_t* rpc, void* ctx, m_tree_t *it,
1019 str *tomatch, int mode)
1020 {
1021 int l, len, n;
1022 int i, j;
1023 mt_node_t *itn;
1024 is_t *tvalue;
1025 mt_dw_t *dw;
1026 int tprefix_len = 0;
1027 str prefix = STR_NULL;
1028 void *vstruct = NULL;
1029
1030 #define MT_MAX_DST_LIST 64
1031 unsigned int tmp_list[2*(MT_MAX_DST_LIST+1)];
1032
1033 if(it==NULL || tomatch == NULL
1034 || tomatch->s == NULL)
1035 {
1036 LM_ERR("bad parameters\n");
1037 return -1;
1038 }
1039 prefix = *tomatch;
1040
1041 if (rpc->add(ctx, "S", &it->tname) < 0) {
1042 rpc->fault(ctx, 500, "Internal error adding tname");
1043 return -1;
1044 }
1045
1046 l = len = 0;
1047 n = 0;
1048 if ((it->type==MT_TREE_SVAL) || (it->type==MT_TREE_IVAL)) {
1049 if (mode == 2)
1050 return mt_rpc_add_tvalues(rpc, ctx, it, tomatch);
1051 tvalue = mt_get_tvalue(it, tomatch, &tprefix_len);
1052 if (tvalue == NULL) {
1053 LM_DBG("no match for: %.*s\n", tomatch->len, tomatch->s);
1054 return -1;
1055 }
1056 if (tvalue) {
1057 prefix.len = tprefix_len;
1058 if (rpc->add(ctx, "{", &vstruct) < 0) {
1059 rpc->fault(ctx, 500, "Internal error adding struct");
1060 return -1;
1061 }
1062 if (rpc->struct_add(vstruct, "S", "PREFIX", &prefix) < 0) {
1063 rpc->fault(ctx, 500, "Internal error adding prefix");
1064 return -1;
1065 }
1066 if (it->type==MT_TREE_SVAL) {
1067 if(rpc->struct_add(vstruct, "S", "TVALUE", &tvalue->s) < 0 ) {
1068 rpc->fault(ctx, 500, "Internal error adding tvalue");
1069 return -1;
1070 }
1071 } else {
1072 if(rpc->struct_add(vstruct, "d", "TVALUE", tvalue->n) < 0 ) {
1073 rpc->fault(ctx, 500, "Internal error adding tvalue");
1074 return -1;
1075 }
1076 }
1077 }
1078 return 0;
1079 }
1080
1081 if(it->type!=MT_TREE_DW)
1082 return -1; /* wrong tree type */
1083
1084 itn = it->head;
1085 memset(tmp_list, 0, sizeof(unsigned int)*2*(MT_MAX_DST_LIST+1));
1086
1087 while(itn!=NULL && l < tomatch->len && l < MT_MAX_DEPTH)
1088 {
1089 unsigned char mtch = _mt_char_table[(unsigned char)tomatch->s[l]];
1090
1091 /* check validity */
1092 if(mtch==MT_CHAR_TABLE_NOTSET)
1093 {
1094 LM_ERR("invalid char at %d in [%.*s]\n",
1095 l, tomatch->len, tomatch->s);
1096 return -1;
1097 }
1098
1099 if(itn[mtch].tvalues!=NULL)
1100 {
1101 dw = (mt_dw_t*)itn[mtch].data;
1102 while(dw) {
1103 tmp_list[2*n]=dw->dstid;
1104 tmp_list[2*n+1]=dw->weight;
1105 n++;
1106 if(n==MT_MAX_DST_LIST)
1107 break;
1108 dw = dw->next;
1109 }
1110 len = l+1;
1111 }
1112 if(n==MT_MAX_DST_LIST)
1113 break;
1114
1115 itn = itn[mtch].child;
1116 l++;
1117 }
1118
1119 if(n==0)
1120 return -1; /* no match */
1121 /* invalidate duplicated dstid, keeping longest match */
1122 for(i=(n-1); i>0; i--)
1123 {
1124 if (tmp_list[2*i]!=0)
1125 {
1126 for(j=0; j<i; j++)
1127 if(tmp_list[2*i]==tmp_list[2*j])
1128 tmp_list[2*j] = 0;
1129 }
1130 }
1131 /* sort the table -- bubble sort -- reverse order */
1132 for (i = (n - 1); i >= 0; i--)
1133 {
1134 for (j = 1; j <= i; j++)
1135 {
1136 if (tmp_list[2*(j-1)+1] < tmp_list[2*j+1])
1137 {
1138 tmp_list[2*MT_MAX_DST_LIST] = tmp_list[2*(j-1)];
1139 tmp_list[2*MT_MAX_DST_LIST+1] = tmp_list[2*(j-1)+1];
1140 tmp_list[2*(j-1)] = tmp_list[2*j];
1141 tmp_list[2*(j-1)+1] = tmp_list[2*j+1];
1142 tmp_list[2*j] = tmp_list[2*MT_MAX_DST_LIST];
1143 tmp_list[2*j+1] = tmp_list[2*MT_MAX_DST_LIST+1];
1144 }
1145 }
1146 }
1147
1148 prefix.len = len;
1149
1150 /* add as attributes */
1151 for(i=0; i<n; i++)
1152 {
1153 if(tmp_list[2*i]!=0)
1154 {
1155 if (rpc->add(ctx, "{", &vstruct) < 0) {
1156 rpc->fault(ctx, 500, "Internal error adding struct");
1157 return -1;
1158 }
1159 if (rpc->struct_add(vstruct, "S", "PREFIX", &prefix) < 0) {
1160 rpc->fault(ctx, 500, "Internal error adding prefix");
1161 return -1;
1162 }
1163 if(rpc->add(vstruct, "dd",
1164 "WEIGHT", tmp_list[2*i+1],
1165 "DSTID", tmp_list[2*i]) < 0 ) {
1166 rpc->fault(ctx, 500, "Internal error adding weight/dstid");
1167 return -1;
1168 }
1169 }
1170 }
1171
1172 return 0;
1173 }
1174