Browse code

- refactor carrierroute module (preparations for later performance improvements and some functional additions) - use core trie structure instead of the own copy of the digit trie - use a iterative approach instead of the recursive digit matching - move belonging functionality to one file, reduce dependencies between different files, change interfaces to use more appropriate structures - get rid of this API pointer to differ between config and DB mode

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

Henning Westerholt authored on 24/10/2008 08:28:01
Showing 24 changed files
1 1
deleted file mode 100644
... ...
@@ -1,547 +0,0 @@
1
-/*
2
- * $Id$
3
- *
4
- * Copyright (C) 2007-2008 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 carrier_tree.c
25
- * \brief Contains the functions to manage carrier tree data.
26
- * \ingroup carrierroute
27
- * - Module; \ref carrierroute
28
- */
29
-
30
-#include "../../mem/shm_mem.h"
31
-#include "../../ut.h"
32
-#include "carrier_tree.h"
33
-#include "carrierroute.h"
34
-#include "route_tree.h"
35
-#include "route_rule.h"
36
-#include "load_data.h"
37
-
38
-/**
39
- * points to the data loading function
40
- */
41
-route_data_load_func_t load_data;
42
-
43
-/**
44
- * Pointer to the routing data.
45
- */
46
-struct rewrite_data ** global_data = NULL;
47
-
48
-/**
49
- * holds the map between routing tree names and numbers
50
- */
51
-struct tree_map ** script_trees = NULL;
52
-
53
-/**
54
- * holds the map between failure routing tree names and numbers
55
- */
56
-struct tree_map ** script_failure_trees = NULL;
57
-
58
-static int carrier_tree_fixup(struct rewrite_data * rd);
59
-
60
-/**
61
- * Initialises the routing data, i.e. it binds the data loader,
62
- * initialises the global data pointer.
63
- *
64
- * @param source data source, can be db or file
65
- *
66
- * @return 0 on success, -1 on failure
67
- */
68
-int init_route_data(const char * source) {
69
-	if (global_data == NULL) {
70
-		global_data = (struct rewrite_data **)
71
-		              shm_malloc(sizeof(struct rewrite_data *));
72
-		if (global_data == NULL) {
73
-			LM_ERR("Out of shared memory before even "
74
-			    "doing anything.\n");
75
-			return -1;
76
-		}
77
-	}
78
-	*global_data = NULL;
79
-	return bind_data_loader(source, &load_data);
80
-}
81
-
82
-/**
83
- * Loads the routing data into the routing tree and sets the
84
- * global_data pointer to the new data. The old_data is removed
85
- * when it is not locked anymore.
86
- *
87
- * @return 0 on success, -1 on failure
88
- */
89
-int prepare_route_tree(void) {
90
-	struct rewrite_data * old_data;
91
-	struct rewrite_data * new_data = NULL;
92
-	int i;
93
-
94
-	if ((new_data = shm_malloc(sizeof(struct rewrite_data))) == NULL) {
95
-		LM_ERR("out of shared memory\n");
96
-		return -1;
97
-	}
98
-	memset(new_data, 0, sizeof(struct rewrite_data));
99
-
100
-	if (!load_data || load_data(new_data) < 0) {
101
-		LM_ERR("could not load routing data\n");
102
-		return -1;
103
-	}
104
-	if (new_data == NULL) {
105
-		return -1;
106
-	}
107
-
108
-	if (rule_fixup(new_data) < 0) {
109
-		LM_ERR("could not fixup rules\n");
110
-		return -1;
111
-	}
112
-
113
-	if (carrier_tree_fixup(new_data) < 0){
114
-		LM_ERR("could not fixup trees\n");
115
-		return -1;
116
-	}
117
-
118
-	new_data->proc_cnt = 0;
119
-
120
-	if (*global_data == NULL) {
121
-		*global_data = new_data;
122
-	} else {
123
-		old_data = *global_data;
124
-		*global_data = new_data;
125
-		i = 0;
126
-		while (old_data->proc_cnt > 0) {
127
-			LM_ERR("data is still locked after %i seconds\n", i);
128
-			sleep_us(i*1000000);
129
-			i++;
130
-		}
131
-		destroy_rewrite_data(old_data);
132
-	}
133
-	return 0;
134
-}
135
-
136
-/**
137
- * Increases lock counter and returns a pointer to the
138
- * current routing data
139
- *
140
- * @return pointer to the global routing data on success,
141
- * NULL on failure
142
-*/
143
-struct rewrite_data * get_data(void) {
144
-	struct rewrite_data *ret;
145
-	if (!global_data || !*global_data) {
146
-		return NULL;
147
-	}
148
-	ret = *global_data;
149
-	lock_get(&ret->lock);
150
-	++ret->proc_cnt;
151
-	lock_release(&ret->lock);
152
-	if (ret == *global_data) {
153
-		return ret;
154
-	} else {
155
-		lock_get(&ret->lock);
156
-		--ret->proc_cnt;
157
-		lock_release(&ret->lock);
158
-		return NULL;
159
-	}
160
-}
161
-
162
-/**
163
- * decrements the lock counter of the routing data
164
- *
165
- * @param data data to be released
166
- */
167
-void release_data(struct rewrite_data *data) {
168
-	lock_get(&data->lock);
169
-	--data->proc_cnt;
170
-	lock_release(&data->lock);
171
-}
172
-
173
-int find_tree(str tree){
174
-	struct tree_map * tmp;
175
-	if (!script_trees){
176
-		return -1;
177
-	}
178
-	if (tree.len <= 0) {
179
-		return -1;
180
-	}
181
-	tmp = *script_trees;
182
-
183
-	while (tmp) {
184
-		if (str_strcmp(&tree, &tmp->name) == 0) {
185
-			return tmp->id;
186
-		}
187
-		tmp = tmp->next;
188
-	}
189
-	return -1;
190
-}
191
-
192
-/**
193
- * Adds the given route information to the route tree identified by
194
- * domain. scan_prefix identifies the number for which the information
195
- * is and the rewrite_* parameters define what to do in case of a match.
196
- * prob gives the probability with which this rule applies if there are
197
- * more than one for a given prefix.
198
- *
199
- * @param rd the route data to which the route shall be added
200
- * @param carrier_id the carrier id of the route to be added
201
- * @param domain the routing domain of the new route
202
- * @param scan_prefix the number prefix
203
- * @param flags user defined flags
204
- * @param mask mask for user defined flags
205
- * @param max_targets the number of targets
206
- * @param prob the weight of the rule
207
- * @param rewrite_hostpart the rewrite_host of the rule
208
- * @param strip the number of digits to be stripped off userpart before prepending prefix
209
- * @param rewrite_local_prefix the rewrite prefix
210
- * @param rewrite_local_suffix the rewrite suffix
211
- * @param status the status of the rule
212
- * @param hash_index the hash index of the rule
213
- * @param backup indicates if the route is backed up by another. only 
214
-                 useful if status==0, if set, it is the hash value
215
-                 of another rule
216
- * @param backed_up an -1-termintated array of hash indices of the route 
217
-                    for which this route is backup
218
- * @param comment a comment for the route rule
219
- *
220
- * @return 0 on success, -1 on error in which case it LOGs a message.
221
- */
222
-int add_route(struct rewrite_data * rd, int carrier_id,
223
-		const str * domain, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
224
-		double prob, const str * rewrite_hostpart, int strip,
225
-		const str * rewrite_local_prefix, const str * rewrite_local_suffix,
226
-		int status, int hash_index, int backup, int * backed_up, const str * comment) {
227
-	struct carrier_tree * ct = NULL;
228
-	struct route_tree * rt = NULL;
229
-	LM_INFO("adding prefix %.*s, prob %f\n", scan_prefix->len, scan_prefix->s, prob);
230
-
231
-	if ((ct = get_carrier_tree(carrier_id, rd)) == NULL) {
232
-		LM_ERR("could not retrieve carrier tree\n");
233
-		return -1;
234
-	}
235
-
236
-	if ((rt = get_route_tree(domain, ct)) == NULL) {
237
-		LM_ERR("could not retrieve route tree\n");
238
-		return -1;
239
-	}
240
-	LM_INFO("found route, now adding\n");
241
-	return add_route_to_tree(rt->tree, scan_prefix, flags, mask, scan_prefix, max_targets, prob, rewrite_hostpart,
242
-	                         strip, rewrite_local_prefix, rewrite_local_suffix, status,
243
-	                         hash_index, backup, backed_up, comment);
244
-}
245
-
246
-/**
247
- * Adds the given failure route information to the failure route tree identified by
248
- * domain. scan_prefix, host, reply_code and flags identifies the number for which
249
- * the information is and the next_domain parameter defines where to continue routing
250
- * in case of a match.
251
- *
252
- * @param rd the route data to which the route shall be added
253
- * @param carrier_id the carrier id of the route to be added
254
- * @param domain the routing domain of the new route
255
- * @param scan_prefix the number prefix
256
- * @param host the hostname last tried
257
- * @param reply_code the reply code 
258
- * @param flags user defined flags
259
- * @param mask for user defined flags
260
- * @param next_domain continue routing with this domain
261
- * @param comment a comment for the failure route rule
262
- *
263
- * @return 0 on success, -1 on error in which case it LOGs a message.
264
- */
265
-int add_failure_route(struct rewrite_data * rd, int carrier_id, const str * domain,
266
-		const str * scan_prefix, const str * host, const str * reply_code,
267
-		flag_t flags, flag_t mask, const str * next_domain, const str * comment) {
268
-	int next_domain_id;
269
-	struct carrier_tree * ct = NULL;
270
-	struct route_tree * rt = NULL;
271
-	LM_INFO("adding prefix %.*s, reply code %.*s\n", scan_prefix->len, scan_prefix->s, reply_code->len, reply_code->s);
272
-		
273
-	if (reply_code->len!=3) {
274
-		LM_ERR("invalid reply_code '%.*s'!\n", reply_code->len, reply_code->s);
275
-		return -1;
276
-	}
277
-	
278
-	if ((ct = get_carrier_tree(carrier_id, rd)) == NULL) {
279
-		LM_ERR("could not retrieve carrier tree\n");
280
-		return -1;
281
-	}
282
-	
283
-	if ((rt = get_route_tree(domain, ct)) == NULL) {
284
-		LM_ERR("could not retrieve route tree\n");
285
-		return -1;
286
-	}
287
-
288
-	if ((next_domain_id = add_domain(next_domain)) < 0) {
289
-		LM_ERR("add_domain failed\n");
290
-		return -1;
291
-	}
292
-	
293
-	LM_INFO("found failure route, now adding\n");
294
-	return add_failure_route_to_tree(rt->failure_tree, scan_prefix, scan_prefix, host, reply_code,
295
-			flags, mask, next_domain_id, comment);
296
-}
297
-
298
-
299
-/**
300
- * adds a carrier tree for the given carrier
301
- *
302
- * @param carrier the carrier name of desired routing tree
303
- * @param carrier_id the id of the carrier
304
- * @param rd route data to be searched
305
- * @param trees number of route_tree entries
306
- *
307
- * @return a pointer to the root node of the desired routing tree,
308
- * NULL on failure
309
- */
310
-struct carrier_tree * add_carrier_tree(const str * carrier, int carrier_id, struct rewrite_data * rd, int trees) {
311
-	int i, id;
312
-	if (!rd) {
313
-		LM_ERR("NULL pointer in parameter\n");
314
-		return NULL;
315
-	}
316
-	LM_INFO("add carrier %.*s\n", carrier->len, carrier->s);
317
-	for (i=0; i<rd->tree_num; i++) {
318
-		if (rd->carriers[i]) {
319
-			if (rd->carriers[i]->id == carrier_id) {
320
-				LM_INFO("found carrier %i: %.*s\n", rd->carriers[i]->id, rd->carriers[i]->name.len, rd->carriers[i]->name.s);
321
-				return rd->carriers[i];
322
-			}
323
-		}
324
-	}
325
-	LM_INFO("carrier %.*s not found, add it\n", carrier->len, carrier->s);
326
-	if ((id = add_tree(carrier, carrier_id)) < 0) {
327
-		LM_ERR("could not add tree\n");
328
-		return NULL;
329
-	}
330
-	if (id > rd->tree_num) {
331
-		LM_ERR("weird: to large tree id\n");
332
-		return NULL;
333
-	}
334
-	if ((rd->carriers[id] = create_carrier_tree(carrier, carrier_id, id, trees)) == NULL) {
335
-		return NULL;
336
-	}
337
-	rd->carriers[id]->index = id;
338
-	LM_INFO("created carrier tree: %.*s, with id %i and %ld trees\n", 
339
-		rd->carriers[id]->name.len, rd->carriers[id]->name.s, rd->carriers[id]->id, 
340
-		(long)rd->carriers[id]->tree_num);
341
-	return rd->carriers[id];
342
-}
343
-
344
-/**
345
- * Create a new carrier tree in shared memory and set it up.
346
- *
347
- * @param tree the name of the carrier tree
348
- * @param carrier_id id of carrier
349
- * @param id the domain id of the carrier tree
350
- * @param trees number of route_tree entries
351
- *
352
- * @return a pointer to the newly allocated route tree or NULL on
353
- * error, in which case it LOGs an error message.
354
- */
355
-struct carrier_tree * create_carrier_tree(const str * tree, int carrier_id, int id, int trees) {
356
-	struct carrier_tree * tmp;
357
-	if ((tmp = shm_malloc(sizeof(struct carrier_tree))) == NULL) {
358
-		LM_ERR("out of shared memory\n");
359
-		return NULL;
360
-	}
361
-	memset(tmp, 0, sizeof(struct carrier_tree));
362
-	if (shm_str_dup(&tmp->name, tree)!=0) {
363
-		LM_ERR("cannot duplicate string\n");
364
-		shm_free(tmp);
365
-		return NULL;
366
-	}
367
-	tmp->id = carrier_id;
368
-	tmp->index = id;
369
-	tmp->tree_num = trees;
370
-	if(trees > 0){
371
-		if ((tmp->trees = shm_malloc(sizeof(struct route_tree *) * trees)) == NULL) {
372
-			LM_ERR("out of shared memory\n");
373
-			shm_free(tmp->name.s);
374
-			shm_free(tmp);
375
-			return NULL;
376
-		}
377
-		memset(tmp->trees, 0, sizeof(struct route_tree *) * trees);
378
-	}
379
-	return tmp;
380
-}
381
-
382
-
383
-/**
384
- * returns the routing tree for the given domain, if domain's tree
385
- * doesnt exist, it will be created. If the trees are completely
386
- * filled and a not existing domain shall be added, an error is
387
- * returned
388
- *
389
- * @param carrier_id the id of the desired carrier tree
390
- * @param rd route data to be searched
391
- *
392
- * @return a pointer to the root node of the desired routing tree,
393
- * NULL on failure
394
- */
395
-struct carrier_tree * get_carrier_tree(int carrier_id, struct rewrite_data * rd) {
396
-	int i;
397
-	if (!rd) {
398
-		LM_ERR("NULL pointer in parameter\n");
399
-		return NULL;
400
-	}
401
-	for (i=0; i<rd->tree_num; i++) {
402
-		if (rd->carriers[i]->id == carrier_id) {
403
-			return rd->carriers[i];
404
-		}
405
-	}
406
-	return NULL;
407
-}
408
-
409
-/**
410
- * Tries to add a tree to the tree map. If the given tree doesn't
411
- * exist, it is added. Otherwise, nothing happens.
412
- *
413
- * @param tree the tree to be added
414
- * @param carrier_id id of the carrier
415
- *
416
- * @return values: on succcess the numerical index of the given tree,
417
- * -1 on failure
418
- */
419
-int add_tree(const str * tree, int carrier_id) {
420
-	struct tree_map * tmp, * prev = NULL;
421
-	int id = 0;
422
-	if (!script_trees) {
423
-		if ((script_trees = shm_malloc(sizeof(struct tree_map *))) == NULL) {
424
-			LM_ERR("out of shared memory\n");
425
-			return -1;
426
-		}
427
-		*script_trees = NULL;
428
-	}
429
-	tmp = *script_trees;
430
-
431
-	while (tmp) {
432
-		if (carrier_id == tmp->id) {
433
-			return tmp->no;
434
-		}
435
-		id = tmp->no + 1;
436
-		prev = tmp;
437
-		tmp = tmp->next;
438
-	}
439
-	if ((tmp = shm_malloc(sizeof(struct tree_map))) == NULL) {
440
-		LM_ERR("out of shared memory\n");
441
-		return -1;
442
-	}
443
-	memset(tmp, 0, sizeof(struct tree_map));
444
-	if (shm_str_dup(&tmp->name, tree)!=0) {
445
-		LM_ERR("cannot duplicate string\n");
446
-		shm_free(tmp);
447
-		return -1;
448
-	}
449
-	tmp->no = id;
450
-	tmp->id = carrier_id;
451
-	if (!prev) {
452
-		*script_trees = tmp;
453
-	} else {
454
-		prev->next = tmp;
455
-	}
456
-	LM_INFO("tree %.*s has internal id %i\n", tree->len, tree->s, id);
457
-	return id;
458
-}
459
-
460
-void destroy_route_data(void){
461
-	struct rewrite_data * rd = get_data();
462
-	struct tree_map * tmp3, * tmp4;
463
-	destroy_rewrite_data(rd);
464
-	destroy_route_map();
465
-	if(script_trees){
466
-		tmp3 = *script_trees;
467
-		while(tmp3){
468
-			tmp4 = tmp3;
469
-			tmp3 = tmp3->next;
470
-			shm_free(tmp4);
471
-		}
472
-		shm_free(script_trees);
473
-		script_trees = NULL;
474
-	}
475
-	if(global_data){
476
-		*global_data = NULL;
477
-		shm_free(global_data);
478
-		global_data = NULL;
479
-	}
480
-}
481
-
482
-/**
483
- * Destroys a carrier tree
484
- *
485
- * @param tree route data to be destroyed
486
- */
487
-static void destroy_carrier_tree(struct carrier_tree * tree) {
488
-	int i;
489
-
490
-	if (tree == NULL) {
491
-		return;
492
-	}
493
-	if (tree->trees != NULL) {
494
-		for (i = 0; i < tree->tree_num; ++i) {
495
-			if (tree->trees[i] != NULL) {
496
-				destroy_route_tree(tree->trees[i]);
497
-			}
498
-		}
499
-		shm_free(tree->trees);
500
-	}
501
-	if(tree->name.s){
502
-		shm_free(tree->name.s);
503
-	}
504
-	shm_free(tree);
505
-	return;
506
-}
507
-
508
-/**
509
- * Destroys the complete routing tree data.
510
- *
511
- * @param data route data to be destroyed
512
- */
513
-void destroy_rewrite_data(struct rewrite_data *data) {
514
-	int i;
515
-
516
-	if (data == NULL) {
517
-		return;
518
-	}
519
-	if (data->carriers != NULL) {
520
-		for (i = 0; i < data->tree_num; ++i) {
521
-			if (data->carriers[i] != NULL) {
522
-				destroy_carrier_tree(data->carriers[i]);
523
-			}
524
-		}
525
-		shm_free(data->carriers);
526
-	}
527
-	shm_free(data);
528
-	return;
529
-}
530
-
531
-static int carrier_tree_fixup(struct rewrite_data * rd){
532
-	int i;
533
-	str tmp;
534
-	tmp = default_tree;
535
-	rd->default_carrier_index = -1;
536
-	for(i=0; i<rd->tree_num; i++){
537
-		if(rd->carriers[i]){
538
-			if(str_strcmp(&(rd->carriers[i]->name), &tmp) == 0){
539
-				rd->default_carrier_index = i;
540
-			}
541
-		}
542
-	}
543
-	if(rd->default_carrier_index < 0){
544
-		LM_ERR("default_carrier not found\n");
545
-	}
546
-	return 0;
547
-}
... ...
@@ -33,26 +33,21 @@
33 33
  * It reads routing entries from a database source or from a config file
34 34
  * at Kamailio startup. It can uses one routing tree (for one carrier),
35 35
  * or if needed for every user a different routing tree (unique for each carrier)
36
- * for number prefix based routing. It supports several route tree domains, e.g.
36
+ * for number prefix based routing. It supports several routing domains, e.g.
37 37
  * for failback routes or different routing rules for VoIP and PSTN targets.
38 38
  */
39 39
 
40 40
 #include "../../sr_module.h"
41 41
 #include "../../str.h"
42
-#include "../../dset.h"
43
-#include "../../dprint.h"
44 42
 #include "../../mem/mem.h"
45
-#include "../../mem/shm_mem.h"
46
-#include "../../ut.h"
47
-#include "../../error.h"
48
-
49 43
 #include "carrierroute.h"
50
-#include "load_data.h"
51
-#include "route_fifo.h"
52
-#include "carrier_tree.h"
53
-#include "route_func.h"
44
+#include "cr_fixup.h"
45
+#include "cr_map.h"
46
+#include "cr_fifo.h"
47
+#include "cr_data.h"
48
+#include "cr_func.h"
54 49
 #include "db_carrierroute.h"
55
-#include "prime_hash.h"
50
+#include <sys/stat.h>
56 51
 
57 52
 MODULE_VERSION
58 53
 
... ...
@@ -73,13 +68,11 @@ char * config_source = "file";
73 68
 char * config_file = CFG_DIR"carrierroute.conf";
74 69
 
75 70
 str default_tree = str_init("default");
76
-const str SP_EMPTY_PREFIX = str_init("null");
71
+const str CR_EMPTY_PREFIX = str_init("null");
77 72
 
78 73
 int mode = 0;
79 74
 int use_domain = 0;
80
-
81 75
 int fallback_default = 1;
82
-
83 76
 int cr_fetch_rows = 2000;
84 77
 
85 78
 
... ...
@@ -88,23 +81,16 @@ static int mod_init(void);
88 81
 static int child_init(int);
89 82
 static int mi_child_init(void);
90 83
 static void mod_destroy(void);
91
-static int route_fixup(void ** param, int param_no);
92
-static int load_user_carrier_fixup(void ** param, int param_no);
93
-static int load_next_domain_fixup(void ** param, int param_no);
94
-
95
-
96
-/************* Declaration of Helper Functions *****************************/
97
-static enum hash_source hash_fixup(const char * domain);
98 84
 
99 85
 
100 86
 /************* Module Exports **********************************************/
101 87
 static cmd_export_t cmds[]={
102
-	{"cr_user_carrier",          (cmd_function)cr_load_user_carrier,  3, load_user_carrier_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
103
-	{"cr_route",                 (cmd_function)cr_route,              5, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
104
-	{"cr_route",                 (cmd_function)cr_route,              6, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
105
-	{"cr_prime_route",           (cmd_function)cr_route,              5, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
106
-	{"cr_prime_route",           (cmd_function)cr_route,              6, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
107
-	{"cr_next_domain",           (cmd_function)cr_load_next_domain,   6, load_next_domain_fixup,  0, REQUEST_ROUTE | FAILURE_ROUTE },
88
+	{"cr_user_carrier", (cmd_function)cr_load_user_carrier,  3, cr_load_user_carrier_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
89
+	{"cr_route",        (cmd_function)cr_route,              5, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
90
+	{"cr_route",        (cmd_function)cr_route,              6, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
91
+	{"cr_prime_route",  (cmd_function)cr_route,              5, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
92
+	{"cr_prime_route",  (cmd_function)cr_route,              6, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
93
+	{"cr_next_domain",  (cmd_function)cr_load_next_domain,   6, cr_load_next_domain_fixup,  0, REQUEST_ROUTE | FAILURE_ROUTE },
108 94
 	{0, 0, 0, 0, 0, 0}
109 95
 };
110 96
 
... ...
@@ -116,16 +102,16 @@ static param_export_t params[]= {
116 102
 	carrierroute_DB_COLS
117 103
 	carrierfailureroute_DB_COLS
118 104
 	route_tree_DB_COLS
119
-	{"subscriber_table",           STR_PARAM, &subscriber_table.s },
120
-	{"subscriber_user_col",        STR_PARAM, &subscriber_username_col.s },
121
-	{"subscriber_domain_col",      STR_PARAM, &subscriber_domain_col.s },
122
-	{"subscriber_carrier_col",     STR_PARAM, &cr_preferred_carrier_col.s },
123
-	{"config_source",              STR_PARAM, &config_source },
124
-	{"default_tree",               STR_PARAM, &default_tree },
125
-	{"config_file",                STR_PARAM, &config_file },
126
-	{"use_domain",                 INT_PARAM, &use_domain },
127
-	{"fallback_default",           INT_PARAM, &fallback_default },
128
-	{"fetch_rows",                 INT_PARAM, &cr_fetch_rows },
105
+	{"subscriber_table",       STR_PARAM, &subscriber_table.s },
106
+	{"subscriber_user_col",    STR_PARAM, &subscriber_username_col.s },
107
+	{"subscriber_domain_col",  STR_PARAM, &subscriber_domain_col.s },
108
+	{"subscriber_carrier_col", STR_PARAM, &cr_preferred_carrier_col.s },
109
+	{"config_source",          STR_PARAM, &config_source },
110
+	{"default_tree",           STR_PARAM, &default_tree },
111
+	{"config_file",            STR_PARAM, &config_file },
112
+	{"use_domain",             INT_PARAM, &use_domain },
113
+	{"fallback_default",       INT_PARAM, &fallback_default },
114
+	{"fetch_rows",             INT_PARAM, &cr_fetch_rows },
129 115
 	{0,0,0}
130 116
 };
131 117
 
... ...
@@ -156,32 +142,6 @@ struct module_exports exports = {
156 142
 };
157 143
 
158 144
 
159
-/************* Helper Functions ********************************************/
160
-
161
-/**
162
- * Fixes the hash source to enum values
163
- *
164
- * @param my_hash_source the hash source as string
165
- *
166
- * @return the enum value on success, -1 on failure
167
- */
168
-static enum hash_source hash_fixup(const char * my_hash_source) {
169
-	if (strcasecmp("call_id", my_hash_source) == 0) {
170
-		return shs_call_id;
171
-	} else if (strcasecmp("from_uri", my_hash_source) == 0) {
172
-		return shs_from_uri;
173
-	} else if (strcasecmp("from_user", my_hash_source) == 0) {
174
-		return shs_from_user;
175
-	} else if (strcasecmp("to_uri", my_hash_source) == 0) {
176
-		return shs_to_uri;
177
-	} else if (strcasecmp("to_user", my_hash_source) == 0) {
178
-		return shs_to_user;
179
-	} else {
180
-		return shs_error;
181
-	}
182
-}
183
-
184
-
185 145
 /************* Interface Functions *****************************************/
186 146
 
187 147
 /**
... ...
@@ -191,6 +151,7 @@ static enum hash_source hash_fixup(const char * my_hash_source) {
191 151
  * @return 0 on success, -1 on failure
192 152
  */
193 153
 static int mod_init(void) {
154
+	struct stat fs;
194 155
 
195 156
 	subscriber_table.len = strlen(subscriber_table.s);
196 157
 	subscriber_username_col.len = strlen(subscriber_username_col.s);
... ...
@@ -200,358 +161,79 @@ static int mod_init(void) {
200 161
 
201 162
 	carrierroute_db_vars();
202 163
 
203
-	if (init_route_data(config_source) < 0) {
204
-		LM_ERR("could not init route data\n");
205
-		return -1;
206
-	}
207
-	if (prepare_route_tree() == -1) {
208
-		LM_ERR("could not prepare route tree\n");
209
-		return -1;
210
-	}
211
-	if(data_main_finalize() < 0) {
212
-		return -1;
213
-	}
214
-	return 0;
215
-}
216
-
217
-
218
-/**
219
- * fixes the module functions' parameters with generic pseudo variable support.
220
- *
221
- * @param param the parameter
222
- *
223
- * @return 0 on success, -1 on failure
224
- */
225
-static int pv_fixup(void ** param) {
226
-	pv_elem_t *model;
227
-	str s;
228
-
229
-	s.s = (char *)(*param);
230
-	s.len = strlen(s.s);
231
-	if (s.len <= 0) return -1;
232
-	/* Check the format */
233
-	if(pv_parse_format(&s, &model)<0) {
234
-		LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
235
-		return -1;
236
-	}
237
-	*param = (void*)model;
238
-
239
-	return 0;
240
-}
241
-
164
+	if (strcmp(config_source, "db") == 0) {
165
+		mode = CARRIERROUTE_MODE_DB;
242 166
 
243
-/**
244
- * fixes the module functions' parameters if it is a carrier.
245
- * supports name string, pseudo-variables and AVPs.
246
- *
247
- * @param param the parameter
248
- *
249
- * @return 0 on success, -1 on failure
250
- */
251
-static int carrier_fixup(void ** param) {
252
-	pv_spec_t avp_spec;
253
-	struct multiparam_t *mp;
254
-	str s;
255
-
256
-	mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
257
-	if (mp == NULL) {
258
-		LM_ERR("no more memory\n");
259
-		return -1;
260
-	}
261
-	memset(mp, 0, sizeof(struct multiparam_t));
262
-	
263
-	s.s = (char *)(*param);
264
-	s.len = strlen(s.s);
265
-
266
-	if (s.s[0]!='$') {
267
-		/* This is a name string */
268
-		mp->type=MP_INT;
269
-		
270
-		/* get carrier id */
271
-		if ((mp->u.n = find_tree(s)) < 0) {
272
-			LM_ERR("could not find carrier tree '%s'\n", (char *)(*param));
273
-			pkg_free(mp);
167
+		LM_INFO("use database as configuration source");
168
+		if(carrierroute_db_init() < 0){
274 169
 			return -1;
275 170
 		}
276
-		LM_INFO("carrier tree %s has id %i\n", (char *)*param, mp->u.n);
277
-		
278
-		pkg_free(*param);
279
-		*param = (void *)mp;
280
-	}
281
-	else {
282
-		/* This is a pseudo-variable */
283
-		if (pv_parse_spec(&s, &avp_spec)==0) {
284
-			LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
285
-			pkg_free(mp);
171
+		// FIXME, move data initialization into child process
172
+		if(carrierroute_db_open() < 0){
286 173
 			return -1;
287 174
 		}
288
-			if (avp_spec.type==PVT_AVP) {
289
-			/* This is an AVP - could be an id or name */
290
-			mp->type=MP_AVP;
291
-			if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
292
-				LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
293
-				pkg_free(mp);
294
-				return -1;
295
-			}
296
-		} else {
297
-			mp->type=MP_PVE;
298
-			if(pv_parse_format(&s, &(mp->u.p))<0) {
299
-				LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
300
-				pkg_free(mp);
301
-				return -1;
302
-			}
303
-		}
304 175
 	}
305
-	*param = (void*)mp;
176
+	else if (strcmp(config_source, "file") == 0) {
177
+		mode = CARRIERROUTE_MODE_FILE;
306 178
 
307
-	return 0;
308
-}
309
-
310
-
311
-/**
312
- * fixes the module functions' parameters if it is a domain.
313
- * supports name string, and AVPs.
314
- *
315
- * @param param the parameter
316
- *
317
- * @return 0 on success, -1 on failure
318
- */
319
-static int domain_fixup(void ** param) {
320
-	pv_spec_t avp_spec;
321
-	struct multiparam_t *mp;
322
-	str s;
323
-
324
-	mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
325
-	if (mp == NULL) {
326
-		LM_ERR("no more memory\n");
327
-		return -1;
328
-	}
329
-	memset(mp, 0, sizeof(struct multiparam_t));
330
-	
331
-	s.s = (char *)(*param);
332
-	s.len = strlen(s.s);
333
-	
334
-	if (s.s[0]!='$') {
335
-		/* This is a name string */
336
-		mp->type=MP_INT;
337
-		
338
-		/* get domain id */
339
-		if ((mp->u.n = add_domain(&s)) < 0) {
340
-			LM_ERR("could not add domain\n");
341
-			pkg_free(mp);
179
+		LM_INFO("use file as configuration source");
180
+		if(stat(config_file, &fs) != 0){
181
+			LM_ERR("can't stat config file\n");
342 182
 			return -1;
343 183
 		}
344
-		pkg_free(*param);
345
-		*param = (void *)mp;
346
-	}
347
-	else {
348
-		/* This is a pseudo-variable */
349
-		if (pv_parse_spec(&s, &avp_spec)==0) {
350
-			LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
351
-			pkg_free(mp);
352
-			return -1;
184
+		if(fs.st_mode & S_IWOTH){
185
+			LM_WARN("insecure file permissions, routing data is world writeable");
353 186
 		}
354
-		if (avp_spec.type==PVT_AVP) {
355
-			/* This is an AVP - could be an id or name */
356
-			mp->type=MP_AVP;
357
-			if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
358
-				LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
359
-				pkg_free(mp);
187
+		if( !( fs.st_mode & S_IWOTH) &&
188
+			!((fs.st_mode & S_IWGRP) && (fs.st_gid == getegid())) &&
189
+			!((fs.st_mode & S_IWUSR) && (fs.st_uid == geteuid())) ) {
190
+				LM_ERR("config file not writable\n");
360 191
 				return -1;
361
-			}
362
-		} else {
363
-			mp->type=MP_PVE;
364
-			if(pv_parse_format(&s, &(mp->u.p))<0) {
365
-				LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
366
-				pkg_free(mp);
367
-				return -1;
368
-			}
369
-		}	
192
+		}
370 193
 	}
371
-	*param = (void*)mp;
372
-
373
-	return 0;
374
-}
375
-
376
-
377
-/**
378
- * fixes the module functions' parameters in case of AVP names.
379
- *
380
- * @param param the parameter
381
- *
382
- * @return 0 on success, -1 on failure
383
- */
384
-static int avp_name_fixup(void ** param) {
385
-	pv_spec_t avp_spec;
386
-	struct multiparam_t *mp;
387
-	str s;
388
-
389
-	s.s = (char *)(*param);
390
-	s.len = strlen(s.s);
391
-	if (s.len <= 0) return -1;
392
-	if (pv_parse_spec(&s, &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
393
-		LM_ERR("Malformed or non AVP definition <%s>\n", (char *)(*param));
194
+	else {
195
+		LM_ERR("invalid config_source parameter\n");
394 196
 		return -1;
395 197
 	}
396
-	
397
-	mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
398
-	if (mp == NULL) {
399
-		LM_ERR("no more memory\n");
198
+
199
+	if (init_route_data() < 0) {
200
+		LM_ERR("could not init route data\n");
400 201
 		return -1;
401 202
 	}
402
-	memset(mp, 0, sizeof(struct multiparam_t));
403
-	
404
-	mp->type=MP_AVP;
405
-	if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
406
-		LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
407
-		pkg_free(mp);
203
+
204
+	if (reload_route_data() == -1) {
205
+		LM_ERR("could not prepare route data\n");
408 206
 		return -1;
409 207
 	}
410 208
 
411
-	*param = (void*)mp;
412
-	
413
-	return 0;
414
-}
415
-
416
-
417
-/**
418
- * fixes the module functions' parameters, i.e. it maps
419
- * the routing domain names to numbers for faster access
420
- * at runtime
421
- *
422
- * @param param the parameter
423
- * @param param_no the number of the parameter
424
- *
425
- * @return 0 on success, -1 on failure
426
- */
427
-static int route_fixup(void ** param, int param_no) {
428
-	enum hash_source my_hash_source;
429
-
430
-	if (param_no == 1) {
431
-		/* carrier */
432
-		if (carrier_fixup(param) < 0) {
433
-			LM_ERR("cannot fixup parameter %d\n", param_no);
434
-			return -1;
435
-		}
436
-	}
437
-	else if (param_no == 2) {
438
-		/* domain */
439
-		if (domain_fixup(param) < 0) {
440
-			LM_ERR("cannot fixup parameter %d\n", param_no);
441
-			return -1;
442
-		}
209
+	if(mode == CARRIERROUTE_MODE_DB){
210
+		carrierroute_db_close();
443 211
 	}
444
-	else if ((param_no == 3) || (param_no == 4)){
445
-		/* prefix matching */
446
-		/* rewrite user */
447
-		if (pv_fixup(param) < 0) {
448
-			LM_ERR("cannot fixup parameter %d\n", param_no);
449
-			return -1;
450
-		}
451
-	}
452
-	else if (param_no == 5) {
453
-		/* hash source */
454
-		if ((my_hash_source = hash_fixup((char *)*param)) == shs_error) {
455
-			LM_ERR("invalid hash source\n");
456
-			return -1;
457
-		}
458
-		pkg_free(*param);
459
-		*param = (void *)my_hash_source;
460
-	}
461
-	else if (param_no == 6) {
462
-		/* destination avp name */
463
-		if (avp_name_fixup(param) < 0) {
464
-			LM_ERR("cannot fixup parameter %d\n", param_no);
465
-			return -1;
466
-		}
467
-	}
468
-
469 212
 	return 0;
470 213
 }
471 214
 
472 215
 
473
-/**
474
- * fixes the module functions' parameters, i.e. it maps
475
- * the routing domain names to numbers for faster access
476
- * at runtime
477
- *
478
- * @param param the parameter
479
- * @param param_no the number of the parameter
480
- *
481
- * @return 0 on success, -1 on failure
482
- */
483
-static int load_next_domain_fixup(void ** param, int param_no) {
484
-	if (param_no == 1) {
485
-		/* carrier */
486
-		if (carrier_fixup(param) < 0) {
487
-			LM_ERR("cannot fixup parameter %d\n", param_no);
488
-			return -1;
489
-		}
490
-	}
491
-	else if (param_no == 2) {
492
-		/* domain */
493
-		if (domain_fixup(param) < 0) {
494
-			LM_ERR("cannot fixup parameter %d\n", param_no);
495
-			return -1;
496
-		}
497
-	}
498
-	else if ((param_no == 3) || (param_no == 4) || (param_no == 5)) {
499
-		/* prefix matching */
500
-		/* host */
501
-		/* reply code */
502
-		if (pv_fixup(param) < 0) {
503
-			LM_ERR("cannot fixup parameter %d\n", param_no);
504
-			return -1;
505
-		}
506
-	}
507
-	else if (param_no == 6) {
508
-		/* destination avp name */
509
-		if (avp_name_fixup(param) < 0) {
510
-			LM_ERR("cannot fixup parameter %d\n", param_no);
511
-			return -1;
512
-		}
216
+static int child_init(int rank) {
217
+	if(mode == CARRIERROUTE_MODE_DB){
218
+		return carrierroute_db_open();
513 219
 	}
514
-
515 220
 	return 0;
516 221
 }
517 222
 
518 223
 
519
-static int load_user_carrier_fixup(void ** param, int param_no) {
520
-	if (mode == SP_ROUTE_MODE_FILE) {
521
-		LM_ERR("command cr_user_rewrite_uri can't be used in file mode\n");
522
-		return -1;
523
-	}
524
-
525
-	if ((param_no == 1) || (param_no == 2)) {
526
-		/* user */
527
-		/* domain */
528
-		if (pv_fixup(param) < 0) {
529
-			LM_ERR("cannot fixup parameter %d\n", param_no);
530
-			return -1;
531
-		}
532
-	}
533
-	else if (param_no == 3) {
534
-		/* destination avp name */
535
-		if (avp_name_fixup(param) < 0) {
536
-			LM_ERR("cannot fixup parameter %d\n", param_no);
537
-			return -1;
538
-		}
224
+static int mi_child_init(void) {
225
+	if(mode == CARRIERROUTE_MODE_DB){
226
+		return carrierroute_db_open();
539 227
 	}
540
-
541 228
 	return 0;
542 229
 }
543 230
 
544 231
 
545
-static int child_init(int rank) {
546
-	return data_child_init();
547
-}
548
-
549
-
550
-static int mi_child_init(void) {
551
-	return data_child_init();
552
-}
553
-
554
-
555 232
 static void mod_destroy(void) {
233
+	if(mode == CARRIERROUTE_MODE_DB){
234
+		carrierroute_db_close();
235
+	}
556 236
 	destroy_route_data();
237
+	destroy_domain_map();
238
+	destroy_carrier_map();
557 239
 }
... ...
@@ -22,24 +22,15 @@
22 22
 
23 23
 /**
24 24
  * \file carrierroute.h
25
- * \brief Contains the functions exported by the module.
25
+ * \brief Some globals.
26 26
  * \ingroup carrierroute
27 27
  * - Module; \ref carrierroute
28 28
  */
29 29
 
30
-#ifndef SP_ROUTE_H
31
-#define SP_ROUTE_H
30
+#ifndef CARRIERROUTE_H
31
+#define CARRIERROUTE_H
32 32
 
33 33
 #include "../../str.h"
34
-#include "../../usr_avp.h"
35
-#include "../../pvar.h"
36
-
37
-#define SIP_URI "sip:"
38
-#define SIP_URI_LEN 4
39
-#define SIPS_URI "sips:"
40
-#define SIPS_URI_LEN 5
41
-#define AT_SIGN "@"
42
-#define AT_SIGN_LEN 1
43 34
 
44 35
 #define DICE_MAX 1000
45 36
 
... ...
@@ -48,8 +39,8 @@
48 39
 #define SUBSCRIBER_DOMAIN_COL   1
49 40
 #define SUBSCRIBER_CARRIER_COL  2
50 41
 
51
-#define SP_ROUTE_MODE_DB 1
52
-#define SP_ROUTE_MODE_FILE 2
42
+#define CARRIERROUTE_MODE_DB 1
43
+#define CARRIERROUTE_MODE_FILE 2
53 44
 
54 45
 extern str subscriber_table;
55 46
 extern str * subscriber_columns[];
... ...
@@ -57,39 +48,11 @@ extern char * config_source;
57 48
 extern char * config_file;
58 49
 extern str default_tree;
59 50
 
60
-extern const str SP_EMPTY_PREFIX;
51
+extern const str CR_EMPTY_PREFIX;
61 52
 
62 53
 extern int mode;
63 54
 extern int use_domain;
64 55
 extern int fallback_default;
65 56
 extern int cr_fetch_rows;
66 57
 
67
-enum hash_algorithm {
68
-	alg_crc32 = 1, /*!< hashing algorithm is CRC32 */
69
-	alg_prime, /*!< hashing algorithm is (right 18 digits of hash_source % prime_number) % max_targets + 1 */
70
-	alg_error
71
-};
72
-
73
-/**
74
- * Generic parameter that holds a string, an int or an pseudo-variable
75
- * @todo replace this with gparam_t
76
- */
77
-struct multiparam_t {
78
-	enum {
79
-		MP_INT,
80
-		MP_STR,
81
-		MP_AVP,
82
-		MP_PVE,
83
-	} type;
84
-	union {
85
-		int n;
86
-		str s;
87
-		struct {
88
-			unsigned short flags;
89
-			int_str name;
90
-		} a;
91
-		pv_elem_t *p;
92
-	} u;
93
-};
94
-
95 58
 #endif
96 59
new file mode 100644
... ...
@@ -0,0 +1,484 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2007-2008 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 cr_carrier.c
25
+ * \brief Contains the functions to manage carrier data.
26
+ * \ingroup carrierroute
27
+ * - Module; \ref carrierroute
28
+ */
29
+
30
+#include "../../mem/shm_mem.h"
31
+#include "../../ut.h"
32
+#include "cr_carrier.h"
33
+#include "carrierroute.h"
34
+#include "cr_rule.h"
35
+#include "cr_config.h"
36
+#include "cr_db.h"
37
+#include "cr_map.h"
38
+#include "cr_domain.h"
39
+
40
+
41
+/**
42
+ * Adds the given route information to the routing domain identified by
43
+ * domain. scan_prefix identifies the number for which the information
44
+ * is and the rewrite_* parameters define what to do in case of a match.
45
+ * prob gives the probability with which this rule applies if there are
46
+ * more than one for a given prefix.
47
+ *
48
+ * @param rd the route data to which the route shall be added
49
+ * @param carrier_id the carrier id of the route to be added
50
+ * @param domain the routing domain of the new route
51
+ * @param scan_prefix the number prefix
52
+ * @param flags user defined flags
53
+ * @param mask mask for user defined flags
54
+ * @param max_targets the number of targets
55
+ * @param prob the weight of the rule
56
+ * @param rewrite_hostpart the rewrite_host of the rule
57
+ * @param strip the number of digits to be stripped off userpart before prepending prefix
58
+ * @param rewrite_local_prefix the rewrite prefix
59
+ * @param rewrite_local_suffix the rewrite suffix
60
+ * @param status the status of the rule
61
+ * @param hash_index the hash index of the rule
62
+ * @param backup indicates if the route is backed up by another. only 
63
+                 useful if status==0, if set, it is the hash value
64
+                 of another rule
65
+ * @param backed_up an -1-termintated array of hash indices of the route 
66
+                    for which this route is backup
67
+ * @param comment a comment for the route rule
68
+ *
69
+ * @return 0 on success, -1 on error in which case it LOGs a message.
70
+ */
71
+int add_route(struct route_data_t * rd, int carrier_id,
72
+		const str * domain, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
73
+		double prob, const str * rewrite_hostpart, int strip,
74
+		const str * rewrite_local_prefix, const str * rewrite_local_suffix,
75
+		int status, int hash_index, int backup, int * backed_up, const str * comment) {
76
+	struct carrier_data_t * carrier_data = NULL;
77
+	struct domain_data_t * domain_data = NULL;
78
+	LM_INFO("adding prefix %.*s, prob %f\n", scan_prefix->len, scan_prefix->s, prob);
79
+
80
+	if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
81
+		LM_ERR("could not retrieve carrier data\n");
82
+		return -1;
83
+	}
84
+
85
+	if ((domain_data = get_domain_data_by_name(carrier_data,domain)) == NULL) {
86
+		LM_ERR("could not retrieve domain data\n");
87
+		return -1;
88
+	}
89
+	LM_INFO("found route, now adding\n");
90
+	return add_route_to_tree(domain_data->tree, scan_prefix, flags, mask, scan_prefix, max_targets, prob, rewrite_hostpart,
91
+	                         strip, rewrite_local_prefix, rewrite_local_suffix, status,
92
+	                         hash_index, backup, backed_up, comment);
93
+}
94
+
95
+
96
+/**
97
+ * Adds the given failure route information to the failure routing domain identified by
98
+ * domain. scan_prefix, host, reply_code and flags identifies the number for which
99
+ * the information is and the next_domain parameter defines where to continue routing
100
+ * in case of a match.
101
+ *
102
+ * @param rd the route data to which the route shall be added
103
+ * @param carrier_id the carrier id of the route to be added
104
+ * @param domain the routing domain of the new route
105
+ * @param scan_prefix the number prefix
106
+ * @param host the hostname last tried
107
+ * @param reply_code the reply code 
108
+ * @param flags user defined flags
109
+ * @param mask for user defined flags
110
+ * @param next_domain continue routing with this domain
111
+ * @param comment a comment for the failure route rule
112
+ *
113
+ * @return 0 on success, -1 on error in which case it LOGs a message.
114
+ */
115
+int add_failure_route(struct route_data_t * rd, int carrier_id, const str * domain,
116
+		const str * scan_prefix, const str * host, const str * reply_code,
117
+		flag_t flags, flag_t mask, const str * next_domain, const str * comment) {
118
+	int next_domain_id;
119
+	struct carrier_data_t * carrier_data = NULL;
120
+	struct domain_data_t * domain_data = NULL;
121
+	LM_INFO("adding prefix %.*s, reply code %.*s\n", scan_prefix->len, scan_prefix->s, reply_code->len, reply_code->s);
122
+		
123
+	if (reply_code->len!=3) {
124
+		LM_ERR("invalid reply_code '%.*s'!\n", reply_code->len, reply_code->s);
125
+		return -1;
126
+	}
127
+	
128
+	if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
129
+		LM_ERR("could not retrieve carrier data\n");
130
+		return -1;
131
+	}
132
+	
133
+	if ((domain_data = get_domain_data_by_name(carrier_data, domain)) == NULL) {
134
+		LM_ERR("could not retrieve domain data\n");
135
+		return -1;
136
+	}
137
+
138
+	if ((next_domain_id = add_domain(next_domain)) < 0) {
139
+		LM_ERR("add_domain failed\n");
140
+		return -1;
141
+	}
142
+	
143
+	LM_INFO("found failure route, now adding\n");
144
+	return add_failure_route_to_tree(domain_data->failure_tree, scan_prefix, scan_prefix, host, reply_code,
145
+			flags, mask, next_domain_id, comment);
146
+}
147
+
148
+
149
+/**
150
+ * adds a carrier_data struct for given carrier
151
+ *
152
+ * @param rd route data to be searched
153
+ * @param carrier the name of desired carrier
154
+ * @param carrier_id the id of the carrier
155
+ * @param domains number of domains for that carrier
156
+ *
157
+ * @return a pointer to the root node of the desired routing tree,
158
+ * NULL on failure
159
+ */
160
+struct carrier_data_t * add_carrier_data(struct route_data_t * rd, const str * carrier, int carrier_id, int domains) {
161
+	int i, index;
162
+	if (!rd) {
163
+		LM_ERR("NULL pointer in parameter\n");
164
+		return NULL;
165
+	}
166
+	LM_INFO("add carrier %.*s\n", carrier->len, carrier->s);
167
+	for (i=0; i<rd->carrier_num; i++) {
168
+		if (rd->carriers[i]) {
169
+			if (rd->carriers[i]->id == carrier_id) {
170
+				LM_INFO("found carrier %i: %.*s\n", rd->carriers[i]->id, rd->carriers[i]->name.len, rd->carriers[i]->name.s);
171
+				return rd->carriers[i];
172
+			}
173
+		}
174
+	}
175
+	LM_INFO("carrier %.*s not found, add it\n", carrier->len, carrier->s);
176
+	if ((index = add_carrier(carrier, carrier_id)) < 0) {
177
+		LM_ERR("could not add carrier\n");
178
+		return NULL;
179
+	}
180
+	if (index > rd->carrier_num) {
181
+		LM_ERR("weird: to large tree index\n");
182
+		return NULL;
183
+	}
184
+	if ((rd->carriers[index] = create_carrier_data(carrier, carrier_id, index, domains)) == NULL) {
185
+		return NULL;
186
+	}
187
+	rd->carriers[index]->index = index;
188
+	LM_INFO("created carrier data: %.*s, with id %i and %ld domains\n", 
189
+		rd->carriers[index]->name.len, rd->carriers[index]->name.s, rd->carriers[index]->id, 
190
+		(long)rd->carriers[index]->domain_num);
191
+	return rd->carriers[index];
192
+}
193
+
194
+
195
+/**
196
+ * Create a new carrier_data struct in shared memory and set it up.
197
+ *
198
+ * @param carrier_name the name of the carrier
199
+ * @param carrier_id id of carrier
200
+ * @param index the index for that carrier
201
+ * @param domains number of domains for that carrier
202
+ *
203
+ * @return a pointer to the newly allocated carrier data or NULL on
204
+ * error, in which case it LOGs an error message.
205
+ */
206
+struct carrier_data_t * create_carrier_data(const str *carrier_name, int carrier_id, int index, int domains) {
207
+	struct carrier_data_t * tmp;
208
+	if ((tmp = shm_malloc(sizeof(struct carrier_data_t))) == NULL) {
209
+		LM_ERR("out of shared memory\n");
210
+		return NULL;
211
+	}
212
+	memset(tmp, 0, sizeof(struct carrier_data_t));
213
+	if (shm_str_dup(&tmp->name, carrier_name)!=0) {
214
+		LM_ERR("cannot duplicate string\n");
215
+		shm_free(tmp);
216
+		return NULL;
217
+	}
218
+	tmp->id = carrier_id;
219
+	tmp->index = index;
220
+	tmp->domain_num = domains;
221
+	if(domains > 0){
222
+		if ((tmp->domains = shm_malloc(sizeof(struct domain_data_t *) * domains)) == NULL) {
223
+			LM_ERR("out of shared memory\n");
224
+			shm_free(tmp->name.s);
225
+			shm_free(tmp);
226
+			return NULL;
227
+		}
228
+		memset(tmp->domains, 0, sizeof(struct domain_data_t *) * domains);
229
+	}
230
+	return tmp;
231
+}
232
+
233
+
234
+/**
235
+ * returns the routing tree for the given domain, if domain's tree
236
+ * doesnt exist, it will be created. If the trees are completely