Browse code

- generalize trie datastructure used in userblacklist and carrierroute - move this implementation into the core, also convert the userblacklist module to use this implementation - patch from Hardy Kahl, hardy dot kahl at 1und1 dot de - write doxygen documentation, add some debug output for allocs/frees - Todo: convert carrierroute too

git-svn-id: https://openser.svn.sourceforge.net/svnroot/openser/trunk@4978 689a6050-402a-0410-94f2-e92a70836424

Henning Westerholt authored on 23/09/2008 14:25:02
Showing 5 changed files
... ...
@@ -28,19 +28,19 @@
28 28
  */
29 29
 
30 30
 #include "db.h"
31
-#include "dt.h"
32 31
 #include "db_userblacklist.h"
33 32
 
34 33
 #include "../../db/db.h"
35 34
 #include "../../mem/mem.h"
36 35
 #include "../../ut.h"
36
+#include "../../trie/dtrie.h"
37 37
 
38 38
 
39 39
 /**
40 40
  * Builds a d-tree using database entries.
41 41
  * \return negative on failure, postive on success, indicating the number of d-tree entries
42 42
  */
43
-int db_build_userbl_tree(const str *username, const str *domain, const str *table, struct dt_node_t *root, int use_domain)
43
+int db_build_userbl_tree(const str *username, const str *domain, const str *table, struct dtrie_node_t *root, int use_domain)
44 44
 {
45 45
 	db_key_t columns[2] = { &userblacklist_prefix_col, &userblacklist_whitelist_col };
46 46
 	db_key_t key[2] = { &userblacklist_username_col, &userblacklist_domain_col };
... ...
@@ -56,6 +56,7 @@ int db_build_userbl_tree(const str *username, const str *domain, const str *tabl
56 56
 	db_res_t *res;
57 57
 	int i;
58 58
 	int n = 0;
59
+	void *nodeflags;
59 60
 	
60 61
 	if (userblacklist_dbf.use_table(userblacklist_dbh, table) < 0) {
61 62
 		LM_ERR("cannot use table '%.*s'.\n", table->len, table->s);
... ...
@@ -66,7 +67,7 @@ int db_build_userbl_tree(const str *username, const str *domain, const str *tabl
66 67
 		return -1;
67 68
 	}
68 69
 
69
-	dt_clear(root);
70
+	dtrie_clear(root);
70 71
 
71 72
 	if (RES_COL_N(res) > 1) {
72 73
 		for(i = 0; i < RES_ROW_N(res); i++) {
... ...
@@ -77,8 +78,9 @@ int db_build_userbl_tree(const str *username, const str *domain, const str *tabl
77 78
 					/* LM_DBG("insert into tree prefix %s, whitelist %d",
78 79
 						RES_ROWS(res)[i].values[0].val.string_val,
79 80
 						RES_ROWS(res)[i].values[1].val.int_val); */
80
-					dt_insert(root, RES_ROWS(res)[i].values[0].val.string_val,
81
-						RES_ROWS(res)[i].values[1].val.int_val);
81
+					if (RES_ROWS(res)[i].values[1].val.int_val == 0) nodeflags=(void *)MARK_BLACKLIST;
82
+					dtrie_insert(root, RES_ROWS(res)[i].values[0].val.string_val, strlen(RES_ROWS(res)[i].values[0].val.string_val),
83
+						nodeflags);
82 84
 					n++;
83 85
 				}
84 86
 				else {
... ...
@@ -97,12 +99,13 @@ int db_build_userbl_tree(const str *username, const str *domain, const str *tabl
97 99
  * Rebuild d-tree using database entries
98 100
  * \return negative on failure, positive on success, indicating the number of d-tree entries
99 101
  */
100
-int db_reload_source(const str *table, struct dt_node_t *root)
102
+int db_reload_source(const str *table, struct dtrie_node_t *root)
101 103
 {
102 104
 	db_key_t columns[2] = { &globalblacklist_prefix_col, &globalblacklist_whitelist_col };
103 105
 	db_res_t *res;
104 106
 	int i;
105 107
 	int n = 0;
108
+	void *nodeflags;
106 109
 	
107 110
 	if (userblacklist_dbf.use_table(userblacklist_dbh, table) < 0) {
108 111
 		LM_ERR("cannot use table '%.*s'.\n", table->len, table->s);
... ...
@@ -113,7 +116,7 @@ int db_reload_source(const str *table, struct dt_node_t *root)
113 116
 		return -1;
114 117
 	}
115 118
 
116
-	dt_clear(root);
119
+	dtrie_clear(root);
117 120
 
118 121
 	if (RES_COL_N(res) > 1) {
119 122
 		for(i = 0; i < RES_ROW_N(res); i++) {
... ...
@@ -124,8 +127,10 @@ int db_reload_source(const str *table, struct dt_node_t *root)
124 127
 					/* LM_DBG("insert into tree prefix %s, whitelist %d",
125 128
 						RES_ROWS(res)[i].values[0].val.string_val,
126 129
 						RES_ROWS(res)[i].values[1].val.int_val); */
127
-					dt_insert(root, RES_ROWS(res)[i].values[0].val.string_val,
128
-						RES_ROWS(res)[i].values[1].val.int_val);
130
+					if (RES_ROWS(res)[i].values[1].val.int_val == 0) nodeflags=(void *) MARK_BLACKLIST;
131
+					else nodeflags=(void *)MARK_WHITELIST;
132
+					dtrie_insert(root, RES_ROWS(res)[i].values[0].val.string_val, strlen(RES_ROWS(res)[i].values[0].val.string_val),
133
+						nodeflags);
129 134
 					n++;
130 135
 				}
131 136
 				else {
... ...
@@ -31,9 +31,12 @@
31 31
 #define _DB_H_
32 32
 
33 33
 #include "../../sr_module.h"
34
-#include "dt.h"
34
+#include "../../trie/dtrie.h"
35 35
 
36
-int db_build_userbl_tree(const str *user, const str *domain, const str *table, struct dt_node_t *root, int use_domain);
37
-int db_reload_source(const str *table, struct dt_node_t *root);
36
+#define MARK_WHITELIST 1
37
+#define MARK_BLACKLIST 2
38
+
39
+int db_build_userbl_tree(const str *user, const str *domain, const str *table, struct dtrie_node_t *root, int use_domain);
40
+int db_reload_source(const str *table, struct dtrie_node_t *root);
38 41
 
39 42
 #endif
40 43
deleted file mode 100644
... ...
@@ -1,133 +0,0 @@
1
-/*
2
- * $Id$
3
- *
4
- * Copyright (C) 2007 1&1 Internet AG
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
- */
22
-
23
-/*!
24
- * \file
25
- * \brief USERBLACKLIST :: data structures
26
- * \ingroup userblacklist
27
- * - Module: \ref userblacklist
28
- */
29
-
30
-#include "dt.h"
31
-#include <assert.h>
32
-#include "../../mem/shm_mem.h"
33
-
34
-
35
-int dt_init(struct dt_node_t **root)
36
-{
37
-	*root = shm_malloc(sizeof(struct dt_node_t));
38
-	if (!(*root)) {
39
-		LM_CRIT("out of private memory\n");
40
-		return -1;
41
-	}
42
-	memset(*root, 0, sizeof(struct dt_node_t));
43
-
44
-	return 0;
45
-}
46
-
47
-
48
-void dt_delete(struct dt_node_t *root, struct dt_node_t *node)
49
-{
50
-	int i;
51
-	if (!node) return;
52
-
53
-	for (i = 0; i < 10; i++) {
54
-		dt_delete(root, node->child[i]);
55
-		node->child[i] = NULL;
56
-	}
57
-
58
-	if (node != root) shm_free(node);
59
-}
60
-
61
-
62
-void dt_destroy(struct dt_node_t **root)
63
-{
64
-	if (*root) {
65
-		dt_delete(*root, *root);
66
-		shm_free(*root);
67
-		*root = NULL;
68
-	}
69
-}
70
-
71
-
72
-void dt_clear(struct dt_node_t *root)
73
-{
74
-	dt_delete(root, root);
75
-	memset(root, 0, sizeof(struct dt_node_t));
76
-}
77
-
78
-
79
-void dt_insert(struct dt_node_t *root, const char *number, char whitelist)
80
-{
81
-	struct dt_node_t *node = root;
82
-
83
-	int i = 0;
84
-	unsigned int digit;
85
-	while (number[i] != 0) {
86
-		digit = number[i] - '0';
87
-		if (digit > 9) {
88
-			LM_ERR("cannot insert non-numerical number\n");
89
-			return;
90
-		}
91
-		if (!node->child[digit]) {
92
-			node->child[digit] = shm_malloc(sizeof(struct dt_node_t));
93
-			assert(node->child[digit] != NULL);
94
-			memset(node->child[digit], 0, sizeof(struct dt_node_t));
95
-		}
96
-		node = node->child[digit];
97
-		i++;
98
-	}
99
-
100
-	node->leaf = 1;
101
-	node->whitelist = whitelist;
102
-}
103
-
104
-
105
-/**
106
- * Find the longest match of number in root.
107
- * Set *whitelist according to value in dtree.
108
- * \return the number of matched digits, in case no match is found, return -1.
109
- */
110
-int dt_longest_match(struct dt_node_t *root, const char *number, char *whitelist)
111
-{
112
-	struct dt_node_t *node = root;
113
-	int nmatch = -1;
114
-	int i = 0;
115
-
116
-	if (node->leaf == 1) {
117
-		nmatch = 0;
118
-		*whitelist = node->whitelist;
119
-	}
120
-	unsigned int digit;
121
-	while (number[i] != 0) {
122
-		digit = number[i] - '0';
123
-		if (!node->child[digit]) return nmatch;
124
-		node = node->child[digit];
125
-		i++;
126
-    if (node->leaf == 1) {
127
-			nmatch=i;
128
-			*whitelist = node->whitelist;
129
-		}
130
-	}
131
-
132
-	return nmatch;
133
-}
134 0
deleted file mode 100644
... ...
@@ -1,50 +0,0 @@
1
-/*
2
- * $Id$
3
- *
4
- * Copyright (C) 2007 1&1 Internet AG
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
- */
22
-
23
-/*!
24
- * \file
25
- * \brief USERBLACKLIST :: data structures
26
- * \ingroup userblacklist
27
- * - Module: \ref userblacklist
28
- */
29
-
30
-#ifndef _DT_H_
31
-#define _DT_H_
32
-
33
-
34
-#include "../../sr_module.h"
35
-
36
-
37
-struct dt_node_t {
38
-	struct dt_node_t *child[10];
39
-	char leaf;
40
-	char whitelist;
41
-};
42
-
43
-
44
-int dt_init(struct dt_node_t **root);
45
-void dt_destroy(struct dt_node_t **root);
46
-void dt_clear(struct dt_node_t *root);
47
-void dt_insert(struct dt_node_t *root, const char *number, char whitelist);
48
-int dt_longest_match(struct dt_node_t *root, const char *number, char *whitelist);
49
-
50
-#endif
... ...
@@ -51,7 +51,7 @@
51 51
 #include "../../ut.h"
52 52
 #include "../../mod_fix.h"
53 53
 
54
-#include "dt.h"
54
+#include "../../trie/dtrie.h"
55 55
 #include "db.h"
56 56
 #include "db_userblacklist.h"
57 57
 
... ...
@@ -69,10 +69,9 @@ typedef struct _avp_check
69 69
 
70 70
 
71 71
 struct check_blacklist_fs_t {
72
-  struct dt_node_t *dt_root;
72
+  struct dtrie_node_t *dtrie_root;
73 73
 };
74 74
 
75
-
76 75
 str userblacklist_db_url = str_init(DEFAULT_RODB_URL);
77 76
 static int use_domain   = 0;
78 77
 
... ...
@@ -142,7 +141,7 @@ struct source_t {
142 141
 	/** prefixes to be used are stored in this table */
143 142
 	char *table;
144 143
 	/** d-tree structure: will be built from data in database */
145
-	struct dt_node_t *dt_root;
144
+	struct dtrie_node_t *dtrie_root;
146 145
 };
147 146
 
148 147
 
... ...
@@ -153,7 +152,7 @@ struct source_list_t {
153 152
 
154 153
 static gen_lock_t *lock = NULL;
155 154
 static struct source_list_t *sources = NULL;
156
-static struct dt_node_t *dt_root;
155
+static struct dtrie_node_t *dtrie_root;
157 156
 
158 157
 
159 158
 static int check_user_blacklist_fixup(void** param, int param_no)
... ...
@@ -208,7 +207,7 @@ static int check_user_blacklist(struct sip_msg *msg, char* str1, char* str2, cha
208 207
 	str table = { .len = 0, .s = NULL};
209 208
 	str number = { .len = 0, .s = NULL};
210 209
 
211
-	char whitelist;
210
+	void *nodeflags;
212 211
 	char *ptr;
213 212
 	char req_number[MAXNUMBERLEN+1];
214 213
 
... ...
@@ -268,7 +267,7 @@ static int check_user_blacklist(struct sip_msg *msg, char* str1, char* str2, cha
268 267
 
269 268
 	LM_DBG("check entry %s for user %.*s on domain %.*s in table %.*s\n", req_number,
270 269
 		user.len, user.s, domain.len, domain.s, table.len, table.s);
271
-	if (db_build_userbl_tree(&user, &domain, &table, dt_root, use_domain) < 0) {
270
+	if (db_build_userbl_tree(&user, &domain, &table, dtrie_root, use_domain) < 0) {
272 271
 		LM_ERR("cannot build d-tree\n");
273 272
 		return -1;
274 273
 	}
... ...
@@ -279,8 +278,8 @@ static int check_user_blacklist(struct sip_msg *msg, char* str1, char* str2, cha
279 278
 		ptr = ptr + 1;
280 279
 	}
281 280
 
282
-	if (dt_longest_match(dt_root, ptr, &whitelist) >= 0) {
283
-		if (whitelist) {
281
+	if (dtrie_longest_match(dtrie_root, ptr, strlen(ptr), &nodeflags) >= 0) {
282
+		if (nodeflags == (void *)MARK_WHITELIST) {
284 283
 			/* LM_ERR("whitelisted"); */
285 284
 			return 1; /* found, but is whitelisted */
286 285
 		}
... ...
@@ -298,11 +297,11 @@ static int check_user_blacklist(struct sip_msg *msg, char* str1, char* str2, cha
298 297
  * Finds d-tree root for given table.
299 298
  * \return pointer to d-tree root on success, NULL otherwise
300 299
  */
301
-static struct dt_node_t *table2dt(const char *table)
300
+static struct dtrie_node_t *table2dt(const char *table)
302 301
 {
303 302
 	struct source_t *src = sources->head;
304 303
 	while (src) {
305
-		if (strcmp(table, src->table) == 0) return src->dt_root;
304
+		if (strcmp(table, src->table) == 0) return src->dtrie_root;
306 305
 		src = src->next;
307 306
 	}
308 307
 
... ...
@@ -344,14 +343,20 @@ static int add_source(const char *table)
344 343
 	strcpy(src->table, table);
345 344
 	LM_DBG("add table %s", table);
346 345
 
347
-	return dt_init(&(src->dt_root));
346
+	src->dtrie_root = dtrie_init();
347
+	if (src->dtrie_root == NULL) {
348
+		LM_ERR("could not initialize data");
349
+		return -1;
350
+	}
351
+
352
+	return 0;
348 353
 }
349 354
 
350 355
 
351 356
 static int check_blacklist_fixup(void **arg, int arg_no)
352 357
 {
353 358
 	char *table = (char *)(*arg);
354
-	struct dt_node_t *node = NULL;
359
+	struct dtrie_node_t *node = NULL;
355 360
 	if (arg_no != 1) {
356 361
 		LM_ERR("wrong number of parameters\n");
357 362
 		return -1;
... ...
@@ -380,7 +385,7 @@ static int check_blacklist_fixup(void **arg, int arg_no)
380 385
 		return -1;
381 386
 	}
382 387
 	memset(new_arg, 0, sizeof(struct check_blacklist_fs_t));
383
-	new_arg->dt_root = node;
388
+	new_arg->dtrie_root = node;
384 389
 	*arg=(void*)new_arg;
385 390
 
386 391
 	return 0;
... ...
@@ -389,7 +394,7 @@ static int check_blacklist_fixup(void **arg, int arg_no)
389 394
 
390 395
 static int check_blacklist(struct sip_msg *msg, struct check_blacklist_fs_t *arg1)
391 396
 {
392
-	char whitelist;
397
+	void *nodeflags;
393 398
 	char *ptr;
394 399
 	char req_number[MAXNUMBERLEN+1];
395 400
 
... ...
@@ -417,8 +422,8 @@ static int check_blacklist(struct sip_msg *msg, struct check_blacklist_fs_t *arg
417 422
 	}
418 423
 
419 424
 	LM_DBG("check entry %s\n", req_number);
420
-	if (dt_longest_match(arg1->dt_root, ptr, &whitelist) >= 0) {
421
-		if (whitelist) {
425
+	if (dtrie_longest_match(arg1->dtrie_root, ptr, strlen(ptr), &nodeflags) >= 0) {
426
+		if (nodeflags == (void *)MARK_WHITELIST) {
422 427
 			/* LM_DBG("whitelisted"); */
423 428
 			return 1; /* found, but is whitelisted */
424 429
 		}
... ...
@@ -449,7 +454,7 @@ static int reload_sources(void)
449 454
 	while (src) {
450 455
 		tmp.s = src->table;
451 456
 		tmp.len = strlen(src->table);
452
-		int n = db_reload_source(&tmp, src->dt_root);
457
+		int n = db_reload_source(&tmp, src->dtrie_root);
453 458
 		if (n < 0) {
454 459
 			LM_ERR("cannot reload source from '%.*s'\n", tmp.len, tmp.s);
455 460
 			result = -1;
... ...
@@ -470,7 +475,7 @@ static int init_source_list(void)
470 475
 {
471 476
 	sources = shm_malloc(sizeof(struct source_list_t));
472 477
 	if (!sources) {
473
-		LM_ERR("out of private memory\n");
478
+		LM_ERR("out of shared memory\n");
474 479
 		return -1;
475 480
 	}
476 481
 	sources->head = NULL;
... ...
@@ -486,7 +491,7 @@ static void destroy_source_list(void)
486 491
 			sources->head = src->next;
487 492
 
488 493
 			if (src->table) shm_free(src->table);
489
-			dt_destroy(&(src->dt_root));
494
+			dtrie_destroy(&(src->dtrie_root));
490 495
 			shm_free(src);
491 496
 		}
492 497
 
... ...
@@ -525,9 +530,8 @@ static void destroy_shmlock(void)
525 530
 struct mi_root * mi_reload_blacklist(struct mi_root* cmd, void* param)
526 531
 {
527 532
 	struct mi_root * tmp = NULL;
528
-
529 533
 	if(reload_sources() == 0) {
530
-		tmp = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);	
534
+		tmp = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
531 535
 	} else {
532 536
 		tmp = init_mi_tree( 500, "cannot reload blacklist", 21);
533 537
 	}
... ...
@@ -550,7 +554,11 @@ static int mod_init(void)
550 554
 static int child_init(int rank)
551 555
 {
552 556
 	if (userblacklist_db_open() != 0) return -1;
553
-	if (dt_init(&dt_root) != 0) return -1;
557
+	dtrie_root=dtrie_init();
558
+	if (dtrie_root == NULL) {
559
+		LM_ERR("could not initialize data");
560
+		return -1;
561
+	}
554 562
 	/* because we've added new sources during the fixup */
555 563
 	if (reload_sources() != 0) return -1;
556 564
 
... ...
@@ -561,7 +569,11 @@ static int child_init(int rank)
561 569
 static int mi_child_init(void)
562 570
 {
563 571
 	if (userblacklist_db_open() != 0) return -1;
564
-	if (dt_init(&dt_root) != 0) return -1;
572
+	dtrie_root=dtrie_init();
573
+	if (dtrie_root == NULL) {
574
+		LM_ERR("could not initialize data");
575
+		return -1;
576
+	}
565 577
 	/* because we've added new sources during the fixup */
566 578
 	if (reload_sources() != 0) return -1;
567 579
 
... ...
@@ -574,5 +586,5 @@ static void mod_destroy(void)
574 586
 	destroy_source_list();
575 587
 	destroy_shmlock();
576 588
 	userblacklist_db_close();
577
-	dt_destroy(&dt_root);
589
+	dtrie_destroy(&dtrie_root);
578 590
 }