Переглянути джерело

- 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 17 роки тому
батько
коміт
5e92049ede

+ 0 - 547
modules/carrierroute/carrier_tree.c

@@ -1,547 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2007-2008 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * \file carrier_tree.c
- * \brief Contains the functions to manage carrier tree data.
- * \ingroup carrierroute
- * - Module; \ref carrierroute
- */
-
-#include "../../mem/shm_mem.h"
-#include "../../ut.h"
-#include "carrier_tree.h"
-#include "carrierroute.h"
-#include "route_tree.h"
-#include "route_rule.h"
-#include "load_data.h"
-
-/**
- * points to the data loading function
- */
-route_data_load_func_t load_data;
-
-/**
- * Pointer to the routing data.
- */
-struct rewrite_data ** global_data = NULL;
-
-/**
- * holds the map between routing tree names and numbers
- */
-struct tree_map ** script_trees = NULL;
-
-/**
- * holds the map between failure routing tree names and numbers
- */
-struct tree_map ** script_failure_trees = NULL;
-
-static int carrier_tree_fixup(struct rewrite_data * rd);
-
-/**
- * Initialises the routing data, i.e. it binds the data loader,
- * initialises the global data pointer.
- *
- * @param source data source, can be db or file
- *
- * @return 0 on success, -1 on failure
- */
-int init_route_data(const char * source) {
-	if (global_data == NULL) {
-		global_data = (struct rewrite_data **)
-		              shm_malloc(sizeof(struct rewrite_data *));
-		if (global_data == NULL) {
-			LM_ERR("Out of shared memory before even "
-			    "doing anything.\n");
-			return -1;
-		}
-	}
-	*global_data = NULL;
-	return bind_data_loader(source, &load_data);
-}
-
-/**
- * Loads the routing data into the routing tree and sets the
- * global_data pointer to the new data. The old_data is removed
- * when it is not locked anymore.
- *
- * @return 0 on success, -1 on failure
- */
-int prepare_route_tree(void) {
-	struct rewrite_data * old_data;
-	struct rewrite_data * new_data = NULL;
-	int i;
-
-	if ((new_data = shm_malloc(sizeof(struct rewrite_data))) == NULL) {
-		LM_ERR("out of shared memory\n");
-		return -1;
-	}
-	memset(new_data, 0, sizeof(struct rewrite_data));
-
-	if (!load_data || load_data(new_data) < 0) {
-		LM_ERR("could not load routing data\n");
-		return -1;
-	}
-	if (new_data == NULL) {
-		return -1;
-	}
-
-	if (rule_fixup(new_data) < 0) {
-		LM_ERR("could not fixup rules\n");
-		return -1;
-	}
-
-	if (carrier_tree_fixup(new_data) < 0){
-		LM_ERR("could not fixup trees\n");
-		return -1;
-	}
-
-	new_data->proc_cnt = 0;
-
-	if (*global_data == NULL) {
-		*global_data = new_data;
-	} else {
-		old_data = *global_data;
-		*global_data = new_data;
-		i = 0;
-		while (old_data->proc_cnt > 0) {
-			LM_ERR("data is still locked after %i seconds\n", i);
-			sleep_us(i*1000000);
-			i++;
-		}
-		destroy_rewrite_data(old_data);
-	}
-	return 0;
-}
-
-/**
- * Increases lock counter and returns a pointer to the
- * current routing data
- *
- * @return pointer to the global routing data on success,
- * NULL on failure
-*/
-struct rewrite_data * get_data(void) {
-	struct rewrite_data *ret;
-	if (!global_data || !*global_data) {
-		return NULL;
-	}
-	ret = *global_data;
-	lock_get(&ret->lock);
-	++ret->proc_cnt;
-	lock_release(&ret->lock);
-	if (ret == *global_data) {
-		return ret;
-	} else {
-		lock_get(&ret->lock);
-		--ret->proc_cnt;
-		lock_release(&ret->lock);
-		return NULL;
-	}
-}
-
-/**
- * decrements the lock counter of the routing data
- *
- * @param data data to be released
- */
-void release_data(struct rewrite_data *data) {
-	lock_get(&data->lock);
-	--data->proc_cnt;
-	lock_release(&data->lock);
-}
-
-int find_tree(str tree){
-	struct tree_map * tmp;
-	if (!script_trees){
-		return -1;
-	}
-	if (tree.len <= 0) {
-		return -1;
-	}
-	tmp = *script_trees;
-
-	while (tmp) {
-		if (str_strcmp(&tree, &tmp->name) == 0) {
-			return tmp->id;
-		}
-		tmp = tmp->next;
-	}
-	return -1;
-}
-
-/**
- * Adds the given route information to the route tree identified by
- * domain. scan_prefix identifies the number for which the information
- * is and the rewrite_* parameters define what to do in case of a match.
- * prob gives the probability with which this rule applies if there are
- * more than one for a given prefix.
- *
- * @param rd the route data to which the route shall be added
- * @param carrier_id the carrier id of the route to be added
- * @param domain the routing domain of the new route
- * @param scan_prefix the number prefix
- * @param flags user defined flags
- * @param mask mask for user defined flags
- * @param max_targets the number of targets
- * @param prob the weight of the rule
- * @param rewrite_hostpart the rewrite_host of the rule
- * @param strip the number of digits to be stripped off userpart before prepending prefix
- * @param rewrite_local_prefix the rewrite prefix
- * @param rewrite_local_suffix the rewrite suffix
- * @param status the status of the rule
- * @param hash_index the hash index of the rule
- * @param backup indicates if the route is backed up by another. only 
-                 useful if status==0, if set, it is the hash value
-                 of another rule
- * @param backed_up an -1-termintated array of hash indices of the route 
-                    for which this route is backup
- * @param comment a comment for the route rule
- *
- * @return 0 on success, -1 on error in which case it LOGs a message.
- */
-int add_route(struct rewrite_data * rd, int carrier_id,
-		const str * domain, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
-		double prob, const str * rewrite_hostpart, int strip,
-		const str * rewrite_local_prefix, const str * rewrite_local_suffix,
-		int status, int hash_index, int backup, int * backed_up, const str * comment) {
-	struct carrier_tree * ct = NULL;
-	struct route_tree * rt = NULL;
-	LM_INFO("adding prefix %.*s, prob %f\n", scan_prefix->len, scan_prefix->s, prob);
-
-	if ((ct = get_carrier_tree(carrier_id, rd)) == NULL) {
-		LM_ERR("could not retrieve carrier tree\n");
-		return -1;
-	}
-
-	if ((rt = get_route_tree(domain, ct)) == NULL) {
-		LM_ERR("could not retrieve route tree\n");
-		return -1;
-	}
-	LM_INFO("found route, now adding\n");
-	return add_route_to_tree(rt->tree, scan_prefix, flags, mask, scan_prefix, max_targets, prob, rewrite_hostpart,
-	                         strip, rewrite_local_prefix, rewrite_local_suffix, status,
-	                         hash_index, backup, backed_up, comment);
-}
-
-/**
- * Adds the given failure route information to the failure route tree identified by
- * domain. scan_prefix, host, reply_code and flags identifies the number for which
- * the information is and the next_domain parameter defines where to continue routing
- * in case of a match.
- *
- * @param rd the route data to which the route shall be added
- * @param carrier_id the carrier id of the route to be added
- * @param domain the routing domain of the new route
- * @param scan_prefix the number prefix
- * @param host the hostname last tried
- * @param reply_code the reply code 
- * @param flags user defined flags
- * @param mask for user defined flags
- * @param next_domain continue routing with this domain
- * @param comment a comment for the failure route rule
- *
- * @return 0 on success, -1 on error in which case it LOGs a message.
- */
-int add_failure_route(struct rewrite_data * rd, int carrier_id, const str * domain,
-		const str * scan_prefix, const str * host, const str * reply_code,
-		flag_t flags, flag_t mask, const str * next_domain, const str * comment) {
-	int next_domain_id;
-	struct carrier_tree * ct = NULL;
-	struct route_tree * rt = NULL;
-	LM_INFO("adding prefix %.*s, reply code %.*s\n", scan_prefix->len, scan_prefix->s, reply_code->len, reply_code->s);
-		
-	if (reply_code->len!=3) {
-		LM_ERR("invalid reply_code '%.*s'!\n", reply_code->len, reply_code->s);
-		return -1;
-	}
-	
-	if ((ct = get_carrier_tree(carrier_id, rd)) == NULL) {
-		LM_ERR("could not retrieve carrier tree\n");
-		return -1;
-	}
-	
-	if ((rt = get_route_tree(domain, ct)) == NULL) {
-		LM_ERR("could not retrieve route tree\n");
-		return -1;
-	}
-
-	if ((next_domain_id = add_domain(next_domain)) < 0) {
-		LM_ERR("add_domain failed\n");
-		return -1;
-	}
-	
-	LM_INFO("found failure route, now adding\n");
-	return add_failure_route_to_tree(rt->failure_tree, scan_prefix, scan_prefix, host, reply_code,
-			flags, mask, next_domain_id, comment);
-}
-
-
-/**
- * adds a carrier tree for the given carrier
- *
- * @param carrier the carrier name of desired routing tree
- * @param carrier_id the id of the carrier
- * @param rd route data to be searched
- * @param trees number of route_tree entries
- *
- * @return a pointer to the root node of the desired routing tree,
- * NULL on failure
- */
-struct carrier_tree * add_carrier_tree(const str * carrier, int carrier_id, struct rewrite_data * rd, int trees) {
-	int i, id;
-	if (!rd) {
-		LM_ERR("NULL pointer in parameter\n");
-		return NULL;
-	}
-	LM_INFO("add carrier %.*s\n", carrier->len, carrier->s);
-	for (i=0; i<rd->tree_num; i++) {
-		if (rd->carriers[i]) {
-			if (rd->carriers[i]->id == carrier_id) {
-				LM_INFO("found carrier %i: %.*s\n", rd->carriers[i]->id, rd->carriers[i]->name.len, rd->carriers[i]->name.s);
-				return rd->carriers[i];
-			}
-		}
-	}
-	LM_INFO("carrier %.*s not found, add it\n", carrier->len, carrier->s);
-	if ((id = add_tree(carrier, carrier_id)) < 0) {
-		LM_ERR("could not add tree\n");
-		return NULL;
-	}
-	if (id > rd->tree_num) {
-		LM_ERR("weird: to large tree id\n");
-		return NULL;
-	}
-	if ((rd->carriers[id] = create_carrier_tree(carrier, carrier_id, id, trees)) == NULL) {
-		return NULL;
-	}
-	rd->carriers[id]->index = id;
-	LM_INFO("created carrier tree: %.*s, with id %i and %ld trees\n", 
-		rd->carriers[id]->name.len, rd->carriers[id]->name.s, rd->carriers[id]->id, 
-		(long)rd->carriers[id]->tree_num);
-	return rd->carriers[id];
-}
-
-/**
- * Create a new carrier tree in shared memory and set it up.
- *
- * @param tree the name of the carrier tree
- * @param carrier_id id of carrier
- * @param id the domain id of the carrier tree
- * @param trees number of route_tree entries
- *
- * @return a pointer to the newly allocated route tree or NULL on
- * error, in which case it LOGs an error message.
- */
-struct carrier_tree * create_carrier_tree(const str * tree, int carrier_id, int id, int trees) {
-	struct carrier_tree * tmp;
-	if ((tmp = shm_malloc(sizeof(struct carrier_tree))) == NULL) {
-		LM_ERR("out of shared memory\n");
-		return NULL;
-	}
-	memset(tmp, 0, sizeof(struct carrier_tree));
-	if (shm_str_dup(&tmp->name, tree)!=0) {
-		LM_ERR("cannot duplicate string\n");
-		shm_free(tmp);
-		return NULL;
-	}
-	tmp->id = carrier_id;
-	tmp->index = id;
-	tmp->tree_num = trees;
-	if(trees > 0){
-		if ((tmp->trees = shm_malloc(sizeof(struct route_tree *) * trees)) == NULL) {
-			LM_ERR("out of shared memory\n");
-			shm_free(tmp->name.s);
-			shm_free(tmp);
-			return NULL;
-		}
-		memset(tmp->trees, 0, sizeof(struct route_tree *) * trees);
-	}
-	return tmp;
-}
-
-
-/**
- * returns the routing tree for the given domain, if domain's tree
- * doesnt exist, it will be created. If the trees are completely
- * filled and a not existing domain shall be added, an error is
- * returned
- *
- * @param carrier_id the id of the desired carrier tree
- * @param rd route data to be searched
- *
- * @return a pointer to the root node of the desired routing tree,
- * NULL on failure
- */
-struct carrier_tree * get_carrier_tree(int carrier_id, struct rewrite_data * rd) {
-	int i;
-	if (!rd) {
-		LM_ERR("NULL pointer in parameter\n");
-		return NULL;
-	}
-	for (i=0; i<rd->tree_num; i++) {
-		if (rd->carriers[i]->id == carrier_id) {
-			return rd->carriers[i];
-		}
-	}
-	return NULL;
-}
-
-/**
- * Tries to add a tree to the tree map. If the given tree doesn't
- * exist, it is added. Otherwise, nothing happens.
- *
- * @param tree the tree to be added
- * @param carrier_id id of the carrier
- *
- * @return values: on succcess the numerical index of the given tree,
- * -1 on failure
- */
-int add_tree(const str * tree, int carrier_id) {
-	struct tree_map * tmp, * prev = NULL;
-	int id = 0;
-	if (!script_trees) {
-		if ((script_trees = shm_malloc(sizeof(struct tree_map *))) == NULL) {
-			LM_ERR("out of shared memory\n");
-			return -1;
-		}
-		*script_trees = NULL;
-	}
-	tmp = *script_trees;
-
-	while (tmp) {
-		if (carrier_id == tmp->id) {
-			return tmp->no;
-		}
-		id = tmp->no + 1;
-		prev = tmp;
-		tmp = tmp->next;
-	}
-	if ((tmp = shm_malloc(sizeof(struct tree_map))) == NULL) {
-		LM_ERR("out of shared memory\n");
-		return -1;
-	}
-	memset(tmp, 0, sizeof(struct tree_map));
-	if (shm_str_dup(&tmp->name, tree)!=0) {
-		LM_ERR("cannot duplicate string\n");
-		shm_free(tmp);
-		return -1;
-	}
-	tmp->no = id;
-	tmp->id = carrier_id;
-	if (!prev) {
-		*script_trees = tmp;
-	} else {
-		prev->next = tmp;
-	}
-	LM_INFO("tree %.*s has internal id %i\n", tree->len, tree->s, id);
-	return id;
-}
-
-void destroy_route_data(void){
-	struct rewrite_data * rd = get_data();
-	struct tree_map * tmp3, * tmp4;
-	destroy_rewrite_data(rd);
-	destroy_route_map();
-	if(script_trees){
-		tmp3 = *script_trees;
-		while(tmp3){
-			tmp4 = tmp3;
-			tmp3 = tmp3->next;
-			shm_free(tmp4);
-		}
-		shm_free(script_trees);
-		script_trees = NULL;
-	}
-	if(global_data){
-		*global_data = NULL;
-		shm_free(global_data);
-		global_data = NULL;
-	}
-}
-
-/**
- * Destroys a carrier tree
- *
- * @param tree route data to be destroyed
- */
-static void destroy_carrier_tree(struct carrier_tree * tree) {
-	int i;
-
-	if (tree == NULL) {
-		return;
-	}
-	if (tree->trees != NULL) {
-		for (i = 0; i < tree->tree_num; ++i) {
-			if (tree->trees[i] != NULL) {
-				destroy_route_tree(tree->trees[i]);
-			}
-		}
-		shm_free(tree->trees);
-	}
-	if(tree->name.s){
-		shm_free(tree->name.s);
-	}
-	shm_free(tree);
-	return;
-}
-
-/**
- * Destroys the complete routing tree data.
- *
- * @param data route data to be destroyed
- */
-void destroy_rewrite_data(struct rewrite_data *data) {
-	int i;
-
-	if (data == NULL) {
-		return;
-	}
-	if (data->carriers != NULL) {
-		for (i = 0; i < data->tree_num; ++i) {
-			if (data->carriers[i] != NULL) {
-				destroy_carrier_tree(data->carriers[i]);
-			}
-		}
-		shm_free(data->carriers);
-	}
-	shm_free(data);
-	return;
-}
-
-static int carrier_tree_fixup(struct rewrite_data * rd){
-	int i;
-	str tmp;
-	tmp = default_tree;
-	rd->default_carrier_index = -1;
-	for(i=0; i<rd->tree_num; i++){
-		if(rd->carriers[i]){
-			if(str_strcmp(&(rd->carriers[i]->name), &tmp) == 0){
-				rd->default_carrier_index = i;
-			}
-		}
-	}
-	if(rd->default_carrier_index < 0){
-		LM_ERR("default_carrier not found\n");
-	}
-	return 0;
-}

+ 64 - 382
modules/carrierroute/carrierroute.c

@@ -33,26 +33,21 @@
  * It reads routing entries from a database source or from a config file
  * at Kamailio startup. It can uses one routing tree (for one carrier),
  * or if needed for every user a different routing tree (unique for each carrier)
- * for number prefix based routing. It supports several route tree domains, e.g.
+ * for number prefix based routing. It supports several routing domains, e.g.
  * for failback routes or different routing rules for VoIP and PSTN targets.
  */
 
 #include "../../sr_module.h"
 #include "../../str.h"
-#include "../../dset.h"
-#include "../../dprint.h"
 #include "../../mem/mem.h"
-#include "../../mem/shm_mem.h"
-#include "../../ut.h"
-#include "../../error.h"
-
 #include "carrierroute.h"
-#include "load_data.h"
-#include "route_fifo.h"
-#include "carrier_tree.h"
-#include "route_func.h"
+#include "cr_fixup.h"
+#include "cr_map.h"
+#include "cr_fifo.h"
+#include "cr_data.h"
+#include "cr_func.h"
 #include "db_carrierroute.h"
-#include "prime_hash.h"
+#include <sys/stat.h>
 
 MODULE_VERSION
 
@@ -73,13 +68,11 @@ char * config_source = "file";
 char * config_file = CFG_DIR"carrierroute.conf";
 
 str default_tree = str_init("default");
-const str SP_EMPTY_PREFIX = str_init("null");
+const str CR_EMPTY_PREFIX = str_init("null");
 
 int mode = 0;
 int use_domain = 0;
-
 int fallback_default = 1;
-
 int cr_fetch_rows = 2000;
 
 
@@ -88,23 +81,16 @@ static int mod_init(void);
 static int child_init(int);
 static int mi_child_init(void);
 static void mod_destroy(void);
-static int route_fixup(void ** param, int param_no);
-static int load_user_carrier_fixup(void ** param, int param_no);
-static int load_next_domain_fixup(void ** param, int param_no);
-
-
-/************* Declaration of Helper Functions *****************************/
-static enum hash_source hash_fixup(const char * domain);
 
 
 /************* Module Exports **********************************************/
 static cmd_export_t cmds[]={
-	{"cr_user_carrier",          (cmd_function)cr_load_user_carrier,  3, load_user_carrier_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
-	{"cr_route",                 (cmd_function)cr_route,              5, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
-	{"cr_route",                 (cmd_function)cr_route,              6, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
-	{"cr_prime_route",           (cmd_function)cr_route,              5, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
-	{"cr_prime_route",           (cmd_function)cr_route,              6, route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
-	{"cr_next_domain",           (cmd_function)cr_load_next_domain,   6, load_next_domain_fixup,  0, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"cr_user_carrier", (cmd_function)cr_load_user_carrier,  3, cr_load_user_carrier_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"cr_route",        (cmd_function)cr_route,              5, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"cr_route",        (cmd_function)cr_route,              6, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"cr_prime_route",  (cmd_function)cr_route,              5, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"cr_prime_route",  (cmd_function)cr_route,              6, cr_route_fixup,             0, REQUEST_ROUTE | FAILURE_ROUTE },
+	{"cr_next_domain",  (cmd_function)cr_load_next_domain,   6, cr_load_next_domain_fixup,  0, REQUEST_ROUTE | FAILURE_ROUTE },
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -116,16 +102,16 @@ static param_export_t params[]= {
 	carrierroute_DB_COLS
 	carrierfailureroute_DB_COLS
 	route_tree_DB_COLS
-	{"subscriber_table",           STR_PARAM, &subscriber_table.s },
-	{"subscriber_user_col",        STR_PARAM, &subscriber_username_col.s },
-	{"subscriber_domain_col",      STR_PARAM, &subscriber_domain_col.s },
-	{"subscriber_carrier_col",     STR_PARAM, &cr_preferred_carrier_col.s },
-	{"config_source",              STR_PARAM, &config_source },
-	{"default_tree",               STR_PARAM, &default_tree },
-	{"config_file",                STR_PARAM, &config_file },
-	{"use_domain",                 INT_PARAM, &use_domain },
-	{"fallback_default",           INT_PARAM, &fallback_default },
-	{"fetch_rows",                 INT_PARAM, &cr_fetch_rows },
+	{"subscriber_table",       STR_PARAM, &subscriber_table.s },
+	{"subscriber_user_col",    STR_PARAM, &subscriber_username_col.s },
+	{"subscriber_domain_col",  STR_PARAM, &subscriber_domain_col.s },
+	{"subscriber_carrier_col", STR_PARAM, &cr_preferred_carrier_col.s },
+	{"config_source",          STR_PARAM, &config_source },
+	{"default_tree",           STR_PARAM, &default_tree },
+	{"config_file",            STR_PARAM, &config_file },
+	{"use_domain",             INT_PARAM, &use_domain },
+	{"fallback_default",       INT_PARAM, &fallback_default },
+	{"fetch_rows",             INT_PARAM, &cr_fetch_rows },
 	{0,0,0}
 };
 
@@ -156,32 +142,6 @@ struct module_exports exports = {
 };
 
 
-/************* Helper Functions ********************************************/
-
-/**
- * Fixes the hash source to enum values
- *
- * @param my_hash_source the hash source as string
- *
- * @return the enum value on success, -1 on failure
- */
-static enum hash_source hash_fixup(const char * my_hash_source) {
-	if (strcasecmp("call_id", my_hash_source) == 0) {
-		return shs_call_id;
-	} else if (strcasecmp("from_uri", my_hash_source) == 0) {
-		return shs_from_uri;
-	} else if (strcasecmp("from_user", my_hash_source) == 0) {
-		return shs_from_user;
-	} else if (strcasecmp("to_uri", my_hash_source) == 0) {
-		return shs_to_uri;
-	} else if (strcasecmp("to_user", my_hash_source) == 0) {
-		return shs_to_user;
-	} else {
-		return shs_error;
-	}
-}
-
-
 /************* Interface Functions *****************************************/
 
 /**
@@ -191,6 +151,7 @@ static enum hash_source hash_fixup(const char * my_hash_source) {
  * @return 0 on success, -1 on failure
  */
 static int mod_init(void) {
+	struct stat fs;
 
 	subscriber_table.len = strlen(subscriber_table.s);
 	subscriber_username_col.len = strlen(subscriber_username_col.s);
@@ -200,358 +161,79 @@ static int mod_init(void) {
 
 	carrierroute_db_vars();
 
-	if (init_route_data(config_source) < 0) {
-		LM_ERR("could not init route data\n");
-		return -1;
-	}
-	if (prepare_route_tree() == -1) {
-		LM_ERR("could not prepare route tree\n");
-		return -1;
-	}
-	if(data_main_finalize() < 0) {
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * fixes the module functions' parameters with generic pseudo variable support.
- *
- * @param param the parameter
- *
- * @return 0 on success, -1 on failure
- */
-static int pv_fixup(void ** param) {
-	pv_elem_t *model;
-	str s;
-
-	s.s = (char *)(*param);
-	s.len = strlen(s.s);
-	if (s.len <= 0) return -1;
-	/* Check the format */
-	if(pv_parse_format(&s, &model)<0) {
-		LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
-		return -1;
-	}
-	*param = (void*)model;
-
-	return 0;
-}
-
+	if (strcmp(config_source, "db") == 0) {
+		mode = CARRIERROUTE_MODE_DB;
 
-/**
- * fixes the module functions' parameters if it is a carrier.
- * supports name string, pseudo-variables and AVPs.
- *
- * @param param the parameter
- *
- * @return 0 on success, -1 on failure
- */
-static int carrier_fixup(void ** param) {
-	pv_spec_t avp_spec;
-	struct multiparam_t *mp;
-	str s;
-
-	mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
-	if (mp == NULL) {
-		LM_ERR("no more memory\n");
-		return -1;
-	}
-	memset(mp, 0, sizeof(struct multiparam_t));
-	
-	s.s = (char *)(*param);
-	s.len = strlen(s.s);
-
-	if (s.s[0]!='$') {
-		/* This is a name string */
-		mp->type=MP_INT;
-		
-		/* get carrier id */
-		if ((mp->u.n = find_tree(s)) < 0) {
-			LM_ERR("could not find carrier tree '%s'\n", (char *)(*param));
-			pkg_free(mp);
+		LM_INFO("use database as configuration source");
+		if(carrierroute_db_init() < 0){
 			return -1;
 		}
-		LM_INFO("carrier tree %s has id %i\n", (char *)*param, mp->u.n);
-		
-		pkg_free(*param);
-		*param = (void *)mp;
-	}
-	else {
-		/* This is a pseudo-variable */
-		if (pv_parse_spec(&s, &avp_spec)==0) {
-			LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
-			pkg_free(mp);
+		// FIXME, move data initialization into child process
+		if(carrierroute_db_open() < 0){
 			return -1;
 		}
-			if (avp_spec.type==PVT_AVP) {
-			/* This is an AVP - could be an id or name */
-			mp->type=MP_AVP;
-			if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
-				LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
-				pkg_free(mp);
-				return -1;
-			}
-		} else {
-			mp->type=MP_PVE;
-			if(pv_parse_format(&s, &(mp->u.p))<0) {
-				LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
-				pkg_free(mp);
-				return -1;
-			}
-		}
 	}
-	*param = (void*)mp;
+	else if (strcmp(config_source, "file") == 0) {
+		mode = CARRIERROUTE_MODE_FILE;
 
-	return 0;
-}
-
-
-/**
- * fixes the module functions' parameters if it is a domain.
- * supports name string, and AVPs.
- *
- * @param param the parameter
- *
- * @return 0 on success, -1 on failure
- */
-static int domain_fixup(void ** param) {
-	pv_spec_t avp_spec;
-	struct multiparam_t *mp;
-	str s;
-
-	mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
-	if (mp == NULL) {
-		LM_ERR("no more memory\n");
-		return -1;
-	}
-	memset(mp, 0, sizeof(struct multiparam_t));
-	
-	s.s = (char *)(*param);
-	s.len = strlen(s.s);
-	
-	if (s.s[0]!='$') {
-		/* This is a name string */
-		mp->type=MP_INT;
-		
-		/* get domain id */
-		if ((mp->u.n = add_domain(&s)) < 0) {
-			LM_ERR("could not add domain\n");
-			pkg_free(mp);
+		LM_INFO("use file as configuration source");
+		if(stat(config_file, &fs) != 0){
+			LM_ERR("can't stat config file\n");
 			return -1;
 		}
-		pkg_free(*param);
-		*param = (void *)mp;
-	}
-	else {
-		/* This is a pseudo-variable */
-		if (pv_parse_spec(&s, &avp_spec)==0) {
-			LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
-			pkg_free(mp);
-			return -1;
+		if(fs.st_mode & S_IWOTH){
+			LM_WARN("insecure file permissions, routing data is world writeable");
 		}
-		if (avp_spec.type==PVT_AVP) {
-			/* This is an AVP - could be an id or name */
-			mp->type=MP_AVP;
-			if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
-				LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
-				pkg_free(mp);
+		if( !( fs.st_mode & S_IWOTH) &&
+			!((fs.st_mode & S_IWGRP) && (fs.st_gid == getegid())) &&
+			!((fs.st_mode & S_IWUSR) && (fs.st_uid == geteuid())) ) {
+				LM_ERR("config file not writable\n");
 				return -1;
-			}
-		} else {
-			mp->type=MP_PVE;
-			if(pv_parse_format(&s, &(mp->u.p))<0) {
-				LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
-				pkg_free(mp);
-				return -1;
-			}
-		}	
+		}
 	}
-	*param = (void*)mp;
-
-	return 0;
-}
-
-
-/**
- * fixes the module functions' parameters in case of AVP names.
- *
- * @param param the parameter
- *
- * @return 0 on success, -1 on failure
- */
-static int avp_name_fixup(void ** param) {
-	pv_spec_t avp_spec;
-	struct multiparam_t *mp;
-	str s;
-
-	s.s = (char *)(*param);
-	s.len = strlen(s.s);
-	if (s.len <= 0) return -1;
-	if (pv_parse_spec(&s, &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
-		LM_ERR("Malformed or non AVP definition <%s>\n", (char *)(*param));
+	else {
+		LM_ERR("invalid config_source parameter\n");
 		return -1;
 	}
-	
-	mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
-	if (mp == NULL) {
-		LM_ERR("no more memory\n");
+
+	if (init_route_data() < 0) {
+		LM_ERR("could not init route data\n");
 		return -1;
 	}
-	memset(mp, 0, sizeof(struct multiparam_t));
-	
-	mp->type=MP_AVP;
-	if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
-		LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
-		pkg_free(mp);
+
+	if (reload_route_data() == -1) {
+		LM_ERR("could not prepare route data\n");
 		return -1;
 	}
 
-	*param = (void*)mp;
-	
-	return 0;
-}
-
-
-/**
- * fixes the module functions' parameters, i.e. it maps
- * the routing domain names to numbers for faster access
- * at runtime
- *
- * @param param the parameter
- * @param param_no the number of the parameter
- *
- * @return 0 on success, -1 on failure
- */
-static int route_fixup(void ** param, int param_no) {
-	enum hash_source my_hash_source;
-
-	if (param_no == 1) {
-		/* carrier */
-		if (carrier_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
-	}
-	else if (param_no == 2) {
-		/* domain */
-		if (domain_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
+	if(mode == CARRIERROUTE_MODE_DB){
+		carrierroute_db_close();
 	}
-	else if ((param_no == 3) || (param_no == 4)){
-		/* prefix matching */
-		/* rewrite user */
-		if (pv_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
-	}
-	else if (param_no == 5) {
-		/* hash source */
-		if ((my_hash_source = hash_fixup((char *)*param)) == shs_error) {
-			LM_ERR("invalid hash source\n");
-			return -1;
-		}
-		pkg_free(*param);
-		*param = (void *)my_hash_source;
-	}
-	else if (param_no == 6) {
-		/* destination avp name */
-		if (avp_name_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
-	}
-
 	return 0;
 }
 
 
-/**
- * fixes the module functions' parameters, i.e. it maps
- * the routing domain names to numbers for faster access
- * at runtime
- *
- * @param param the parameter
- * @param param_no the number of the parameter
- *
- * @return 0 on success, -1 on failure
- */
-static int load_next_domain_fixup(void ** param, int param_no) {
-	if (param_no == 1) {
-		/* carrier */
-		if (carrier_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
-	}
-	else if (param_no == 2) {
-		/* domain */
-		if (domain_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
-	}
-	else if ((param_no == 3) || (param_no == 4) || (param_no == 5)) {
-		/* prefix matching */
-		/* host */
-		/* reply code */
-		if (pv_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
-	}
-	else if (param_no == 6) {
-		/* destination avp name */
-		if (avp_name_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
+static int child_init(int rank) {
+	if(mode == CARRIERROUTE_MODE_DB){
+		return carrierroute_db_open();
 	}
-
 	return 0;
 }
 
 
-static int load_user_carrier_fixup(void ** param, int param_no) {
-	if (mode == SP_ROUTE_MODE_FILE) {
-		LM_ERR("command cr_user_rewrite_uri can't be used in file mode\n");
-		return -1;
-	}
-
-	if ((param_no == 1) || (param_no == 2)) {
-		/* user */
-		/* domain */
-		if (pv_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
-	}
-	else if (param_no == 3) {
-		/* destination avp name */
-		if (avp_name_fixup(param) < 0) {
-			LM_ERR("cannot fixup parameter %d\n", param_no);
-			return -1;
-		}
+static int mi_child_init(void) {
+	if(mode == CARRIERROUTE_MODE_DB){
+		return carrierroute_db_open();
 	}
-
 	return 0;
 }
 
 
-static int child_init(int rank) {
-	return data_child_init();
-}
-
-
-static int mi_child_init(void) {
-	return data_child_init();
-}
-
-
 static void mod_destroy(void) {
+	if(mode == CARRIERROUTE_MODE_DB){
+		carrierroute_db_close();
+	}
 	destroy_route_data();
+	destroy_domain_map();
+	destroy_carrier_map();
 }

+ 6 - 43
modules/carrierroute/carrierroute.h

@@ -22,24 +22,15 @@
 
 /**
  * \file carrierroute.h
- * \brief Contains the functions exported by the module.
+ * \brief Some globals.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#ifndef SP_ROUTE_H
-#define SP_ROUTE_H
+#ifndef CARRIERROUTE_H
+#define CARRIERROUTE_H
 
 #include "../../str.h"
-#include "../../usr_avp.h"
-#include "../../pvar.h"
-
-#define SIP_URI "sip:"
-#define SIP_URI_LEN 4
-#define SIPS_URI "sips:"
-#define SIPS_URI_LEN 5
-#define AT_SIGN "@"
-#define AT_SIGN_LEN 1
 
 #define DICE_MAX 1000
 
@@ -48,8 +39,8 @@
 #define SUBSCRIBER_DOMAIN_COL   1
 #define SUBSCRIBER_CARRIER_COL  2
 
-#define SP_ROUTE_MODE_DB 1
-#define SP_ROUTE_MODE_FILE 2
+#define CARRIERROUTE_MODE_DB 1
+#define CARRIERROUTE_MODE_FILE 2
 
 extern str subscriber_table;
 extern str * subscriber_columns[];
@@ -57,39 +48,11 @@ extern char * config_source;
 extern char * config_file;
 extern str default_tree;
 
-extern const str SP_EMPTY_PREFIX;
+extern const str CR_EMPTY_PREFIX;
 
 extern int mode;
 extern int use_domain;
 extern int fallback_default;
 extern int cr_fetch_rows;
 
-enum hash_algorithm {
-	alg_crc32 = 1, /*!< hashing algorithm is CRC32 */
-	alg_prime, /*!< hashing algorithm is (right 18 digits of hash_source % prime_number) % max_targets + 1 */
-	alg_error
-};
-
-/**
- * Generic parameter that holds a string, an int or an pseudo-variable
- * @todo replace this with gparam_t
- */
-struct multiparam_t {
-	enum {
-		MP_INT,
-		MP_STR,
-		MP_AVP,
-		MP_PVE,
-	} type;
-	union {
-		int n;
-		str s;
-		struct {
-			unsigned short flags;
-			int_str name;
-		} a;
-		pv_elem_t *p;
-	} u;
-};
-
 #endif

+ 484 - 0
modules/carrierroute/cr_carrier.c

@@ -0,0 +1,484 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007-2008 1&1 Internet AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * \file cr_carrier.c
+ * \brief Contains the functions to manage carrier data.
+ * \ingroup carrierroute
+ * - Module; \ref carrierroute
+ */
+
+#include "../../mem/shm_mem.h"
+#include "../../ut.h"
+#include "cr_carrier.h"
+#include "carrierroute.h"
+#include "cr_rule.h"
+#include "cr_config.h"
+#include "cr_db.h"
+#include "cr_map.h"
+#include "cr_domain.h"
+
+
+/**
+ * Adds the given route information to the routing domain identified by
+ * domain. scan_prefix identifies the number for which the information
+ * is and the rewrite_* parameters define what to do in case of a match.
+ * prob gives the probability with which this rule applies if there are
+ * more than one for a given prefix.
+ *
+ * @param rd the route data to which the route shall be added
+ * @param carrier_id the carrier id of the route to be added
+ * @param domain the routing domain of the new route
+ * @param scan_prefix the number prefix
+ * @param flags user defined flags
+ * @param mask mask for user defined flags
+ * @param max_targets the number of targets
+ * @param prob the weight of the rule
+ * @param rewrite_hostpart the rewrite_host of the rule
+ * @param strip the number of digits to be stripped off userpart before prepending prefix
+ * @param rewrite_local_prefix the rewrite prefix
+ * @param rewrite_local_suffix the rewrite suffix
+ * @param status the status of the rule
+ * @param hash_index the hash index of the rule
+ * @param backup indicates if the route is backed up by another. only 
+                 useful if status==0, if set, it is the hash value
+                 of another rule
+ * @param backed_up an -1-termintated array of hash indices of the route 
+                    for which this route is backup
+ * @param comment a comment for the route rule
+ *
+ * @return 0 on success, -1 on error in which case it LOGs a message.
+ */
+int add_route(struct route_data_t * rd, int carrier_id,
+		const str * domain, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
+		double prob, const str * rewrite_hostpart, int strip,
+		const str * rewrite_local_prefix, const str * rewrite_local_suffix,
+		int status, int hash_index, int backup, int * backed_up, const str * comment) {
+	struct carrier_data_t * carrier_data = NULL;
+	struct domain_data_t * domain_data = NULL;
+	LM_INFO("adding prefix %.*s, prob %f\n", scan_prefix->len, scan_prefix->s, prob);
+
+	if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
+		LM_ERR("could not retrieve carrier data\n");
+		return -1;
+	}
+
+	if ((domain_data = get_domain_data_by_name(carrier_data,domain)) == NULL) {
+		LM_ERR("could not retrieve domain data\n");
+		return -1;
+	}
+	LM_INFO("found route, now adding\n");
+	return add_route_to_tree(domain_data->tree, scan_prefix, flags, mask, scan_prefix, max_targets, prob, rewrite_hostpart,
+	                         strip, rewrite_local_prefix, rewrite_local_suffix, status,
+	                         hash_index, backup, backed_up, comment);
+}
+
+
+/**
+ * Adds the given failure route information to the failure routing domain identified by
+ * domain. scan_prefix, host, reply_code and flags identifies the number for which
+ * the information is and the next_domain parameter defines where to continue routing
+ * in case of a match.
+ *
+ * @param rd the route data to which the route shall be added
+ * @param carrier_id the carrier id of the route to be added
+ * @param domain the routing domain of the new route
+ * @param scan_prefix the number prefix
+ * @param host the hostname last tried
+ * @param reply_code the reply code 
+ * @param flags user defined flags
+ * @param mask for user defined flags
+ * @param next_domain continue routing with this domain
+ * @param comment a comment for the failure route rule
+ *
+ * @return 0 on success, -1 on error in which case it LOGs a message.
+ */
+int add_failure_route(struct route_data_t * rd, int carrier_id, const str * domain,
+		const str * scan_prefix, const str * host, const str * reply_code,
+		flag_t flags, flag_t mask, const str * next_domain, const str * comment) {
+	int next_domain_id;
+	struct carrier_data_t * carrier_data = NULL;
+	struct domain_data_t * domain_data = NULL;
+	LM_INFO("adding prefix %.*s, reply code %.*s\n", scan_prefix->len, scan_prefix->s, reply_code->len, reply_code->s);
+		
+	if (reply_code->len!=3) {
+		LM_ERR("invalid reply_code '%.*s'!\n", reply_code->len, reply_code->s);
+		return -1;
+	}
+	
+	if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
+		LM_ERR("could not retrieve carrier data\n");
+		return -1;
+	}
+	
+	if ((domain_data = get_domain_data_by_name(carrier_data, domain)) == NULL) {
+		LM_ERR("could not retrieve domain data\n");
+		return -1;
+	}
+
+	if ((next_domain_id = add_domain(next_domain)) < 0) {
+		LM_ERR("add_domain failed\n");
+		return -1;
+	}
+	
+	LM_INFO("found failure route, now adding\n");
+	return add_failure_route_to_tree(domain_data->failure_tree, scan_prefix, scan_prefix, host, reply_code,
+			flags, mask, next_domain_id, comment);
+}
+
+
+/**
+ * adds a carrier_data struct for given carrier
+ *
+ * @param rd route data to be searched
+ * @param carrier the name of desired carrier
+ * @param carrier_id the id of the carrier
+ * @param domains number of domains for that carrier
+ *
+ * @return a pointer to the root node of the desired routing tree,
+ * NULL on failure
+ */
+struct carrier_data_t * add_carrier_data(struct route_data_t * rd, const str * carrier, int carrier_id, int domains) {
+	int i, index;
+	if (!rd) {
+		LM_ERR("NULL pointer in parameter\n");
+		return NULL;
+	}
+	LM_INFO("add carrier %.*s\n", carrier->len, carrier->s);
+	for (i=0; i<rd->carrier_num; i++) {
+		if (rd->carriers[i]) {
+			if (rd->carriers[i]->id == carrier_id) {
+				LM_INFO("found carrier %i: %.*s\n", rd->carriers[i]->id, rd->carriers[i]->name.len, rd->carriers[i]->name.s);
+				return rd->carriers[i];
+			}
+		}
+	}
+	LM_INFO("carrier %.*s not found, add it\n", carrier->len, carrier->s);
+	if ((index = add_carrier(carrier, carrier_id)) < 0) {
+		LM_ERR("could not add carrier\n");
+		return NULL;
+	}
+	if (index > rd->carrier_num) {
+		LM_ERR("weird: to large tree index\n");
+		return NULL;
+	}
+	if ((rd->carriers[index] = create_carrier_data(carrier, carrier_id, index, domains)) == NULL) {
+		return NULL;
+	}
+	rd->carriers[index]->index = index;
+	LM_INFO("created carrier data: %.*s, with id %i and %ld domains\n", 
+		rd->carriers[index]->name.len, rd->carriers[index]->name.s, rd->carriers[index]->id, 
+		(long)rd->carriers[index]->domain_num);
+	return rd->carriers[index];
+}
+
+
+/**
+ * Create a new carrier_data struct in shared memory and set it up.
+ *
+ * @param carrier_name the name of the carrier
+ * @param carrier_id id of carrier
+ * @param index the index for that carrier
+ * @param domains number of domains for that carrier
+ *
+ * @return a pointer to the newly allocated carrier data or NULL on
+ * error, in which case it LOGs an error message.
+ */
+struct carrier_data_t * create_carrier_data(const str *carrier_name, int carrier_id, int index, int domains) {
+	struct carrier_data_t * tmp;
+	if ((tmp = shm_malloc(sizeof(struct carrier_data_t))) == NULL) {
+		LM_ERR("out of shared memory\n");
+		return NULL;
+	}
+	memset(tmp, 0, sizeof(struct carrier_data_t));
+	if (shm_str_dup(&tmp->name, carrier_name)!=0) {
+		LM_ERR("cannot duplicate string\n");
+		shm_free(tmp);
+		return NULL;
+	}
+	tmp->id = carrier_id;
+	tmp->index = index;
+	tmp->domain_num = domains;
+	if(domains > 0){
+		if ((tmp->domains = shm_malloc(sizeof(struct domain_data_t *) * domains)) == NULL) {
+			LM_ERR("out of shared memory\n");
+			shm_free(tmp->name.s);
+			shm_free(tmp);
+			return NULL;
+		}
+		memset(tmp->domains, 0, sizeof(struct domain_data_t *) * domains);
+	}
+	return tmp;
+}
+
+
+/**
+ * returns the routing tree for the given domain, if domain's tree
+ * doesnt exist, it will be created. If the trees are completely
+ * filled and a not existing domain shall be added, an error is
+ * returned
+ *
+ * @param rd route data to be searched
+ * @param carrier_id the id of the desired carrier
+ *
+ * @return a pointer to the root node of the desired routing tree,
+ * NULL on failure
+ */
+struct carrier_data_t *get_carrier_data(struct route_data_t * rd, int carrier_id) {
+	int i;
+	if (!rd) {
+		LM_ERR("NULL pointer in parameter\n");
+		return NULL;
+	}
+	for (i=0; i<rd->carrier_num; i++) {
+		if (rd->carriers[i]->id == carrier_id) {
+			return rd->carriers[i];
+		}
+	}
+	return NULL;
+}
+
+
+static int add_domain_data(struct carrier_data_t * carrier_data, struct domain_data_t * domain_data) {
+	int i;
+	LM_INFO("tree %.*s has %ld trees\n",
+			carrier_data->name.len, carrier_data->name.s, (long)carrier_data->domain_num);
+	for (i=0; i<carrier_data->domain_num; i++) {
+		LM_DBG("tree %p", carrier_data->domains[i]);
+		if (carrier_data->domains[i] == 0) {
+			carrier_data->domains[i] = domain_data;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+
+/**
+ * Returns the domain data for the given name. If it doesnt exist,
+ * it will be created. If the domain list is completely
+ * filled and a not existing domain shall be added, an error is
+ * returned
+ *
+ * @param carrier_data carrier data to be searched
+ * @param domain the name of desired domain
+ *
+ * @return a pointer to the desired domain data, NULL on failure.
+ */
+struct domain_data_t *get_domain_data_by_name(struct carrier_data_t * carrier_data, const str * domain) {
+	int i, id;
+	struct domain_data_t * domain_data = NULL;
+	if (!carrier_data) {
+		LM_ERR("NULL pointer in parameter\n");
+		return NULL;
+	}
+	for (i=0; i<carrier_data->domain_num; i++) {
+		if (carrier_data->domains[i] && carrier_data->domains[i]->name.s) {
+			if (str_strcmp(&carrier_data->domains[i]->name, domain) == 0) {
+				LM_INFO("found domain %.*s\n", carrier_data->domains[i]->name.len, carrier_data->domains[i]->name.s);
+				return carrier_data->domains[i];
+			}
+		}
+	}
+	LM_INFO("domain %.*s not found, add it\n", domain->len, domain->s);
+	if ((id = add_domain(domain)) < 0) {
+		LM_ERR("could not add domain\n");
+		return NULL;
+	}
+	if ((domain_data = create_domain_data(domain, id)) == NULL) {
+		return NULL;
+	}
+	if (add_domain_data(carrier_data, domain_data) < 0) {
+		LM_ERR("couldn't add domain data\n");
+		destroy_domain_data(domain_data);
+		return NULL;
+	}
+	LM_INFO("created domain data: %.*s, with id %i\n", domain_data->name.len, domain_data->name.s, domain_data->id);
+	return domain_data;
+}
+
+
+/**
+ * Returns the domain data for the given id.
+ *
+ * @param carrier_data carrier data to be searched
+ * @param domain the name of desired domain
+ *
+ * @return a pointer to the desired domain data, NULL if not found.
+ */
+struct domain_data_t * get_domain_data_by_id(struct carrier_data_t * carrier_data, int id) {
+	int i;
+	LM_DBG("searching in carrier %.*s, id %d\n", carrier_data->name.len, carrier_data->name.s, carrier_data->id);
+	for (i=0; i<carrier_data->domain_num; i++) {
+		if (carrier_data->domains[i]) {
+			LM_DBG("tree %.*s, domain %.*s : %i\n", carrier_data->name.len, carrier_data->name.s, carrier_data->domains[i]->name.len, carrier_data->domains[i]->name.s, carrier_data->domains[i]->id);
+			if (carrier_data->domains[i]->id == id) {
+				return carrier_data->domains[i];
+			}
+		}
+	}
+	return NULL;
+}
+
+
+static int fixup_rule_backup(struct route_flags * rf, struct route_rule * rr){
+	struct route_rule_p_list * rl;
+	if(!rr->status && rr->backup){
+		if((rr->backup->rr = find_rule_by_hash(rf, rr->backup->hash_index)) == NULL){
+			LM_ERR("didn't find backup route\n");
+			return -1;
+		}
+	}
+	rl = rr->backed_up;
+	while(rl){
+		if((rl->rr = find_rule_by_hash(rf, rl->hash_index)) == NULL){
+			LM_ERR("didn't find backed up route\n");
+			return -1;
+		}
+		rl = rl->next;
+	}
+	return 0;
+}
+
+
+/**
+ * Does the work for rule_fixup recursively.
+ * First, it tries to set a pointer the rules with an existing hash index
+ * at the marching array index. Afterward, remaining rules are populated
+ * with incrementing hash indices.
+ *
+ * @param node the prefix tree node to be fixed up
+ *
+ * @return 0 on success, -1 on failure
+ */
+static int rule_fixup_recursor(struct dtrie_node_t *node) {
+	struct route_rule * rr;
+	struct route_flags * rf;
+	int i, p_dice, ret = 0;
+
+	for (rf=(struct route_flags *)(node->data); rf!=NULL; rf=rf->next) {
+		p_dice = 0;
+		if (rf->rule_list) {
+			rr = rf->rule_list;
+			rf->rule_num = 0;
+			while (rr) {
+				rf->rule_num++;
+				rf->dice_max += rr->prob * DICE_MAX;
+				rr = rr->next;
+			}
+			rr = rf->rule_list;
+			while (rr) {
+				rr->dice_to = (rr->prob * DICE_MAX) + p_dice;
+				p_dice = rr->dice_to;
+				rr = rr->next;
+			}
+			
+			if (rf->rule_num != rf->max_targets) {
+				LM_ERR("number of rules(%i) differs from max_targets(%i), maybe your config is wrong?\n", rf->rule_num, rf->max_targets);
+				return -1;
+			}
+			if(rf->rules) {
+				shm_free(rf->rules);
+				rf->rules = NULL;
+			}
+			if ((rf->rules = shm_malloc(sizeof(struct route_rule *) * rf->rule_num)) == NULL) {
+				LM_ERR("out of shared memory\n");
+				return -1;
+			}
+			memset(rf->rules, 0, sizeof(struct route_rule *) * rf->rule_num);
+			for (rr = rf->rule_list; rr; rr = rr->next) {
+				if (rr->hash_index) {
+					if (rr->hash_index > rf->rule_num) {
+						LM_ERR("too large hash index %i, max is %i\n", rr->hash_index, rf->rule_num);
+						shm_free(rf->rules);
+						return -1;
+					}
+					if (rf->rules[rr->hash_index - 1]) {
+						LM_ERR("duplicate hash index %i\n", rr->hash_index);
+						shm_free(rf->rules);
+						return -1;
+					}
+					rf->rules[rr->hash_index - 1] = rr;
+					LM_INFO("rule with host %.*s hash has hashindex %i.\n", rr->host.len, rr->host.s, rr->hash_index);
+				}
+			}
+			
+			rr = rf->rule_list;
+			i=0;
+			while (rr && i < rf->rule_num) {
+				if (!rr->hash_index) {
+					if (rf->rules[i]) {
+						i++;
+					} else {
+						rf->rules[i] = rr;
+						rr->hash_index = i + 1;
+						LM_INFO("hashless rule with host %.*s hash hash_index %i\n", rr->host.len, rr->host.s, i+1);
+						rr = rr->next;
+					}
+				} else {
+					rr = rr->next;
+				}
+			}
+			if (rr) {
+				LM_ERR("Could not populate rules: rr: %p\n", rr);
+				return -1;
+			}
+			for(i=0; i<rf->rule_num; i++){
+				ret += fixup_rule_backup(rf, rf->rules[i]);
+			}
+		}
+	}
+
+	for (i=0; i<10; i++) {
+		if (node->child[i]) {
+			ret += rule_fixup_recursor(node->child[i]);
+		}
+	}
+
+	return ret;
+}
+
+
+/**
+ * Fixes the route rules by creating an array for accessing
+ * route rules by hash index directly
+ *
+ * @param rd route data to be fixed
+ *
+ * @return 0 on success, -1 on failure
+ */
+int rule_fixup(struct route_data_t * rd) {
+	int i,j;
+	for (i=0; i<rd->carrier_num; i++) {
+		for (j=0; j<rd->carriers[i]->domain_num; j++) {
+			if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
+				LM_INFO("fixing tree %.*s\n", rd->carriers[i]->domains[j]->name.len, rd->carriers[i]->domains[j]->name.s);
+				if (rule_fixup_recursor(rd->carriers[i]->domains[j]->tree) < 0) {
+					return -1;
+				}
+			} else {
+				LM_NOTICE("empty tree at [%i][%i]\n", i, j);
+			}
+		}
+	}
+	return 0;
+}

+ 65 - 80
modules/carrierroute/carrier_tree.h → modules/carrierroute/cr_carrier.h

@@ -21,71 +21,50 @@
  */
 
 /**
- * \file carrier_tree.h
- * \brief Contains the functions to manage carrier tree data.
+ * \file cr_carrier.h
+ * \brief Contains the functions to manage carrier data.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#ifndef SP_ROUTE_CARRIER_TREE_H
-#define SP_ROUTE_CARRIER_TREE_H
+#ifndef CR_CARRIER_H
+#define CR_CARRIER_H
 
 #include <sys/types.h>
 #include "../../str.h"
-#include "route.h"
-
+#include "../../locking.h"
+#include "../../flags.h"
+#include "cr_data.h"
 
 
 /**
- * initialises the routing data, i.e. it binds the data loader
- * initialises the global data pointer
- *
- * @param source data source, can be db or file
- *
- * @return 0 on success, -1 on failure
+ * The struct for a carrier.
  */
-int init_route_data(const char * source);
-
-/**
- * Loads the routing data into the routing tree and sets the
- * global_data pointer to the new data. The old_data is removed
- * when it is not locked anymore.
- *
- * @return 0 on success, -1 on failure
- */
-int prepare_route_tree(void);
-
-/**
- * Increases lock counter and returns a pointer to the
- * current routing data
- *
- * @return pointer to the global routing data on success,
- * NULL on failure
-*/
-struct rewrite_data * get_data(void);
+struct carrier_data_t {
+	struct domain_data_t ** domains; /*!< array of routing domains */
+	size_t domain_num; /*!< number of routing domains */
+	str name; /*!< name of the carrier */
+	int id; /*!< id of the carrier */
+	int index; /*!< index of the carrier */
+};
 
-/**
- * decrements the lock counter of the routing data
- *
- * @param data data to be released
- */
-void release_data(struct rewrite_data *data);
 
 /**
- * Create a new carrier tree in shared memory and set it up.
+ * Create a new carrier_data struct in shared memory and set it up.
  *
- * @param tree the name of the carrier tree
- * @param carrier_id the id
- * @param id the domain id of the carrier tree
- * @param trees number of route_tree entries
+ * @param carrier_name the name of the carrier
+ * @param carrier_id id of carrier
+ * @param index the index for that carrier
+ * @param domains number of domains for that carrier
  *
- * @return a pointer to the newly allocated route tree or NULL on
+ * @return a pointer to the newly allocated carrier data or NULL on
  * error, in which case it LOGs an error message.
  */
-struct carrier_tree * create_carrier_tree(const str * tree, int carrier_id, int id, int trees);
+struct carrier_data_t * create_carrier_data(const str *carrier_name, int carrier_id, int index, int domains);
+
 
 /**
- * Adds the given route information to the route tree identified by
+ * Adds the given route information to the routing domain identified by
  * domain. scan_prefix identifies the number for which the information
  * is and the rewrite_* parameters define what to do in case of a match.
  * prob gives the probability with which this rule applies if there are
@@ -114,14 +93,15 @@ struct carrier_tree * create_carrier_tree(const str * tree, int carrier_id, int
  *
  * @return 0 on success, -1 on error in which case it LOGs a message.
  */
-int add_route(struct rewrite_data * rd, int carrier_id,
+int add_route(struct route_data_t * rd, int carrier_id,
               const str * domain, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
               double prob, const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix,
               const str * rewrite_local_suffix, int status, int hash_index, int backup, int * backed_up,
               const str * comment);
 
+
 /**
- * Adds the given failure route information to the failure route tree identified by
+ * Adds the given failure route information to the failure routing domain identified by
  * domain. scan_prefix, host, reply_code and flags identifies the number for which
  * the information is and the next_domain parameter defines where to continue routing
  * in case of a match.
@@ -139,43 +119,24 @@ int add_route(struct rewrite_data * rd, int carrier_id,
  *
  * @return 0 on success, -1 on error in which case it LOGs a message.
  */
-int add_failure_route(struct rewrite_data * rd, int carrier_id, const str * domain,
+int add_failure_route(struct route_data_t * rd, int carrier_id, const str * domain,
 											const str * scan_prefix, const str * host, const str * reply_code,
 											flag_t flags, flag_t mask, const str * next_domain, const str * comment);
 
-/**
- * Tries to add a tree to the tree map. If the given tree doesn't
- * exist, it is added. Otherwise, nothing happens.
- *
- * @param tree the tree to be added
- *
- * @return values: on succcess the numerical index of the given tree,
- * -1 on failure
- */
-int add_tree(const str * tree, int carrier_id);
-
-/**
- * Searches for the ID for a Carrier-Name
- *
- * @param tree the carrier, we are looking for
- *
- * @return values: on succcess the id of for this carrier,
- * -1 on failure
- */
-int find_tree(str tree);
 
 /**
- * adds a carrier tree for the given carrier
+ * adds a carrier_data struct for given carrier
  *
- * @param carrier the carrier name of desired routing tree
- * @param carrier_id the id of the carrier
  * @param rd route data to be searched
- * @param trees number of route_tree entries
+ * @param carrier the name of desired carrier
+ * @param carrier_id the id of the carrier
+ * @param domains number of domains for that carrier
  *
  * @return a pointer to the root node of the desired routing tree,
  * NULL on failure
  */
-struct carrier_tree * add_carrier_tree(const str * carrier, int carrier_id, struct rewrite_data * rd, int trees);
+struct carrier_data_t * add_carrier_data(struct route_data_t * rd, const str * carrier, int carrier_id, int domains);
+
 
 /**
  * returns the routing tree for the given domain, if domain's tree
@@ -183,24 +144,48 @@ struct carrier_tree * add_carrier_tree(const str * carrier, int carrier_id, stru
  * filled and a not existing domain shall be added, an error is
  * returned
  *
- * @param carrier_id the id of the desired carrier tree
+ * @param carrier_id the id of the desired carrier
  * @param rd route data to be searched
  *
  * @return a pointer to the root node of the desired routing tree,
  * NULL on failure
  */
-struct carrier_tree * get_carrier_tree(int carrier_id, struct rewrite_data * rd);
+struct carrier_data_t *get_carrier_data(struct route_data_t * rd, int carrier_id);
+
+
+/**
+ * Returns the domain data for the given name. If it doesnt exist,
+ * it will be created. If the domain list is completely
+ * filled and a not existing domain shall be added, an error is
+ * returned
+ *
+ * @param carrier_data carrier data to be searched
+ * @param domain the name of desired domain
+ *
+ * @return a pointer to the desired domain data, NULL on failure.
+ */
+struct domain_data_t *get_domain_data_by_name(struct carrier_data_t * carrier_data, const str * domain);
+
 
 /**
- * Frees the routing data
+ * Returns the domain data for the given id.
+ *
+ * @param carrier_data carrier data to be searched
+ * @param domain the name of desired domain
+ *
+ * @return a pointer to the desired domain data, NULL if not found.
  */
-void destroy_route_data(void);
+struct domain_data_t *get_domain_data_by_id(struct carrier_data_t * carrier_data, int id);
+
 
 /**
- * Destroys the complete routing tree data.
+ * Fixes the route rules by creating an array for accessing
+ * route rules by hash index directly
  *
- * @param data route data to be destroyed
+ * @param rd route data to be fixed
+ *
+ * @return 0 on success, -1 on failure
  */
-void destroy_rewrite_data(struct rewrite_data *data);
+int rule_fixup(struct route_data_t * rd);
 
 #endif

+ 168 - 167
modules/carrierroute/route_config.c → modules/carrierroute/cr_config.c

@@ -21,29 +21,25 @@
  */
 
 /**
- * \file route_config.c
+ * \file cr_config.c
  * \brief Functions for load and save routing data from a config file.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
 #include <confuse.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include "../../mem/shm_mem.h"
 #include "../../mem/mem.h"
 #include "../../ut.h"
-#include "route_config.h"
-#include "route.h"
+#include "cr_config.h"
 #include "carrierroute.h"
-#include "carrier_tree.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-static int save_route_data_recursor(struct route_tree_item * rt, FILE * outfile);
+#include "cr_rule.h"
+#include "cr_domain.h"
+#include "cr_carrier.h"
 
-static cfg_t * parse_config();
-
-static int backup_config();
 
 /**
  * reports errors during config file parsing using LOG macro
@@ -52,12 +48,126 @@ static int backup_config();
  * @param fmt a format string
  * @param ap format arguments
  */
-void conf_error(cfg_t *cfg, const char * fmt, va_list ap) {
+static void conf_error(cfg_t *cfg, const char * fmt, va_list ap) {
 	// FIXME this don't seems to work reliable, produces strange error messages
 	LM_GEN1(L_ERR, (char *) fmt, ap);
 }
 
 
+/**
+ * Parses the config file
+ *
+ * @return a pointer to the configuration data structure, NULL on failure
+ */
+static cfg_t * parse_config(void) {
+	cfg_t * cfg = NULL;
+
+	cfg_opt_t target_opts[] = {
+	                              CFG_STR("comment", 0, CFGF_NONE),
+	                              CFG_INT("strip", 0, CFGF_NONE),
+	                              CFG_STR("rewrite_prefix", 0, CFGF_NONE),
+	                              CFG_FLOAT("prob", 0, CFGF_NONE),
+	                              CFG_INT("hash_index", 0, CFGF_NONE),
+	                              CFG_STR("rewrite_suffix", 0, CFGF_NONE),
+	                              CFG_INT("status", 1, CFGF_NONE),
+	                              CFG_INT_LIST("backed_up", NULL, CFGF_NONE),
+	                              CFG_INT("backup", -1, CFGF_NONE),
+	                              CFG_END()
+	                          };
+
+	cfg_opt_t prefix_opts[] = {
+	                              CFG_SEC("target", target_opts, CFGF_MULTI | CFGF_TITLE),
+	                              CFG_INT("max_targets", -1, CFGF_NONE),
+	                              CFG_END()
+	                          };
+
+	cfg_opt_t domain_opts[] = {
+	                              CFG_SEC("prefix", prefix_opts, CFGF_MULTI | CFGF_TITLE),
+	                              CFG_END()
+	                          };
+
+	cfg_opt_t opts[] = {
+	                       CFG_SEC("domain", domain_opts, CFGF_MULTI | CFGF_TITLE),
+	                       CFG_END()
+	                   };
+
+	cfg = cfg_init(opts, CFGF_NONE);
+
+	cfg_set_error_function(cfg, conf_error);
+
+	switch (cfg_parse(cfg, config_file)) {
+		case CFG_FILE_ERROR: LM_ERR("file not found: %s\n", config_file);
+			return NULL;
+		case CFG_PARSE_ERROR: LM_ERR("error while parsing %s in line %i, section %s\n",
+			                          cfg->filename, cfg->line, cfg->name);
+			return NULL;
+		case CFG_SUCCESS: break;
+	}
+	return cfg;
+}
+
+
+static int backup_config(void) {
+	FILE * from, * to;
+	char * backup_file, ch;
+	LM_INFO("start configuration backup\n");
+	if((backup_file = pkg_malloc(strlen(config_file) + strlen (".bak") + 1)) == NULL){
+		LM_ERR("out of private memory\n");
+		return -1;
+	}
+	if(!strcpy(backup_file, config_file)){
+		LM_ERR("can't copy filename\n");
+		goto errout;
+	}
+	if(!strcat(backup_file, ".bak")){
+		LM_ERR("can't attach suffix\n");
+		goto errout;
+	}
+	/* open source file */
+	if ((from = fopen(config_file, "rb"))==NULL) {
+		LM_ERR("Cannot open source file.\n");
+		goto errout;
+	}
+
+	/* open destination file */
+	if ((to = fopen(backup_file, "wb"))==NULL) {
+		LM_ERR("Cannot open destination file.\n");
+		fclose(from);
+		goto errout;
+	}
+
+	/* copy the file */
+	while (!feof(from)) {
+		ch = fgetc(from);
+		if (ferror(from)) {
+			LM_ERR("Error reading source file.\n");
+			goto errout;
+		}
+		if (!feof(from)) fputc(ch, to);
+		if (ferror(to)) {
+			LM_ERR("Error writing destination file.\n");
+			goto errout;
+		}
+	}
+
+	if (fclose(from)==EOF) {
+		LM_ERR("Error closing source file.\n");
+		goto errout;
+	}
+
+	if (fclose(to)==EOF) {
+		LM_ERR("Error closing destination file.\n");
+		goto errout;
+	}
+	LM_NOTICE("backup written to %s\n", backup_file);
+	pkg_free(backup_file);
+	return 0;
+errout:
+	pkg_free(backup_file);
+	return -1;
+}
+
+
 /**
  * Loads the routing data from the config file given in global
  * variable config_data and stores it in routing tree rd.
@@ -68,7 +178,7 @@ void conf_error(cfg_t *cfg, const char * fmt, va_list ap) {
  * @return 0 means ok, -1 means an error occured
  *
  */
-int load_config(struct rewrite_data * rd) {
+int load_config(struct route_data_t * rd) {
 	cfg_t * cfg = NULL;
 	int n, m, o, i, j, k,l, status, hash_index, max_targets, strip;
 	cfg_t * d, * p, * t;
@@ -82,20 +192,20 @@ int load_config(struct rewrite_data * rd) {
 		return -1;
 	}
 
-	if ((rd->carriers = shm_malloc(sizeof(struct carrier_tree *))) == NULL) {
+	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *))) == NULL) {
 		LM_ERR("out of shared memory\n");
 		return -1;
 	}
-	memset(rd->carriers, 0, sizeof(struct carrier_tree *));
+	memset(rd->carriers, 0, sizeof(struct carrier_data_t *));
 
-	rd->tree_num = 1;
+	rd->carrier_num = 1;
 	n = cfg_size(cfg, "domain");
-	if (add_carrier_tree(&default_tree, 1, rd, n) == NULL) {
-		LM_ERR("couldn't add carrier tree\n");
+	if (add_carrier_data(rd, &default_tree, 1, n) == NULL) {
+		LM_ERR("couldn't add carrier data\n");
 		return -1;
 	}
 
-	memset(rd->carriers[0]->trees, 0, sizeof(struct route_tree *) * n);
+	memset(rd->carriers[0]->domains, 0, sizeof(struct domain_data_t *) * n);
 	for (i = 0; i < n; i++) {
 		d = cfg_getnsec(cfg, "domain", i);
 		domain.s = (char *)cfg_title(d);
@@ -109,7 +219,7 @@ int load_config(struct rewrite_data * rd) {
 			prefix.s = (char *)cfg_title(p);
 			if (prefix.s==NULL) prefix.s="";
 			prefix.len = strlen(prefix.s);
-			if (str_strcasecmp(&prefix, &SP_EMPTY_PREFIX) == 0) {
+			if (str_strcasecmp(&prefix, &CR_EMPTY_PREFIX) == 0) {
 				prefix.s = "";
 				prefix.len = 0;
 			}
@@ -122,7 +232,7 @@ int load_config(struct rewrite_data * rd) {
 				rewrite_host.s = (char *)cfg_title(t);
 				if (rewrite_host.s==NULL) rewrite_host.s="";
 				rewrite_host.len = strlen(rewrite_host.s);
-				if (str_strcasecmp(&rewrite_host, &SP_EMPTY_PREFIX) == 0) {
+				if (str_strcasecmp(&rewrite_host, &CR_EMPTY_PREFIX) == 0) {
 					rewrite_host.s = "";
 					rewrite_host.len = 0;
 				}
@@ -177,119 +287,31 @@ int load_config(struct rewrite_data * rd) {
 	return 0;
 }
 
-/**
- * Parses the config file
- *
- * @return a pointer to the configuration data structure, NULL on failure
- */
-static cfg_t * parse_config(void) {
-	cfg_t * cfg = NULL;
-
-	cfg_opt_t target_opts[] = {
-	                              CFG_STR("comment", 0, CFGF_NONE),
-	                              CFG_INT("strip", 0, CFGF_NONE),
-	                              CFG_STR("rewrite_prefix", 0, CFGF_NONE),
-	                              CFG_FLOAT("prob", 0, CFGF_NONE),
-	                              CFG_INT("hash_index", 0, CFGF_NONE),
-	                              CFG_STR("rewrite_suffix", 0, CFGF_NONE),
-	                              CFG_INT("status", 1, CFGF_NONE),
-	                              CFG_INT_LIST("backed_up", NULL, CFGF_NONE),
-	                              CFG_INT("backup", -1, CFGF_NONE),
-	                              CFG_END()
-	                          };
-
-	cfg_opt_t prefix_opts[] = {
-	                              CFG_SEC("target", target_opts, CFGF_MULTI | CFGF_TITLE),
-	                              CFG_INT("max_targets", -1, CFGF_NONE),
-	                              CFG_END()
-	                          };
-
-	cfg_opt_t domain_opts[] = {
-	                              CFG_SEC("prefix", prefix_opts, CFGF_MULTI | CFGF_TITLE),
-	                              CFG_END()
-	                          };
-
-	cfg_opt_t opts[] = {
-	                       CFG_SEC("domain", domain_opts, CFGF_MULTI | CFGF_TITLE),
-	                       CFG_END()
-	                   };
-
-	cfg = cfg_init(opts, CFGF_NONE);
-
-	cfg_set_error_function(cfg, conf_error);
-
-	switch (cfg_parse(cfg, config_file)) {
-		case CFG_FILE_ERROR: LM_ERR("file not found: %s\n", config_file);
-			return NULL;
-		case CFG_PARSE_ERROR: LM_ERR("error while parsing %s in line %i, section %s\n",
-			                          cfg->filename, cfg->line, cfg->name);
-			return NULL;
-		case CFG_SUCCESS: break;
-	}
-	return cfg;
-}
-
-
-/**
- * Stores the routing data rd in config_file
- *
- * @param rd Pointer to the routing tree which shall be saved to file
- *
- * @return 0 means ok, -1 means an error occured
- */
-int save_config(struct rewrite_data * rd) {
-	FILE * outfile;
-	int i,j;
-
-	if(backup_config() < 0){
-		return -1;
-	}
-
-	if ((outfile = fopen(config_file, "w")) == NULL) {
-		LM_ERR("Could not open config file %s\n", config_file);
-		return -1;
-	}
-
-	i = 0;
-	if (rd->tree_num>=1) {
-		for (j=0; j< rd->carriers[i]->tree_num; j++) {
-			fprintf(outfile, "domain %.*s {\n", rd->carriers[i]->trees[j]->name.len, rd->carriers[i]->trees[j]->name.s);
-			if (save_route_data_recursor(rd->carriers[i]->trees[j]->tree, outfile) < 0) {
-				goto errout;
-			}
-			fprintf(outfile, "}\n\n");
-		}
-	}
-	fclose(outfile);
-	return 0;
-errout:
-	fclose(outfile);
-	LM_ERR("Cannot save config file %s\n", config_file);
-	return -1;
-}
 
 /**
  * Does the work for save_config, traverses the routing data tree
  * and writes each rule to file.
  *
- * @param rt the current route tree node
+ * @param node the current prefix tree node
  * @param outfile the filehandle to which the config data is written
  *
  * @return 0 on success, -1 on failure
  */
-static int save_route_data_recursor(struct route_tree_item * rt, FILE * outfile) {
+static int save_route_data_recursor(struct dtrie_node_t * node, FILE * outfile) {
 	int i;
+	struct route_flags *rf;
 	struct route_rule * rr;
 	struct route_rule_p_list * rl;
 	str *tmp_str;
 	str null_str = str_init("NULL");
 
 	/* no support for flag lists in route config */
-	if (rt->flag_list && rt->flag_list->rule_list) {
-		rr = rt->flag_list->rule_list;
+	rf = (struct route_flags *)(node->data);
+	if (rf && rf->rule_list) {
+		rr = rf->rule_list;
 		tmp_str = (rr->prefix.len ? &rr->prefix : &null_str);
 		fprintf(outfile, "\tprefix %.*s {\n", tmp_str->len, tmp_str->s);
-		fprintf(outfile, "\t\tmax_targets = %i\n\n", rt->flag_list->max_targets);
+		fprintf(outfile, "\t\tmax_targets = %i\n\n", rf->max_targets);
 		while (rr) {
 			tmp_str = (rr->host.len ? &rr->host : &null_str);
 			fprintf(outfile, "\t\ttarget %.*s {\n", tmp_str->len, tmp_str->s);
@@ -331,8 +353,8 @@ static int save_route_data_recursor(struct route_tree_item * rt, FILE * outfile)
 		fprintf(outfile, "\t}\n");
 	}
 	for (i = 0; i < 10; i++) {
-		if (rt->nodes[i]) {
-			if (save_route_data_recursor(rt->nodes[i], outfile) < 0) {
+		if (node->child[i]) {
+			if (save_route_data_recursor(node->child[i], outfile) < 0) {
 				return -1;
 			}
 		}
@@ -340,62 +362,41 @@ static int save_route_data_recursor(struct route_tree_item * rt, FILE * outfile)
 	return 0;
 }
 
-static int backup_config(void) {
-	FILE * from, * to;
-	char * backup_file, ch;
-	LM_INFO("start configuration backup\n");
-	if((backup_file = pkg_malloc(strlen(config_file) + strlen (".bak") + 1)) == NULL){
-		LM_ERR("out of private memory\n");
-		return -1;
-	}
-	if(!strcpy(backup_file, config_file)){
-		LM_ERR("can't copy filename\n");
-		goto errout;
-	}
-	if(!strcat(backup_file, ".bak")){
-		LM_ERR("can't attach suffix\n");
-		goto errout;
-	}
-	/* open source file */
-	if ((from = fopen(config_file, "rb"))==NULL) {
-		LM_ERR("Cannot open source file.\n");
-		goto errout;
-	}
 
-	/* open destination file */
-	if ((to = fopen(backup_file, "wb"))==NULL) {
-		LM_ERR("Cannot open destination file.\n");
-		fclose(from);
-		goto errout;
-	}
+/**
+ * Stores the routing data rd in config_file
+ *
+ * @param rd Pointer to the routing tree which shall be saved to file
+ *
+ * @return 0 means ok, -1 means an error occured
+ */
+int save_config(struct route_data_t * rd) {
+	FILE * outfile;
+	int i,j;
 
-	/* copy the file */
-	while (!feof(from)) {
-		ch = fgetc(from);
-		if (ferror(from)) {
-			LM_ERR("Error reading source file.\n");
-			goto errout;
-		}
-		if (!feof(from)) fputc(ch, to);
-		if (ferror(to)) {
-			LM_ERR("Error writing destination file.\n");
-			goto errout;
-		}
+	if(backup_config() < 0){
+		return -1;
 	}
 
-	if (fclose(from)==EOF) {
-		LM_ERR("Error closing source file.\n");
-		goto errout;
+	if ((outfile = fopen(config_file, "w")) == NULL) {
+		LM_ERR("Could not open config file %s\n", config_file);
+		return -1;
 	}
 
-	if (fclose(to)==EOF) {
-		LM_ERR("Error closing destination file.\n");
-		goto errout;
+	i = 0;
+	if (rd->carrier_num>=1) {
+		for (j=0; j< rd->carriers[i]->domain_num; j++) {
+			fprintf(outfile, "domain %.*s {\n", rd->carriers[i]->domains[j]->name.len, rd->carriers[i]->domains[j]->name.s);
+			if (save_route_data_recursor(rd->carriers[i]->domains[j]->tree, outfile) < 0) {
+				goto errout;
+			}
+			fprintf(outfile, "}\n\n");
+		}
 	}
-	LM_NOTICE("backup written to %s\n", backup_file);
-	pkg_free(backup_file);
+	fclose(outfile);
 	return 0;
 errout:
-	pkg_free(backup_file);
+	fclose(outfile);
+	LM_ERR("Cannot save config file %s\n", config_file);
 	return -1;
 }

+ 8 - 6
modules/carrierroute/route_config.h → modules/carrierroute/cr_config.h

@@ -21,16 +21,17 @@
  */
 
 /**
- * \file route_config.h
+ * \file cr_config.h
  * \brief Functions for load and save routing data from a config file.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#ifndef SP_ROUTE_ROUTE_CONFIG_H
-#define SP_ROUTE_ROUTE_CONFIG_H
+#ifndef CR_CONFIG_H
+#define CR_CONFIG_H
+
+#include "cr_data.h"
 
-#include "route_tree.h"
 
 /**
  * Loads the routing data from the config file given in global
@@ -42,7 +43,8 @@
  * @return 0 means ok, -1 means an error occured
  *
  */
-int load_config(struct rewrite_data * rd);
+int load_config(struct route_data_t * rd);
+
 
 /**
  * Stores the routing data rd in config_file
@@ -52,6 +54,6 @@ int load_config(struct rewrite_data * rd);
  * @return 0 means ok, -1 means an error occured
  *
  */
-int save_config(struct rewrite_data * rd);
+int save_config(struct route_data_t * rd);
 
 #endif

+ 253 - 0
modules/carrierroute/cr_data.c

@@ -0,0 +1,253 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007-2008 1&1 Internet AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * \file cr_data.c
+ * \brief Contains the functions to manage routing data.
+ * \ingroup carrierroute
+ * - Module; \ref carrierroute
+ */
+
+#include "../../mem/shm_mem.h"
+#include "cr_data.h"
+#include "carrierroute.h"
+#include "cr_config.h"
+#include "cr_db.h"
+#include "cr_carrier.h"
+#include "cr_domain.h"
+
+
+/**
+ * Pointer to the routing data.
+ */
+struct route_data_t ** global_data = NULL;
+
+
+/**
+ * Destroys a carrier
+ *
+ * @param tree route data to be destroyed
+ */
+static void destroy_carrier_data(struct carrier_data_t * carrier_data) {
+	int i;
+
+	if (carrier_data == NULL) {
+		return;
+	}
+	if (carrier_data->domains != NULL) {
+		for (i = 0; i < carrier_data->domain_num; ++i) {
+			if (carrier_data->domains[i] != NULL) {
+				destroy_domain_data(carrier_data->domains[i]);
+			}
+		}
+		shm_free(carrier_data->domains);
+	}
+	if(carrier_data->name.s){
+		shm_free(carrier_data->name.s);
+	}
+	shm_free(carrier_data);
+	return;
+}
+
+
+static int carrier_data_fixup(struct route_data_t * rd){
+	int i;
+	str tmp;
+	tmp = default_tree;
+	rd->default_carrier_index = -1;
+	for(i=0; i<rd->carrier_num; i++){
+		if(rd->carriers[i]){
+			if(str_strcmp(&(rd->carriers[i]->name), &tmp) == 0){
+				rd->default_carrier_index = i;
+			}
+		}
+	}
+	if(rd->default_carrier_index < 0){
+		LM_ERR("default_carrier not found\n");
+	}
+	return 0;
+}
+
+
+/**
+ * initialises the routing data, initialises the global data pointer
+ *
+ * @return 0 on success, -1 on failure
+ */
+int init_route_data(void) {
+	if (global_data == NULL) {
+		global_data = (struct route_data_t **)
+		              shm_malloc(sizeof(struct route_data_t *));
+		if (global_data == NULL) {
+			LM_ERR("Out of shared memory before even doing anything.\n");
+			return -1;
+		}
+	}
+	*global_data = NULL;
+	return 0;
+}
+
+
+/**
+ * Frees the routing data
+ */
+void destroy_route_data(void){
+	struct route_data_t * rd = get_data();
+	clear_route_data(rd);
+	if(global_data){
+		*global_data = NULL;
+		shm_free(global_data);
+		global_data = NULL;
+	}
+}
+
+
+/**
+ * Clears the complete routing data.
+ *
+ * @param data route data to be cleared
+ */
+void clear_route_data(struct route_data_t *data) {
+	int i;
+
+	if (data == NULL) {
+		return;
+	}
+	if (data->carriers != NULL) {
+		for (i = 0; i < data->carrier_num; ++i) {
+			if (data->carriers[i] != NULL) {
+				destroy_carrier_data(data->carriers[i]);
+			}
+		}
+		shm_free(data->carriers);
+	}
+	shm_free(data);
+	return;
+}
+
+
+/**
+ * Loads the routing data into the routing trees and sets the
+ * global_data pointer to the new data. The old_data is removed
+ * when it is not locked anymore.
+ *
+ * @return 0 on success, -1 on failure
+ */
+int reload_route_data(void) {
+	struct route_data_t * old_data;
+	struct route_data_t * new_data = NULL;
+	int i;
+
+	if ((new_data = shm_malloc(sizeof(struct route_data_t))) == NULL) {
+		LM_ERR("out of shared memory\n");
+		return -1;
+	}
+	memset(new_data, 0, sizeof(struct route_data_t));
+
+	switch (mode) {
+	case CARRIERROUTE_MODE_DB:
+		if (load_route_data_db(new_data) < 0) {
+			LM_ERR("could not load routing data\n");
+			return -1;
+		}
+		break;
+	case CARRIERROUTE_MODE_FILE:
+		if (load_config(new_data) < 0) {
+			LM_ERR("could not load routing data\n");
+			return -1;
+		}
+		break;
+	default:
+		LM_ERR("invalid mode");
+		return -1;
+	}
+	if (new_data == NULL) {
+		LM_ERR("loading routing data failed (NULL pointer)");
+		return -1;
+	}
+
+	if (rule_fixup(new_data) < 0) {
+		LM_ERR("could not fixup rules\n");
+		return -1;
+	}
+
+	if (carrier_data_fixup(new_data) < 0){
+		LM_ERR("could not fixup trees\n");
+		return -1;
+	}
+
+	new_data->proc_cnt = 0;
+
+	if (*global_data == NULL) {
+		*global_data = new_data;
+	} else {
+		old_data = *global_data;
+		*global_data = new_data;
+		i = 0;
+		while (old_data->proc_cnt > 0) {
+			LM_ERR("data is still locked after %i seconds\n", i);
+			sleep_us(i*1000000);
+			i++;
+		}
+		clear_route_data(old_data);
+	}
+	return 0;
+}
+
+
+/**
+ * Increases lock counter and returns a pointer to the
+ * current routing data
+ *
+ * @return pointer to the global routing data on success,
+ * NULL on failure
+*/
+struct route_data_t * get_data(void) {
+	struct route_data_t *ret;
+	if (!global_data || !*global_data) {
+		return NULL;
+	}
+	ret = *global_data;
+	lock_get(&ret->lock);
+	++ret->proc_cnt;
+	lock_release(&ret->lock);
+	if (ret == *global_data) {
+		return ret;
+	} else {
+		lock_get(&ret->lock);
+		--ret->proc_cnt;
+		lock_release(&ret->lock);
+		return NULL;
+	}
+}
+
+
+/**
+ * decrements the lock counter of the routing data
+ *
+ * @param data data to be released
+ */
+void release_data(struct route_data_t *data) {
+	lock_get(&data->lock);
+	--data->proc_cnt;
+	lock_release(&data->lock);
+}

+ 97 - 0
modules/carrierroute/cr_data.h

@@ -0,0 +1,97 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007-2008 1&1 Internet AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * \file cr_data.h
+ * \brief Contains the functions to manage routing data.
+ * \ingroup carrierroute
+ * - Module; \ref carrierroute
+ */
+
+#ifndef CR_DATA_H
+#define CR_DATA_H
+
+#include <sys/types.h>
+#include "../../locking.h"
+
+
+/**
+ * contains all routing data.
+ */
+struct route_data_t {
+	struct carrier_data_t ** carriers; /*!< array of carriers */
+	size_t carrier_num; /*!< number of carriers */
+	int default_carrier_index;
+	int proc_cnt; /*!< a ref counter for the shm data */
+	gen_lock_t lock; /*!< lock for ref counter updates */
+};
+
+/**
+ * initialises the routing data, initialises the global data pointer
+ *
+ * @return 0 on success, -1 on failure
+ */
+int init_route_data(void);
+
+
+/**
+ * Frees the routing data
+ */
+void destroy_route_data(void);
+
+
+/**
+ * Clears the complete routing data.
+ *
+ * @param data route data to be cleared
+ */
+void clear_route_data(struct route_data_t *data);
+
+
+/**
+ * Loads the routing data into the routing trees and sets the
+ * global_data pointer to the new data. The old_data is removed
+ * when it is not locked anymore.
+ *
+ * @return 0 on success, -1 on failure
+ */
+int reload_route_data(void);
+
+
+/**
+ * Increases lock counter and returns a pointer to the
+ * current routing data
+ *
+ * @return pointer to the global routing data on success,
+ * NULL on failure
+*/
+struct route_data_t * get_data(void);
+
+
+/**
+ * decrements the lock counter of the routing data
+ *
+ * @param data data to be released
+ */
+void release_data(struct route_data_t *data);
+
+#endif

+ 11 - 6
modules/carrierroute/route_db.c → modules/carrierroute/cr_db.c

@@ -31,11 +31,13 @@
 #include "../../mem/mem.h"
 #include "../../mem/shm_mem.h"
 #include "carrierroute.h"
-#include "route_db.h"
+#include "cr_db.h"
+#include "cr_carrier.h"
 #include <stdio.h>
 
 #define QUERY_LEN 2048
 
+/*! carrier list */
 struct carrier {
 	int id;
 	char * name;
@@ -129,6 +131,7 @@ int load_user_carrier(str * user, str * domain) {
 	return id;
 }
 
+
 /**
  * Loads the routing data from the database given in global
  * variable db_url and stores it in routing tree rd.
@@ -139,7 +142,7 @@ int load_user_carrier(str * user, str * domain) {
  * @return 0 means ok, -1 means an error occured
  *
  */
-int load_route_data(struct rewrite_data * rd) {
+int load_route_data_db(struct route_data_t * rd) {
 	db_res_t * res = NULL;
 	db_row_t * row = NULL;
 	int i, ret, carrier_count = 0;
@@ -160,12 +163,12 @@ int load_route_data(struct rewrite_data * rd) {
 		goto errout;
 	}
 
-	if ((rd->carriers = shm_malloc(sizeof(struct carrier_tree *) * carrier_count)) == NULL) {
+	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *) * carrier_count)) == NULL) {
 		LM_ERR("out of shared memory\n");
 		goto errout;
 	}
-	memset(rd->carriers, 0, sizeof(struct carrier_tree *) * carrier_count);
-	rd->tree_num = carrier_count;
+	memset(rd->carriers, 0, sizeof(struct carrier_data_t *) * carrier_count);
+	rd->carrier_num = carrier_count;
 
 	tmp = carriers;
 	for (i=0; i<carrier_count; i++) {
@@ -187,7 +190,7 @@ int load_route_data(struct rewrite_data * rd) {
 		LM_INFO("name %s, id %i, trees: %i\n", tmp->name, tmp->id, RES_ROW_N(res));
 		tmp_carrier.s=tmp->name;
 		tmp_carrier.len=strlen(tmp_carrier.s);
-		if (add_carrier_tree(&tmp_carrier, tmp->id, rd, RES_ROW_N(res)) == NULL) {
+		if (add_carrier_data(rd, &tmp_carrier, tmp->id, RES_ROW_N(res)) == NULL) {
 			LM_ERR("can't add carrier %s\n", tmp->name);
 			goto errout;
 		}
@@ -331,6 +334,7 @@ errout:
 	return -1;
 }
 
+
 static int store_carriers(struct carrier ** start){
 	db_res_t * res = NULL;
 	int i, count;
@@ -373,6 +377,7 @@ if(res){
 	return -1;
 }
 
+
 static void destroy_carriers(struct carrier * start){
 	struct carrier * tmp, * tmp2;
 	tmp = start;

+ 5 - 5
modules/carrierroute/route_db.h → modules/carrierroute/cr_db.h

@@ -21,18 +21,18 @@
  */
 
 /**
- * @file route_db.h
+ * @file cr_db.h
  * @brief Functions for loading routing data from a database.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#ifndef SP_ROUTE_ROUTE_DB_H
-#define SP_ROUTE_ROUTE_DB_H
+#ifndef CR_DB_H
+#define CR_DB_H
 
 #include "../../db/db.h"
-#include "carrier_tree.h"
 #include "db_carrierroute.h"
+#include "cr_data.h"
 
 
 #define COLUMN_NUM 12
@@ -80,7 +80,7 @@ extern str * failure_columns[];
  * @return 0 means ok, -1 means an error occured
  *
  */
-int load_route_data (struct rewrite_data * rd);
+int load_route_data_db (struct route_data_t * rd);
 
 int load_user_carrier(str * user, str * domain);
 

+ 62 - 46
modules/carrierroute/route_fifo.c → modules/carrierroute/cr_fifo.c

@@ -21,24 +21,28 @@
  */
 
 /**
- * \file route_fifo.c
+ * \file cr_fifo.c
  * \brief Functions for modifying routing data via fifo commands.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#include "route_fifo.h"
-#include "carrierroute.h"
-#include "route_rule.h"
-#include "route_config.h"
+#include <ctype.h>
+#include <stdlib.h>
 
 #include "../../mem/mem.h"
 #include "../../mem/shm_mem.h"
-#include <ctype.h>
-#include <stdlib.h>
 #include "../../str.h"
 #include "../../ut.h"
 
+#include "cr_fifo.h"
+#include "carrierroute.h"
+#include "cr_config.h"
+#include "cr_carrier.h"
+#include "cr_domain.h"
+#include "cr_rule.h"
+
+
 /**
  * Defines the option set for the different fifo commands
  * Every line is for a command,
@@ -51,8 +55,11 @@ static unsigned int opt_settings[5][3] = {{O_PREFIX|O_DOMAIN|O_HOST|O_PROB, O_R_
         {O_HOST|O_DOMAIN|O_PREFIX, O_PROB|O_NEW_TARGET, O_R_PREFIX|O_R_SUFFIX|O_H_INDEX},
         {O_HOST|O_DOMAIN|O_PREFIX, O_PROB, O_R_PREFIX|O_R_SUFFIX|O_NEW_TARGET|O_H_INDEX}};
 
+int fifo_err;
+
+static int updated;
 
-static int dump_tree_recursor (struct mi_node* msg, struct route_tree_item *tree, char *prefix);
+static int dump_tree_recursor (struct mi_node* msg, struct dtrie_node_t *node, char *prefix);
 
 static struct mi_root* print_replace_help(void);
 
@@ -60,7 +67,7 @@ static int get_fifo_opts(str * buf, fifo_opt_t * opts, unsigned int opt_set[]);
 
 static int update_route_data(fifo_opt_t * opts);
 
-static int update_route_data_recursor(struct route_tree_item * rt, str * act_domain, fifo_opt_t * opts);
+static int update_route_data_recursor(struct dtrie_node_t *node, str * act_domain, fifo_opt_t * opts);
 
 static struct mi_root* print_fifo_err(void);
 
@@ -85,6 +92,7 @@ static int str_toklen(str * str, const char * delims)
 	return len;
 }
 
+
 /**
  * reloads the routing data
  *
@@ -96,7 +104,7 @@ static int str_toklen(str * str, const char * delims)
 struct mi_root* reload_fifo (struct mi_root* cmd_tree, void *param) {
 	struct mi_root * tmp = NULL;
 
-	if (prepare_route_tree () == -1) {
+	if (reload_route_data () == -1) {
 		tmp = init_mi_tree(500, "failed to re-built tree, see log", 33);
 	}
 	else {
@@ -105,9 +113,6 @@ struct mi_root* reload_fifo (struct mi_root* cmd_tree, void *param) {
 	return tmp;
 }
 
-int fifo_err;
-
-static int updated;
 
 /**
  * prints the routing data
@@ -118,7 +123,7 @@ static int updated;
  * @return code 200 on success, code 400 or 500 on failure
  */
 struct mi_root* dump_fifo (struct mi_root* cmd_tree, void *param) {
-	struct rewrite_data * rd;
+	struct route_data_t * rd;
 	str *tmp_str;
 	str empty_str = str_init("<empty>");
 
@@ -138,19 +143,19 @@ struct mi_root* dump_fifo (struct mi_root* cmd_tree, void *param) {
 
 	LM_DBG("start processing of data\n");
 	int i, j;
- 	for (i = 0; i < rd->tree_num; i++) {
+ 	for (i = 0; i < rd->carrier_num; i++) {
  		if (rd->carriers[i]) {
 			tmp_str = (rd->carriers[i] ? &rd->carriers[i]->name : &empty_str);
 			node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "Printing tree for carrier %.*s (%i)\n", tmp_str->len, tmp_str->s, rd->carriers[i] ? rd->carriers[i]->id : 0);
 			if(node == NULL)
 				goto error;
- 			for (j=0; j<rd->carriers[i]->tree_num; j++) {
- 				if (rd->carriers[i]->trees[j] && rd->carriers[i]->trees[j]->tree) {
-					tmp_str = (rd->carriers[i]->trees[j] ? &rd->carriers[i]->trees[j]->name : &empty_str);
+ 			for (j=0; j<rd->carriers[i]->domain_num; j++) {
+ 				if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
+					tmp_str = (rd->carriers[i]->domains[j] ? &rd->carriers[i]->domains[j]->name : &empty_str);
 					node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "Printing tree for domain %.*s\n", tmp_str->len, tmp_str->s);
 					if(node == NULL)
 						goto error;
- 					dump_tree_recursor (&rpl_tree->node, rd->carriers[i]->trees[j]->tree, "");
+ 					dump_tree_recursor (&rpl_tree->node, rd->carriers[i]->domains[j]->tree, "");
 				}
  			}
 		}
@@ -165,6 +170,7 @@ error:
 	return 0;
 }
 
+
 /**
  * replaces the host specified by parameters in the
  * fifo command, can be used only in file mode
@@ -181,7 +187,7 @@ struct mi_root* replace_host (struct mi_root* cmd_tree, void *param) {
 	int ret;
 	fifo_opt_t options;
 
-	if(mode != SP_ROUTE_MODE_FILE) {
+	if(mode != CARRIERROUTE_MODE_FILE) {
 		return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
 	}
 	
@@ -208,6 +214,7 @@ struct mi_root* replace_host (struct mi_root* cmd_tree, void *param) {
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
 
+
 /**
  * deactivates the host given in the command line options,
  * can be used only in file mode
@@ -224,7 +231,7 @@ struct mi_root* deactivate_host (struct mi_root* cmd_tree, void *param) {
 	int ret;
 	fifo_opt_t options;
 
-	if(mode != SP_ROUTE_MODE_FILE) {
+	if(mode != CARRIERROUTE_MODE_FILE) {
 		return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
 	}
 
@@ -251,6 +258,7 @@ struct mi_root* deactivate_host (struct mi_root* cmd_tree, void *param) {
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
 
+
 /**
  * activates the host given in the command line options,
  * can be used only in file mode
@@ -267,7 +275,7 @@ struct mi_root* activate_host (struct mi_root* cmd_tree, void *param) {
 	int ret;
 	fifo_opt_t options;
 
-	if(mode != SP_ROUTE_MODE_FILE) {
+	if(mode != CARRIERROUTE_MODE_FILE) {
 		return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
 	}
 
@@ -294,6 +302,7 @@ struct mi_root* activate_host (struct mi_root* cmd_tree, void *param) {
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
 
+
 /**
  * adds the host specified by the command line args,
  * can be used only in file mode
@@ -310,7 +319,7 @@ struct mi_root* add_host (struct mi_root* cmd_tree, void *param) {
 	int ret;
 	fifo_opt_t options;
 
-	if(mode != SP_ROUTE_MODE_FILE) {
+	if(mode != CARRIERROUTE_MODE_FILE) {
 		return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
 	}
 
@@ -333,6 +342,7 @@ struct mi_root* add_host (struct mi_root* cmd_tree, void *param) {
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
 
+
 /**
  * deletes the host specified by the command line args,
  * can be used only in file mode
@@ -349,7 +359,7 @@ struct mi_root* delete_host (struct mi_root* cmd_tree, void * param) {
 	int ret;
 	fifo_opt_t options;
 
-	if(mode != SP_ROUTE_MODE_FILE) {
+	if(mode != CARRIERROUTE_MODE_FILE) {
 		return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
 	}
 
@@ -375,6 +385,7 @@ struct mi_root* delete_host (struct mi_root* cmd_tree, void * param) {
 	return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
 }
 
+
 /**
  * does the work for dump_fifo, traverses the routing tree
  * and prints route rules if present.
@@ -385,7 +396,7 @@ struct mi_root* delete_host (struct mi_root* cmd_tree, void * param) {
  *
  * @return mi node containing the route rules
  */
-static int dump_tree_recursor (struct mi_node* msg, struct route_tree_item *tree, char *prefix) {
+static int dump_tree_recursor (struct mi_node* msg, struct dtrie_node_t *node, char *prefix) {
 	char s[256];
 	char *p;
 	int i;
@@ -398,13 +409,13 @@ static int dump_tree_recursor (struct mi_node* msg, struct route_tree_item *tree
 	p = s + strlen (s);
 	p[1] = '\0';
 	for (i = 0; i < 10; ++i) {
-		if (tree->nodes[i] != NULL) {
+		if (node->child[i] != NULL) {
 			*p = i + '0';
-			dump_tree_recursor (msg->next, tree->nodes[i], s);
+			dump_tree_recursor (msg->next, node->child[i], s);
 		}
 	}
 	*p = '\0';
-	for (rf = tree->flag_list; rf != NULL; rf = rf->next) {
+	for (rf = (struct route_flags *)(node->data); rf != NULL; rf = rf->next) {
 		for (rr = rf->rule_list; rr != NULL; rr = rr->next) {
 			if(rf->dice_max){
 				prob = (double)(rr->prob * DICE_MAX)/(double)rf->dice_max;
@@ -436,6 +447,7 @@ static int dump_tree_recursor (struct mi_node* msg, struct route_tree_item *tree
 	return 0;
 }
 
+
 /**
  * parses the command line argument for options
  *
@@ -520,7 +532,7 @@ static int get_fifo_opts(str * buf, fifo_opt_t * opts, unsigned int opt_set[]) {
 							op = -1;
 							break;
 							case OPT_PREFIX:
-							if (str_strcasecmp(&opt_argv[i], &SP_EMPTY_PREFIX) == 0) {
+							if (str_strcasecmp(&opt_argv[i], &CR_EMPTY_PREFIX) == 0) {
 								opts->prefix.s = NULL;
 								opts->prefix.len = 0;
 							} else {
@@ -579,6 +591,7 @@ static int get_fifo_opts(str * buf, fifo_opt_t * opts, unsigned int opt_set[]) {
 	return 0;
 }
 
+
 /**
  * loads the config data into shared memory (but doesn't really
  * share it), updates the routing data and writes it to the config
@@ -590,7 +603,7 @@ static int get_fifo_opts(str * buf, fifo_opt_t * opts, unsigned int opt_set[]) {
  * @return 0 on success, -1 on failure
  */
 static int update_route_data(fifo_opt_t * opts) {
-	struct rewrite_data * rd;
+	struct route_data_t * rd;
 	int i,j;
 	str tmp_domain;
 	str tmp_prefix;
@@ -599,11 +612,11 @@ static int update_route_data(fifo_opt_t * opts) {
 	str tmp_rewrite_suffix;
 	str tmp_comment = str_init("");
 
-	if ((rd = shm_malloc(sizeof(struct rewrite_data))) == NULL) {
+	if ((rd = shm_malloc(sizeof(struct route_data_t))) == NULL) {
 		LM_ERR("out of shared memory\n");
 		return -1;
 	}
-	memset(rd, 0, sizeof(struct rewrite_data));
+	memset(rd, 0, sizeof(struct route_data_t));
 	if (load_config(rd) < 0) {
 		LM_ERR("could not load config");
 		FIFO_ERR(E_LOADCONF);
@@ -657,11 +670,11 @@ static int update_route_data(fifo_opt_t * opts) {
 		}
 
 	} else {
-		for (i=0; i<rd->tree_num; i++) {
+		for (i=0; i<rd->carrier_num; i++) {
 			if(rd->carriers[i]){
-			for (j=0; j<rd->carriers[i]->tree_num; j++) {
-				if (rd->carriers[i]->trees[j] && rd->carriers[i]->trees[j]->tree) {
-					if (update_route_data_recursor(rd->carriers[i]->trees[j]->tree, &rd->carriers[i]->trees[j]->name, opts) < 0) {
+			for (j=0; j<rd->carriers[i]->domain_num; j++) {
+				if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
+					if (update_route_data_recursor(rd->carriers[i]->domains[j]->tree, &rd->carriers[i]->domains[j]->name, opts) < 0) {
 						goto errout;
 					}
 				}
@@ -682,19 +695,20 @@ static int update_route_data(fifo_opt_t * opts) {
 		goto errout;
 	}
 
-	if (prepare_route_tree() == -1) {
-		LM_ERR("could not prepare the route tree");
+	if (reload_route_data() == -1) {
+		LM_ERR("could not reload route data");
 		FIFO_ERR(E_LOADCONF);
 		goto errout;
 	}
 
-	destroy_rewrite_data(rd);
+	clear_route_data(rd);
 	return 0;
 errout:
-	destroy_rewrite_data(rd);
+	clear_route_data(rd);
 	return -1;
 }
 
+
 /**
  * Does the work for update_route_data by recursively
  * traversing the routing tree
@@ -708,13 +722,13 @@ errout:
  *
  * @return 0 on success, -1 on failure
  */
-static int update_route_data_recursor(struct route_tree_item * rt, str * act_domain, fifo_opt_t * opts) {
+static int update_route_data_recursor(struct dtrie_node_t *node, str * act_domain, fifo_opt_t * opts) {
 	int i, hash = 0;
 	struct route_rule * rr, * prev = NULL, * tmp, * backup;
 	struct route_flags *rf;
 
-	if (rt->flag_list && rt->flag_list->rule_list) {
-		rf = rt->flag_list;
+	rf = (struct route_flags *)(node->data);
+	if (rf && rf->rule_list) {
 		rr = rf->rule_list;
 		while (rr) {
 			if ((!opts->domain.len || (strncmp(opts->domain.s, OPT_STAR, strlen(OPT_STAR)) == 0)
@@ -778,7 +792,7 @@ static int update_route_data_recursor(struct route_tree_item * rt, str * act_dom
 									}
 								}
 							}
-							if (add_backup_route(rr, backup) < 0) {
+							if (add_backup_rule(rr, backup) < 0) {
 								LM_ERR("couldn't set backup route\n");
 								FIFO_ERR(E_ADDBACKUP);
 								return -1;
@@ -847,8 +861,8 @@ static int update_route_data_recursor(struct route_tree_item * rt, str * act_dom
 		}
 	}
 	for (i=0; i<10; i++) {
-		if (rt->nodes[i]) {
-			if (update_route_data_recursor(rt->nodes[i], act_domain, opts) < 0) {
+		if (node->child[i]) {
+			if (update_route_data_recursor(node->child[i], act_domain, opts) < 0) {
 				return -1;
 			}
 		}
@@ -856,6 +870,7 @@ static int update_route_data_recursor(struct route_tree_item * rt, str * act_dom
 	return 0;
 }
 
+
 /**
  * prints a short help text for fifo command usage
  */
@@ -905,6 +920,7 @@ error:
        return 0;
 }
 
+
 /**
  * interpret the fifo errors, creates a mi tree
  * @todo this is currently not evaluated for errors during update_route_data

+ 3 - 5
modules/carrierroute/route_fifo.h → modules/carrierroute/cr_fifo.h

@@ -21,19 +21,17 @@
  */
 
 /**
- * \file route_fifo.h
+ * \file cr_fifo.h
  * \brief Functions for modifying routing data via fifo commands.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#ifndef SP_ROUTE_ROUTE_FIFO_H
-#define SP_ROUTE_ROUTE_FIFO_H
+#ifndef CR_FIFO_H
+#define CR_FIFO_H
 
 #include "../../mi/mi.h"
 
-#include "carrier_tree.h"
-
 extern int fifo_err;
 
 #define E_MISC -1

+ 174 - 202
modules/carrierroute/route_func.c → modules/carrierroute/cr_func.c

@@ -21,7 +21,7 @@
  */
 
 /**
- * \file route_func.c
+ * \file cr_func.c
  * \brief Routing and balancing functions.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
@@ -30,9 +30,8 @@
 #include <ctype.h>
 #include <assert.h>
 #include <stdlib.h>
-#include "route_func.h"
-#include "route_tree.h"
-#include "route_db.h"
+#include "cr_func.h"
+#include "cr_db.h"
 #include "../../sr_module.h"
 #include "../../action.h"
 #include "../../parser/parse_uri.h"
@@ -43,95 +42,71 @@
 #include "../../mem/mem.h"
 #include "../../qvalue.h"
 #include "../../dset.h"
+#include "cr_map.h"
+#include "cr_rule.h"
+#include "cr_domain.h"
+#include "cr_carrier.h"
 #include "carrierroute.h"
 
 
-/**
- * Loads user carrier from subscriber table and stores it in an AVP.
- *
- * @param _msg the current SIP message
- * @param _user the user to determine the route tree
- * @param _domain the domain to determine the route tree
- * @param _dstavp the name of the AVP where to store the carrier tree id
- *
- * @return 1 on success, -1 on failure
- */
-int cr_load_user_carrier(struct sip_msg * _msg, pv_elem_t *_user, pv_elem_t *_domain, struct multiparam_t *_dstavp) {
-	str user, domain;
-	int_str avp_val;
-	
-	if (pv_printf_s(_msg, _user, &user)<0)	{
-		LM_ERR("cannot print the user\n");
-		return -1;
-	}
+enum hash_algorithm {
+	alg_crc32 = 1, /*!< hashing algorithm is CRC32 */
+	alg_prime, /*!< hashing algorithm is (right 18 digits of hash_source % prime_number) % max_targets + 1 */
+	alg_error
+};
 
-	if (pv_printf_s(_msg, _domain, &domain)<0)	{
-		LM_ERR("cannot print the domain\n");
-		return -1;
-	}
-	
-	/* get carrier id */
-	if ((avp_val.n = load_user_carrier(&user, &domain)) < 0) {
-		LM_ERR("error in load user carrier");
-		return -1;
-	}
-	else {
-		/* set avp ! */
-		if (add_avp(_dstavp->u.a.flags, _dstavp->u.a.name, avp_val)<0) {
-			LM_ERR("add AVP failed\n");
-			return -1;
-		}
-	}
-	return 1;
-}
+
+static const str SIP_URI  = { .s="sip:",  .len=4 };
+static const str SIPS_URI = { .s="sips:", .len=5 };
+static const str AT_SIGN  = { .s="@",     .len=1 };
 
 
 /**
- * Get the carrier id from multiparam_t structure.
+ * Get the carrier id from gparam_t structure.
  *
  * @param mp carrier id as integer, pseudo-variable or AVP name of carrier
  * @param _msg SIP message
  * @return carrier id on success, -1 otherwise
  *
  */
-int mp2carrier_id(struct sip_msg * _msg, struct multiparam_t *mp) {
+int gp2carrier_id(struct sip_msg * _msg, gparam_t *gp) {
 	int carrier_id;
 	struct usr_avp *avp;
 	int_str avp_val;
 	str tmp;
 
 	/* TODO combine the redundant parts of the logic */
-	switch (mp->type) {
-	case MP_INT:
-		return mp->u.n;
+	switch (gp->type) {
+	case GPARAM_TYPE_INT:
+		return gp->v.ival;
 		break;
-	case MP_AVP:
-		avp = search_first_avp(mp->u.a.flags, mp->u.a.name, &avp_val, 0);
+	case GPARAM_TYPE_AVP:
+		avp = search_first_avp(gp->v.avp.flags, gp->v.avp.name, &avp_val, 0);
 		if (!avp) {
-			LM_ERR("cannot find AVP '%.*s'\n", mp->u.a.name.s.len, mp->u.a.name.s.s);
+			LM_ERR("cannot find AVP '%.*s'\n", gp->v.avp.name.s.len, gp->v.avp.name.s.s);
 			return -1;
 		}
 		if ((avp->flags&AVP_VAL_STR)==0) {
 			return avp_val.n;
 		}
 		else {
-			carrier_id = find_tree(avp_val.s);
+			carrier_id = find_carrier(avp_val.s);
 			if (carrier_id < 0) {
-				LM_WARN("could not find carrier tree '%.*s'\n", avp_val.s.len, avp_val.s.s);
+				LM_WARN("could not find carrier '%.*s'\n", avp_val.s.len, avp_val.s.s);
 				/* might be using fallback later... */
 			}
 			return carrier_id;
 		}
 		break;
-	case MP_PVE:
+	case GPARAM_TYPE_PVE:
 		/* retrieve carrier name from parameter */
-		if (pv_printf_s(_msg, mp->u.p, &tmp)<0) {
+		if (pv_printf_s(_msg, gp->v.pve, &tmp)<0) {
 			LM_ERR("cannot print the carrier\n");
 			return -1;
 		}
-		carrier_id = find_tree(tmp);
+		carrier_id = find_carrier(tmp);
 		if (carrier_id < 0) {
-			LM_WARN("could not find carrier tree '%.*s'\n", tmp.len, tmp.s);
+			LM_WARN("could not find carrier '%.*s'\n", tmp.len, tmp.s);
 			/* might be using fallback later... */
 		}
 		return carrier_id;
@@ -143,28 +118,28 @@ int mp2carrier_id(struct sip_msg * _msg, struct multiparam_t *mp) {
 
 
 /**
- * Get the domain id from multiparam_t structure.
+ * Get the domain id from gparam_t structure.
  *
  * @param _msg SIP message
  * @param mp carrier id as integer, pseudo-variable or AVP name of carrier
  * @return carrier id on success, -1 otherwise
  *
  */
-int mp2domain_id(struct sip_msg * _msg, struct multiparam_t *mp) {
+int gp2domain_id(struct sip_msg * _msg, gparam_t *gp) {
 	int domain_id;
 	struct usr_avp *avp;
 	int_str avp_val;
 	str tmp;
 
 	/* TODO combine the redundant parts of the logic */
-	switch (mp->type) {
-	case MP_INT:
-		return mp->u.n;
+	switch (gp->type) {
+	case GPARAM_TYPE_INT:
+		return gp->v.ival;
 		break;
-	case MP_AVP:
-		avp = search_first_avp(mp->u.a.flags, mp->u.a.name, &avp_val, 0);
+	case GPARAM_TYPE_AVP:
+		avp = search_first_avp(gp->v.avp.flags, gp->v.avp.name, &avp_val, 0);
 		if (!avp) {
-			LM_ERR("cannot find AVP '%.*s'\n", mp->u.a.name.s.len, mp->u.a.name.s.s);
+			LM_ERR("cannot find AVP '%.*s'\n", gp->v.avp.name.s.len, gp->v.avp.name.s.s);
 			return -1;
 		}
 		if ((avp->flags&AVP_VAL_STR)==0) {
@@ -179,9 +154,9 @@ int mp2domain_id(struct sip_msg * _msg, struct multiparam_t *mp) {
 			return domain_id;
 		}
 		break;
-	case MP_PVE:
+	case GPARAM_TYPE_PVE:
 		/* retrieve domain name from parameter */
-		if (pv_printf_s(_msg, mp->u.p, &tmp)<0) {
+		if (pv_printf_s(_msg, gp->v.pve, &tmp)<0) {
 			LM_ERR("cannot print the domain\n");
 			return -1;
 		}
@@ -222,9 +197,9 @@ static inline int reply_code_matcher(const str *rcw, const str *rc) {
 
 
 /**
- * writes the next_domain avp using the rule list of route_tree
+ * writes the next_domain avp using the rule list of failure_tree
  *
- * @param failure_tree the current failure routing tree node
+ * @param failure_tree the head of the failure route rule list
  * @param host last tried host
  * @param reply_code the last reply code
  * @param flags flags for the failure route rule
@@ -232,16 +207,16 @@ static inline int reply_code_matcher(const str *rcw, const str *rc) {
  *
  * @return 0 on success, -1 on failure
  */
-static int set_next_domain_on_rule(const struct failure_route_tree_item *failure_tree,
+static int set_next_domain_on_rule(struct failure_route_rule *frr_head,
 		const str *host, const str *reply_code, const flag_t flags,
-		const struct multiparam_t *dstavp) {
+		const gparam_t *dstavp) {
 	struct failure_route_rule * rr;
 	int_str avp_val;
 	
-	assert(failure_tree != NULL);
+	assert(frr_head != NULL);
 	
 	LM_DBG("searching for matching routing rules");
-	for (rr = failure_tree->rule_list; rr != NULL; rr = rr->next) {
+	for (rr = frr_head; rr != NULL; rr = rr->next) {
 		/*
 		LM_DBG("rr.flags=%d rr.mask=%d flags=%d\n", rr->flags, rr->mask, flags);
 		LM_DBG("rr.host.len=%d host.len=%d\n", rr->host.len, host->len);
@@ -253,16 +228,17 @@ static int set_next_domain_on_rule(const struct failure_route_tree_item *failure
 				((rr->host.len == 0) || (str_strcmp(host, &rr->host)==0)) &&
 				(reply_code_matcher(&(rr->reply_code), reply_code)==0)) {
 			avp_val.n = rr->next_domain;
-			if (add_avp(dstavp->u.a.flags, dstavp->u.a.name, avp_val)<0) {
+			if (add_avp(dstavp->v.avp.flags, dstavp->v.avp.name, avp_val)<0) {
 				LM_ERR("set AVP failed\n");
 				return -1;
 			}
 			
-			LM_INFO("next_domain is %d.\n", rr->next_domain);
+			LM_INFO("next_domain is %d\n", rr->next_domain);
 			return 0;
 		}
 	}
 	
+	LM_INFO("no matching rule for (flags=%d, host='%.*s', reply_code='%.*s') found\n", flags, host->len, host->s, reply_code->len, reply_code->s);
 	return -1;
 }
 
@@ -281,46 +257,24 @@ static int set_next_domain_on_rule(const struct failure_route_tree_item *failure
  *
  * @return 0 on success, -1 on failure, 1 on no more matching child node and no rule list
  */
-static int set_next_domain_recursor(const struct failure_route_tree_item *failure_tree,
+static int set_next_domain_recursor(struct dtrie_node_t *failure_node,
 		const str *uri, const str *host, const str *reply_code, const flag_t flags,
-		const struct multiparam_t *dstavp) {
-	int ret;
-	struct failure_route_tree_item *re_tree;
+		const gparam_t *dstavp) {
 	str re_uri = *uri;
+	void **ret;
 	
 	/* Skip over non-digits.  */
 	while (re_uri.len > 0 && !isdigit(*re_uri.s)) {
 		++re_uri.s;
 		--re_uri.len;
 	}
-	if (re_uri.len == 0 || failure_tree->nodes[*re_uri.s - '0'] == NULL) {
-		if (failure_tree->rule_list == NULL) {
-			LM_INFO("URI or route tree nodes empty, empty rule list\n");
-			return 1;
-		} else {
-			return set_next_domain_on_rule(failure_tree, host, reply_code, flags, dstavp);
-		}
-	} else {
-		/* match, goto the next digit of the uri and try again */
-		re_tree = failure_tree->nodes[*re_uri.s - '0'];
-		re_uri.s++;
-		re_uri.len--;
-		ret = set_next_domain_recursor(re_tree, &re_uri, host, reply_code, flags, dstavp);
-		switch (ret) {
-		case 0:
-			return 0;
-		case 1:
-			if (failure_tree->rule_list != NULL) {
-				return set_next_domain_on_rule(failure_tree, host, reply_code, flags, dstavp);
-			} else {
-					LM_INFO("empty rule list for host [%.*s]%.*s\n", re_uri.len, re_uri.s,
-						host->len, host->s);
-				return 1;
-			}
-		default:
-			return -1;
-		}
+	ret = dtrie_longest_match(failure_node, re_uri.s, re_uri.len, NULL);
+
+	if (ret == NULL) {
+		LM_INFO("URI or prefix tree nodes empty, empty rule list\n");
+		return 1;
 	}
+	else return set_next_domain_on_rule(*ret, host, reply_code, flags, dstavp);
 }
 
 
@@ -370,7 +324,7 @@ static struct route_rule * get_rule_by_hash(const struct route_flags * rf,
  * @see rewrite_on_rule()
  */
 static int actually_rewrite(const struct route_rule *rs, str *dest,
-		const struct sip_msg *msg, const str * user, struct multiparam_t *dstavp) {
+		const struct sip_msg *msg, const str * user, gparam_t *dstavp) {
 	size_t len;
 	char *p;
 	int_str avp_val;
@@ -380,12 +334,13 @@ static int actually_rewrite(const struct route_rule *rs, str *dest,
 	strip = (strip < 0 ? 0 : strip);
 
 	len = rs->local_prefix.len + user->len + rs->local_suffix.len +
-	      AT_SIGN_LEN + rs->host.len - strip;
+	      AT_SIGN.len + rs->host.len - strip;
 	if (msg->parsed_uri.type == SIPS_URI_T) {
-		len += SIPS_URI_LEN;
+		len += SIPS_URI.len;
 	} else {
-		len += SIP_URI_LEN;
+		len += SIP_URI.len;
 	}
+	dest->len = 0;
 	dest->s = (char *)pkg_malloc(len + 1);
 	if (dest->s == NULL) {
 		LM_ERR("out of private memory.\n");
@@ -394,11 +349,11 @@ static int actually_rewrite(const struct route_rule *rs, str *dest,
 	dest->len = len;
 	p = dest->s;
 	if (msg->parsed_uri.type == SIPS_URI_T) {
-		memcpy(p, SIPS_URI, SIPS_URI_LEN);
-		p += SIPS_URI_LEN;
+		memcpy(p, SIPS_URI.s, SIPS_URI.len);
+		p += SIPS_URI.len;
 	} else {
-		memcpy(p, SIP_URI, SIP_URI_LEN);
-		p += SIP_URI_LEN;
+		memcpy(p, SIP_URI.s, SIP_URI.len);
+		p += SIP_URI.len;
 	}
 	if (user->len) {
 		memcpy(p, rs->local_prefix.s, rs->local_prefix.len);
@@ -407,8 +362,8 @@ static int actually_rewrite(const struct route_rule *rs, str *dest,
 		p += user->len - strip;
 		memcpy(p, rs->local_suffix.s, rs->local_suffix.len);
 		p += rs->local_suffix.len;
-		memcpy(p, AT_SIGN, AT_SIGN_LEN);
-		p += AT_SIGN_LEN;
+		memcpy(p, AT_SIGN.s, AT_SIGN.len);
+		p += AT_SIGN.len;
 	}
 	/* this could be an error, or a blacklisted destination */
 	if (rs->host.len == 0) {
@@ -422,7 +377,7 @@ static int actually_rewrite(const struct route_rule *rs, str *dest,
 
 	if (dstavp) {
 		avp_val.s = rs->host;
-		if (add_avp(AVP_VAL_STR | dstavp->u.a.flags, dstavp->u.a.name, avp_val)<0) {
+		if (add_avp(AVP_VAL_STR | dstavp->v.avp.flags, dstavp->v.avp.name, avp_val)<0) {
 			LM_ERR("set AVP failed\n");
 			pkg_free(dest->s);
 			return -1;
@@ -434,9 +389,9 @@ static int actually_rewrite(const struct route_rule *rs, str *dest,
 
 
 /**
- * writes the uri dest using the rule list of route_tree
+ * writes the uri dest using the flags and rule list of rf_head
  *
- * @param route_tree the current routing tree node
+ * @param rf_head the head of the route flags list
  * @param flags user defined flags
  * @param dest the returned new destination URI
  * @param msg the sip message
@@ -447,18 +402,17 @@ static int actually_rewrite(const struct route_rule *rs, str *dest,
  *
  * @return 0 on success, -1 on failure, 1 on empty rule list
  */
-static int rewrite_on_rule(const struct route_tree_item * route_tree, flag_t flags, str * dest,
+static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest,
 		struct sip_msg * msg, const str * user, const enum hash_source hash_source,
-		const enum hash_algorithm alg, struct multiparam_t *dstavp) {
+		const enum hash_algorithm alg, gparam_t *dstavp) {
 	struct route_flags * rf;
 	struct route_rule * rr;
 	int prob;
 
-	assert(route_tree != NULL);
-	assert(route_tree->flag_list != NULL);
-	
+	assert(rf_head != NULL);
+
 	LM_DBG("searching for matching routing rules");
-	for (rf = route_tree->flag_list; rf != NULL; rf = rf->next) {
+	for (rf = rf_head; rf != NULL; rf = rf->next) {
 		/* LM_DBG("actual flags %i, searched flags %i, mask %i and match %i", rf->flags, flags, rf->mask, flags&rf->mask); */
 		if ((flags&rf->mask) == rf->flags) break;
 	}
@@ -525,7 +479,7 @@ static int rewrite_on_rule(const struct route_tree_item * route_tree, flag_t fla
  * The longest match is taken, so it is possible to define
  * route rules for a single number
  *
- * @param route_tree the current routing tree node
+ * @param node the current routing tree node
  * @param pm the user to be used for prefix matching
  * @param flags user defined flags
  * @param dest the returned new destination URI
@@ -537,46 +491,25 @@ static int rewrite_on_rule(const struct route_tree_item * route_tree, flag_t fla
  *
  * @return 0 on success, -1 on failure, 1 on no more matching child node and no rule list
  */
-static int rewrite_uri_recursor(const struct route_tree_item * route_tree,
+static int rewrite_uri_recursor(struct dtrie_node_t * node,
 		const str * pm, flag_t flags, str * dest, struct sip_msg * msg, const str * user,
 		const enum hash_source hash_source, const enum hash_algorithm alg,
-		struct multiparam_t *dstavp) {
-	struct route_tree_item *re_tree;
-	str re_pm;
-
-	re_pm=*pm;
+		gparam_t *dstavp) {
+	str re_pm = *pm;
+	void **ret;
+	
 	/* Skip over non-digits.  */
 	while (re_pm.len > 0 && !isdigit(*re_pm.s)) {
 		++re_pm.s;
 		--re_pm.len;
 	}
-	if (re_pm.len == 0 || route_tree->nodes[*re_pm.s - '0'] == NULL) {
-		if (route_tree->flag_list == NULL) {
-			LM_INFO("URI or route tree nodes empty, empty flag list\n");
-			return 1;
-		} else {
-			return rewrite_on_rule(route_tree, flags, dest, msg, user, hash_source, alg, dstavp);
-		}
-	} else {
-		/* match, goto the next digit of the uri and try again */
-		re_tree = route_tree->nodes[*re_pm.s - '0'];
-		re_pm.s = re_pm.s + 1;
-		re_pm.len = re_pm.len - 1;
-		switch (rewrite_uri_recursor(re_tree, &re_pm, flags, dest, msg, user, hash_source, alg, dstavp)) {
-			case 0:
-				return 0;
-			case 1:
-				if (route_tree->flag_list != NULL) {
-					return rewrite_on_rule(route_tree, flags, dest, msg, user, hash_source, alg, dstavp);
-				} else {
-					LM_INFO("empty flag list for prefix [%.*s]%.*s\n", user->len - re_pm.len,
-						user->s, re_pm.len, re_pm.s);
-					return 1;
-				}
-			default:
-				return -1;
-		}
+	ret = dtrie_longest_match(node, re_pm.s, re_pm.len, NULL);
+
+	if (ret == NULL) {
+		LM_INFO("URI or prefix tree nodes empty, empty rule list\n");
+		return 1;
 	}
+	else return rewrite_on_rule(*ret, flags, dest, msg, user, hash_source, alg, dstavp);
 }
 
 
@@ -595,21 +528,21 @@ static int rewrite_uri_recursor(const struct route_tree_item * route_tree,
  *
  * @return 1 on success, -1 on failure
  */
-int cr_do_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
-		struct multiparam_t *_domain, pv_elem_t *_prefix_matching,
+int cr_do_route(struct sip_msg * _msg, gparam_t *_carrier,
+		gparam_t *_domain, pv_elem_t *_prefix_matching,
 		pv_elem_t *_rewrite_user, enum hash_source _hsrc,
-		enum hash_algorithm _halg, struct multiparam_t *_dstavp) {
+		enum hash_algorithm _halg, gparam_t *_dstavp) {
 
 	int carrier_id, domain_id, ret = -1;
 	str rewrite_user, prefix_matching, dest;
 	flag_t flags;
-	struct rewrite_data * rd;
-	struct carrier_tree * ct;
-	struct route_tree * rt;
+	struct route_data_t * rd;
+	struct carrier_data_t * carrier_data;
+	struct domain_data_t * domain_data;
 	struct action act;
 
-	carrier_id = mp2carrier_id(_msg, _carrier);
-	domain_id = mp2domain_id(_msg, _domain);
+	carrier_id = gp2carrier_id(_msg, _carrier);
+	domain_id = gp2domain_id(_msg, _domain);
 	if (domain_id < 0) {
 		LM_ERR("invalid domain id %d\n", domain_id);
 		return -1;
@@ -631,36 +564,36 @@ int cr_do_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
 		rd = get_data();
 	} while (rd == NULL);
 	
-	ct=NULL;
+	carrier_data=NULL;
 	if (carrier_id < 0) {
 		if (fallback_default) {
 			LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-			ct = rd->carriers[rd->default_carrier_index];
+			carrier_data = rd->carriers[rd->default_carrier_index];
 		}
 	} else if (carrier_id == 0) {
-		ct = rd->carriers[rd->default_carrier_index];
+		carrier_data = rd->carriers[rd->default_carrier_index];
 	} else {
-		ct = get_carrier_tree(carrier_id, rd);
-		if (ct == NULL) {
+		carrier_data = get_carrier_data(rd, carrier_id);
+		if (carrier_data == NULL) {
 			if (fallback_default) {
 				LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-				ct = rd->carriers[rd->default_carrier_index];
+				carrier_data = rd->carriers[rd->default_carrier_index];
 			}
 		}
 	}
-	if (ct == NULL) {
-		LM_ERR("cannot get carrier tree\n");
+	if (carrier_data == NULL) {
+		LM_ERR("cannot get carrier data\n");
 		goto unlock_and_out;
 	}
 
-	rt = get_route_tree_by_id(ct, domain_id);
-	if (rt == NULL) {
+	domain_data = get_domain_data_by_id(carrier_data, domain_id);
+	if (domain_data == NULL) {
 		LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n",
 			prefix_matching.len, prefix_matching.s, carrier_id, domain_id);
 		goto unlock_and_out;
 	}
 
-	if (rewrite_uri_recursor(rt->tree, &prefix_matching, flags, &dest, _msg, &rewrite_user, _hsrc, _halg, _dstavp) != 0) {
+	if (rewrite_uri_recursor(domain_data->tree, &prefix_matching, flags, &dest, _msg, &rewrite_user, _hsrc, _halg, _dstavp) != 0) {
 		/* this is not necessarily an error, rewrite_recursor does already some error logging */
 		LM_INFO("rewrite_uri_recursor doesn't complete, uri %.*s, carrier %d, domain %d\n", prefix_matching.len,
 			prefix_matching.s, carrier_id, domain_id);
@@ -685,6 +618,47 @@ unlock_and_out:
 	return ret;
 }
 
+
+/**
+ * Loads user carrier from subscriber table and stores it in an AVP.
+ *
+ * @param _msg the current SIP message
+ * @param _user the user to determine the carrier data
+ * @param _domain the domain to determine the domain data
+ * @param _dstavp the name of the AVP where to store the carrier id
+ *
+ * @return 1 on success, -1 on failure
+ */
+int cr_load_user_carrier(struct sip_msg * _msg, pv_elem_t *_user, pv_elem_t *_domain, gparam_t *_dstavp) {
+	str user, domain;
+	int_str avp_val;
+	
+	if (pv_printf_s(_msg, _user, &user)<0)	{
+		LM_ERR("cannot print the user\n");
+		return -1;
+	}
+
+	if (pv_printf_s(_msg, _domain, &domain)<0)	{
+		LM_ERR("cannot print the domain\n");
+		return -1;
+	}
+	
+	/* get carrier id */
+	if ((avp_val.n = load_user_carrier(&user, &domain)) < 0) {
+		LM_ERR("error in load user carrier");
+		return -1;
+	}
+	else {
+		/* set avp ! */
+		if (add_avp(_dstavp->v.avp.flags, _dstavp->v.avp.name, avp_val)<0) {
+			LM_ERR("add AVP failed\n");
+			return -1;
+		}
+	}
+	return 1;
+}
+
+
 /**
  * rewrites the request URI of msg after determining the
  * new destination URI with the crc32 hash algorithm.
@@ -699,10 +673,10 @@ unlock_and_out:
  *
  * @return 1 on success, -1 on failure
  */
-int cr_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
-		struct multiparam_t *_domain, pv_elem_t *_prefix_matching,
+int cr_route(struct sip_msg * _msg, gparam_t *_carrier,
+		gparam_t *_domain, pv_elem_t *_prefix_matching,
 		pv_elem_t *_rewrite_user, enum hash_source _hsrc,
-		struct multiparam_t *_dstavp)
+		gparam_t *_dstavp)
 {
 	return cr_do_route(_msg, _carrier, _domain, _prefix_matching,
 		_rewrite_user, _hsrc, alg_crc32, _dstavp);
@@ -723,18 +697,16 @@ int cr_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
  *
  * @return 1 on success, -1 on failure
  */
-int cr_prime_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
-		struct multiparam_t *_domain, pv_elem_t *_prefix_matching,
+int cr_prime_route(struct sip_msg * _msg, gparam_t *_carrier,
+		gparam_t *_domain, pv_elem_t *_prefix_matching,
 		pv_elem_t *_rewrite_user, enum hash_source _hsrc,
-		struct multiparam_t *_dstavp)
+		gparam_t *_dstavp)
 {
 	return cr_do_route(_msg, _carrier, _domain, _prefix_matching,
 		_rewrite_user, _hsrc, alg_prime, _dstavp);
 }
 
 
-
-
 /**
  * Loads next domain from failure routing table and stores it in an AVP.
  *
@@ -748,19 +720,19 @@ int cr_prime_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
  *
  * @return 1 on success, -1 on failure
  */
-int cr_load_next_domain(struct sip_msg * _msg, struct multiparam_t *_carrier,
-		struct multiparam_t *_domain, pv_elem_t *_prefix_matching,
-		pv_elem_t *_host, pv_elem_t *_reply_code, struct multiparam_t *_dstavp) {
+int cr_load_next_domain(struct sip_msg * _msg, gparam_t *_carrier,
+		gparam_t *_domain, pv_elem_t *_prefix_matching,
+		pv_elem_t *_host, pv_elem_t *_reply_code, gparam_t *_dstavp) {
 
 	int carrier_id, domain_id, ret = -1;
 	str prefix_matching, host, reply_code;
 	flag_t flags;
-	struct rewrite_data * rd;
-	struct carrier_tree * ct;
-	struct route_tree * rt;
+	struct route_data_t * rd;
+	struct carrier_data_t * carrier_data;
+	struct domain_data_t * domain_data;
 
-	carrier_id = mp2carrier_id(_msg, _carrier);
-	domain_id = mp2domain_id(_msg, _domain);
+	carrier_id = gp2carrier_id(_msg, _carrier);
+	domain_id = gp2domain_id(_msg, _domain);
 	if (domain_id < 0) {
 		LM_ERR("invalid domain id %d\n", domain_id);
 		return -1;
@@ -787,36 +759,36 @@ int cr_load_next_domain(struct sip_msg * _msg, struct multiparam_t *_carrier,
 		rd = get_data();
 	} while (rd == NULL);
 	
-	ct=NULL;
+	carrier_data=NULL;
 	if (carrier_id < 0) {
 		if (fallback_default) {
 			LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-			ct = rd->carriers[rd->default_carrier_index];
+			carrier_data = rd->carriers[rd->default_carrier_index];
 		}
 	} else if (carrier_id == 0) {
-		ct = rd->carriers[rd->default_carrier_index];
+		carrier_data = rd->carriers[rd->default_carrier_index];
 	} else {
-		ct = get_carrier_tree(carrier_id, rd);
-		if (ct == NULL) {
+		carrier_data = get_carrier_data(rd, carrier_id);
+		if (carrier_data == NULL) {
 			if (fallback_default) {
 				LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-				ct = rd->carriers[rd->default_carrier_index];
+				carrier_data = rd->carriers[rd->default_carrier_index];
 			}
 		}
 	}
-	if (ct == NULL) {
-		LM_ERR("cannot get carrier tree\n");
+	if (carrier_data == NULL) {
+		LM_ERR("cannot get carrier data\n");
 		goto unlock_and_out;
 	}
 
-	rt = get_route_tree_by_id(ct, domain_id);
-	if (rt == NULL) {
+	domain_data = get_domain_data_by_id(carrier_data, domain_id);
+	if (domain_data == NULL) {
 		LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n",
 			prefix_matching.len, prefix_matching.s, carrier_id, domain_id);
 		goto unlock_and_out;
 	}
 
-	if (set_next_domain_recursor(rt->failure_tree, &prefix_matching, &host, &reply_code, flags, _dstavp) != 0) {
+	if (set_next_domain_recursor(domain_data->failure_tree, &prefix_matching, &host, &reply_code, flags, _dstavp) != 0) {
 		LM_ERR("during set_next_domain_recursor, prefix '%.*s', carrier %d, domain %d\n", prefix_matching.len,
 			prefix_matching.s, carrier_id, domain_id);
 		goto unlock_and_out;

+ 19 - 19
modules/carrierroute/route_func.h → modules/carrierroute/cr_func.h

@@ -22,32 +22,33 @@
  */
 
 /**
- * \file route_func.h
+ * \file cr_func.h
  * \brief Routing and balancing functions.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#ifndef SP_ROUTE_ROUTE_FUNC_H
-#define SP_ROUTE_ROUTE_FUNC_H
+#ifndef CR_FUNC_H
+#define CR_FUNC_H
 
 #include "../../parser/msg_parser.h"
 #include "../../pvar.h"
+#include "../../mod_fix.h"
 #include "prime_hash.h"
-#include "carrierroute.h"
+
 
 /**
  * Loads user carrier from subscriber table and stores it in an AVP.
  *
  * @param _msg the current SIP message
- * @param _user the user to determine the route tree
- * @param _domain the domain to determine the route tree
- * @param _dstavp the name of the AVP where to store the carrier tree id
+ * @param _user the user to determine the carrier data
+ * @param _domain the domain to determine the domain data
+ * @param _dstavp the name of the AVP where to store the carrier id
  *
  * @return 1 on success, -1 on failure
  */
 int cr_load_user_carrier(struct sip_msg * _msg, pv_elem_t *_user,
-		pv_elem_t *_domain, struct multiparam_t *_dstavp);
+		pv_elem_t *_domain, gparam_t *_dstavp);
 
 
 /**
@@ -64,10 +65,11 @@ int cr_load_user_carrier(struct sip_msg * _msg, pv_elem_t *_user,
  *
  * @return 1 on success, -1 on failure
  */
-int cr_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
-		struct multiparam_t *_domain, pv_elem_t *_prefix_matching,
+int cr_route(struct sip_msg * _msg, gparam_t *_carrier,
+		gparam_t *_domain, pv_elem_t *_prefix_matching,
 		pv_elem_t *_rewrite_user, enum hash_source _hsrc,
-		struct multiparam_t *_dstavp);
+		gparam_t *_dstavp);
+
 
 /**
  * rewrites the request URI of msg after determining the
@@ -83,10 +85,10 @@ int cr_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
  *
  * @return 1 on success, -1 on failure
  */
-int cr_prime_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
-		struct multiparam_t *_domain, pv_elem_t *_prefix_matching,
+int cr_prime_route(struct sip_msg * _msg, gparam_t *_carrier,
+		gparam_t *_domain, pv_elem_t *_prefix_matching,
 		pv_elem_t *_rewrite_user, enum hash_source _hsrc,
-		struct multiparam_t *_dstavp);
+		gparam_t *_dstavp);
 
 
 /**
@@ -102,10 +104,8 @@ int cr_prime_route(struct sip_msg * _msg, struct multiparam_t *_carrier,
  *
  * @return 1 on success, -1 on failure
  */
-int cr_load_next_domain(struct sip_msg * _msg, struct multiparam_t *_carrier,
-		struct multiparam_t *_domain, pv_elem_t *_prefix_matching, pv_elem_t *_host,
-		pv_elem_t *_reply_code, struct multiparam_t *_dstavp);
-
-
+int cr_load_next_domain(struct sip_msg * _msg, gparam_t *_carrier,
+		gparam_t *_domain, pv_elem_t *_prefix_matching, pv_elem_t *_host,
+		pv_elem_t *_reply_code, gparam_t *_dstavp);
 
 #endif

+ 233 - 0
modules/carrierroute/cr_map.c

@@ -0,0 +1,233 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007-2008 1&1 Internet AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * \file cr_map.c
+ * \brief Contains the functions to map domain and carrier names to ids.
+ * \ingroup carrierroute
+ * - Module; \ref carrierroute
+ */
+
+#include "cr_map.h"
+#include "../../mem/shm_mem.h"
+#include "../../ut.h"
+
+
+/**
+ * used to map routing domain names to numbers for
+ * faster access.
+ */
+struct domain_map_t {
+	str name; /*!< name of the routing domain */
+	int index; /*!< domain index */
+	struct domain_map_t * next; /*!< pointer to the next element */
+};
+
+/**
+ * used to map carrier names to numbers for
+ * faster access.
+ */
+struct carrier_map_t {
+	str name; /*!< name of the carrier */
+	int id; /*!< id of the carrier */
+	int index; /*!< number of carrier array index for rewrite_data.trees */
+	struct carrier_map_t * next; /*!< pointer to the next element */
+};
+
+
+/**
+ * holds the map between routing domain names and numbers
+ */
+static struct domain_map_t ** domain_map = NULL;
+
+
+/**
+ * holds the map between carrier names and numbers
+ */
+static struct carrier_map_t ** carrier_map = NULL;
+
+
+/**
+ * Tries to add a domain to the domain map. If the given domain doesn't
+ * exist, it is added. Otherwise, nothing happens.
+ *
+ * @param domain the domain to be added
+ *
+ * @return values: on succcess the numerical index of the given domain,
+ * -1 on failure
+ */
+int add_domain(const str * domain) {
+	struct domain_map_t * tmp, * prev = NULL;
+	int index = 0;
+	if (!domain_map) {
+		if ((domain_map = shm_malloc(sizeof(struct domain_map_t *))) == NULL) {
+			LM_ERR("out of shared memory\n");
+			return -1;
+		}
+		memset(domain_map, 0, sizeof(struct domain_map_t *));
+	}
+
+	tmp = *domain_map;
+
+	while (tmp) {
+		if (str_strcmp(&tmp->name, domain) == 0) {
+			return tmp->index;
+		}
+		index = tmp->index + 1;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+	if ((tmp = shm_malloc(sizeof(struct domain_map_t))) == NULL) {
+		LM_ERR("out of shared memory\n");
+		return -1;
+	}
+	memset(tmp, 0, sizeof(struct domain_map_t));
+	if (shm_str_dup(&tmp->name, domain) != 0) {
+		LM_ERR("cannot duplicate string\n");
+		shm_free(tmp);
+		return -1;
+	}
+	tmp->index = index;
+	if (!prev) {
+		*domain_map = tmp;
+	} else {
+		prev->next = tmp;
+	}
+	LM_INFO("domain %.*s has index %i\n", domain->len, domain->s, index);
+	return index;
+}
+
+
+/**
+ * Destroy the domain map by freeing its memory.
+ */
+void destroy_domain_map(void) {
+	struct domain_map_t * tmp;
+	if (domain_map) {
+		tmp = *domain_map;
+		while (*domain_map) {
+			tmp = *domain_map;
+			*domain_map = tmp->next;
+			shm_free(tmp);
+		}
+		shm_free(domain_map);
+		domain_map = NULL;
+	}
+}
+
+
+/**
+ * Tries to add a carrier name to the carrier map. If the given carrier
+ * doesn't exist, it is added. Otherwise, nothing happens.
+ *
+ * @param carrier_name the carrier name to be added
+ * @param carrier_id the corresponding id
+ *
+ * @return values: on succcess the numerical index of the given carrier,
+ * -1 on failure
+ */
+int add_carrier(const str * tree, int carrier_id) {
+	struct carrier_map_t * tmp, * prev = NULL;
+	int index = 0;
+	if (!carrier_map) {
+		if ((carrier_map = shm_malloc(sizeof(struct carrier_map_t *))) == NULL) {
+			LM_ERR("out of shared memory\n");
+			return -1;
+		}
+		*carrier_map = NULL;
+	}
+	tmp = *carrier_map;
+
+	while (tmp) {
+		if (carrier_id == tmp->id) {
+			return tmp->index;
+		}
+		index = tmp->index + 1;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+	if ((tmp = shm_malloc(sizeof(struct carrier_map_t))) == NULL) {
+		LM_ERR("out of shared memory\n");
+		return -1;
+	}
+	memset(tmp, 0, sizeof(struct carrier_map_t));
+	if (shm_str_dup(&tmp->name, tree)!=0) {
+		LM_ERR("cannot duplicate string\n");
+		shm_free(tmp);
+		return -1;
+	}
+	tmp->index = index;
+	tmp->id = carrier_id;
+	if (!prev) {
+		*carrier_map = tmp;
+	} else {
+		prev->next = tmp;
+	}
+	LM_INFO("tree %.*s has internal id %i\n", tree->len, tree->s, index);
+	return index;
+}
+
+
+/**
+ * Searches for the ID for a Carrier-Name
+ *
+ * @param carrier_name the carrier name, we are looking for
+ *
+ * @return values: on succcess the id for this carrier name,
+ * -1 on failure
+ */
+int find_carrier(str carrier_name) {
+	struct carrier_map_t * tmp;
+	if (!carrier_map) {
+		return -1;
+	}
+	if (carrier_name.len <= 0) {
+		return -1;
+	}
+	tmp = *carrier_map;
+
+	while (tmp) {
+		if (str_strcmp(&carrier_name, &tmp->name) == 0) {
+			return tmp->id;
+		}
+		tmp = tmp->next;
+	}
+	return -1;
+}
+
+
+/**
+ * Destroy the carrier map by freeing its memory.
+ */
+void destroy_carrier_map(void) {
+	struct carrier_map_t * tmp;
+	if (carrier_map) {
+		tmp = *carrier_map;
+		while (*carrier_map) {
+			tmp = *carrier_map;
+			*carrier_map = tmp->next;
+			shm_free(tmp);
+		}
+		shm_free(carrier_map);
+		carrier_map = NULL;
+	}
+}

+ 83 - 0
modules/carrierroute/cr_map.h

@@ -0,0 +1,83 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007-2008 1&1 Internet AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * \file cr_map.h
+ * \brief Contains the functions to map domain and carrier names to ids.
+ * \ingroup carrierroute
+ * - Module; \ref carrierroute
+ */
+
+#ifndef CR_MAP_H
+#define CR_MAP_H
+
+#include "../../str.h"
+
+
+/**
+ * Tries to add a domain to the domain map. If the given domain doesn't
+ * exist, it is added. Otherwise, nothing happens.
+ *
+ * @param domain the domain to be added
+ *
+ * @return values: on succcess the numerical index of the given domain,
+ * -1 on failure
+ */
+int add_domain(const str * domain);
+
+
+/**
+ * Destroy the domain map by freeing its memory.
+ */
+void destroy_domain_map(void);
+
+
+/**
+ * Tries to add a carrier name to the carrier map. If the given carrier
+ * doesn't exist, it is added. Otherwise, nothing happens.
+ *
+ * @param carrier_name the carrier name to be added
+ * @param carrier_id the corresponding id
+ *
+ * @return values: on succcess the numerical index of the given carrier,
+ * -1 on failure
+ */
+int add_carrier(const str * tree, int carrier_id);
+
+
+/**
+ * Searches for the ID for a Carrier-Name
+ *
+ * @param carrier_name the carrier name, we are looking for
+ *
+ * @return values: on succcess the id for this carrier name,
+ * -1 on failure
+ */
+int find_carrier(str carrier_name);
+
+
+/**
+ * Destroy the carrier map by freeing its memory.
+ */
+void destroy_carrier_map(void);
+
+#endif

+ 174 - 247
modules/carrierroute/route_rule.c → modules/carrierroute/cr_rule.c

@@ -21,22 +21,15 @@
  */
 
 /**
- * \file route_rule.c
+ * \file cr_rule.c
  * \brief Contains the functions to manage routing rule data.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#include "../../mem/shm_mem.h"
-#include "../../dprint.h"
 #include "../../ut.h"
+#include "cr_rule.h"
 
-#include "carrierroute.h"
-#include "route_rule.h"
-
-static int rule_fixup_recursor(struct route_tree_item * rt);
-
-static int fixup_rule_backup(struct route_flags * rf, struct route_rule * rr);
 
 /**
  * Adds a route rule to rf. prefix, rewrite_hostpart, rewrite_local_prefix,
@@ -165,52 +158,158 @@ mem_error:
 }
 
 
+/**
+ * Destroys route rule rr by freeing all its memory.
+ *
+ * @param rr route rule to be destroyed
+ */
+void destroy_route_rule(struct route_rule * rr) {
+	struct route_rule_p_list * t_rl;
+	if (rr->host.s) {
+		shm_free(rr->host.s);
+	}
+	if (rr->local_prefix.s) {
+		shm_free(rr->local_prefix.s);
+	}
+	if (rr->local_suffix.s) {
+		shm_free(rr->local_suffix.s);
+	}
+	if (rr->comment.s) {
+		shm_free(rr->comment.s);
+	}
+	if (rr->prefix.s) {
+		shm_free(rr->prefix.s);
+	}
+	if(rr->backup){
+		shm_free(rr->backup);
+	}
+	while(rr->backed_up){
+		t_rl = rr->backed_up->next;
+		shm_free(rr->backed_up);
+		rr->backed_up = t_rl;
+	}
+	shm_free(rr);
+	return;
+}
+
+
+/**
+ * Try to find a matching route_flags struct in rt and return it, add it if not found.
+ *
+ * @param rf_head pointer to the head of the route flags list, might be changed during insert.
+ * @param flags user defined flags
+ * @param mask mask for user defined flags
+ *
+ * @return pointer to the route_flags struct on success, NULL on failure.
+ *
+ */
+struct route_flags * add_route_flags(struct route_flags **rf_head, const flag_t flags, const flag_t mask)
+{
+	struct route_flags *shm_rf;
+	struct route_flags *prev_rf, *tmp_rf;
+	prev_rf = tmp_rf = NULL;
+
+	if (rf_head) {
+		/* search for matching route_flags struct */
+		for (tmp_rf=*rf_head; tmp_rf!=NULL; tmp_rf=tmp_rf->next) {
+			if ((tmp_rf->flags == flags) && (tmp_rf->mask == mask)) return tmp_rf;
+		}
+		
+		/* not found, insert one */
+		for (tmp_rf=*rf_head; tmp_rf!=NULL; tmp_rf=tmp_rf->next) {
+			if (tmp_rf->mask < mask) break;
+			prev_rf=tmp_rf;
+		}
+	}
+
+	if ((shm_rf = shm_malloc(sizeof(struct route_flags))) == NULL) {
+		LM_ERR("out of shared memory\n");
+		return NULL;
+	}
+	memset(shm_rf, 0, sizeof(struct route_flags));
+
+	shm_rf->flags=flags;
+	shm_rf->mask=mask;
+	shm_rf->next=tmp_rf;
+	
+	if (prev_rf) {
+		prev_rf->next = shm_rf;
+	}
+	else {
+		if (rf_head) *rf_head=shm_rf;
+	}
+
+	return shm_rf;
+}
+
+
+/**
+ * Destroys route_flags in shared memory by freing all its memory.
+ *
+ * @param rf route_flags struct to be destroyed
+ */
+void destroy_route_flags(struct route_flags *rf) {
+	struct route_rule *rs, *rs_tmp;
+
+	if (rf->rules) {
+		shm_free(rf->rules);
+	}
+	rs = rf->rule_list;
+	while (rs != NULL) {
+		rs_tmp = rs->next;
+		destroy_route_rule(rs);
+		rs = rs_tmp;
+	}
+	shm_free(rf);
+}
+
+
 /**
  * Compares the priority of two failure route rules.
  *
- * @param rr1 first failure rule
- * @param rr2 second failure rule
+ * @param frr1 first failure rule
+ * @param frr2 second failure rule
  *
- * @return 0 if rr1 and rr2 have the same priority, -1 if rr1 has higher priority than rr2, 1 if rr1 has lower priority than rr2.
+ * @return 0 if frr1 and frr2 have the same priority, -1 if frr1 has higher priority than frr2, 1 if frr1 has lower priority than frr2.
  *
  * @see add_failure_route_to_tree()
  */
-int rule_prio_cmp(struct failure_route_rule *rr1, struct failure_route_rule *rr2) {
+static int failure_rule_prio_cmp(struct failure_route_rule *frr1, struct failure_route_rule *frr2) {
 	int n1, n2, i;
 	
 	/* host has highest priority */
-	if ((rr1->host.len == 0) && (rr2->host.len > 0)) {
-		/* host1 is wildcard -> rr1 has lower priority */
+	if ((frr1->host.len == 0) && (frr2->host.len > 0)) {
+		/* host1 is wildcard -> frr1 has lower priority */
 		return 1;
 	}
-	else if ((rr1->host.len > 0) && (rr2->host.len == 0)) {
-		/* host2 is wildcard -> rr1 has higher priority */
+	else if ((frr1->host.len > 0) && (frr2->host.len == 0)) {
+		/* host2 is wildcard -> frr1 has higher priority */
 		return -1;
 	}
 	else {
 		/* reply_code has second highest priority */
 		n1=0;
 		n2=0;
-		for (i=0; i < rr1->reply_code.len; i++) {
-			if (rr1->reply_code.s[i]=='.') n1++;
+		for (i=0; i < frr1->reply_code.len; i++) {
+			if (frr1->reply_code.s[i]=='.') n1++;
 		}
-		for (i=0; i < rr2->reply_code.len; i++) {
-			if (rr2->reply_code.s[i]=='.') n2++;
+		for (i=0; i < frr2->reply_code.len; i++) {
+			if (frr2->reply_code.s[i]=='.') n2++;
 		}
 		if (n1 < n2) {
-			/* reply_code1 has fewer wildcards -> rr1 has higher priority */
+			/* reply_code1 has fewer wildcards -> frr1 has higher priority */
 			return -1;
 		}
 		else if (n1 > n2) {
-			/* reply_code1 has more wildcards -> rr1 has lower priority */
+			/* reply_code1 has more wildcards -> frr1 has lower priority */
 			return 1;
 		}
 		else {
 			/* flags have lowest priority */
-			if (rr1->mask > rr2->mask) {
+			if (frr1->mask > frr2->mask) {
 				return -1;
 			}
-			else if (rr1->mask < rr2->mask) {
+			else if (frr1->mask < frr2->mask) {
 				return 1;
 			}
 		}
@@ -221,10 +320,10 @@ int rule_prio_cmp(struct failure_route_rule *rr1, struct failure_route_rule *rr2
 
 
 /**
- * Adds a failure route rule to rt. prefix, host, reply_code, and comment
+ * Adds a failure route rule to rule list. prefix, host, reply_code, and comment
  * must not contain NULL pointers.
  *
- * @param failure_tree the current route tree node
+ * @param frr_head pointer to the head of the failure route rule list, might be changed during insert
  * @param prefix the whole scan prefix
  * @param host the hostname last tried
  * @param reply_code the reply code 
@@ -233,202 +332,86 @@ int rule_prio_cmp(struct failure_route_rule *rr1, struct failure_route_rule *rr2
  * @param next_domain continue routing with this domain
  * @param comment a comment for the route rule
  *
- * @return 0 on success, -1 on failure
+ * @return pointer to the failure_route_rul struct on success, NULL on failure.
  *
  * @see add_failure_route_to_tree()
  */
-int add_failure_route_rule(struct failure_route_tree_item * failure_tree, const str * prefix,
-		const str * host, const str * reply_code, flag_t flags, flag_t mask,
-		const int next_domain, const str * comment) {
-	struct failure_route_rule *shm_rr, *rr, *prev;
+struct failure_route_rule *add_failure_route_rule(struct failure_route_rule **frr_head,
+		const str * prefix, const str * host, const str * reply_code,
+		flag_t flags, flag_t mask, const int next_domain, const str * comment) {
+	struct failure_route_rule *shm_frr, *frr, *prev;
+	frr = prev = NULL;
 	
-	if ((shm_rr = shm_malloc(sizeof(struct failure_route_rule))) == NULL) {
+	if ((shm_frr = shm_malloc(sizeof(struct failure_route_rule))) == NULL) {
 		LM_ERR("out of shared memory\n");
-		return -1;
+		return NULL;
 	}
-	memset(shm_rr, 0, sizeof(struct failure_route_rule));
+	memset(shm_frr, 0, sizeof(struct failure_route_rule));
 	
-	if (shm_str_dup(&shm_rr->host, host) != 0) {
+	if (shm_str_dup(&shm_frr->host, host) != 0) {
 		goto mem_error;
 	}
 	
-	if (shm_str_dup(&shm_rr->reply_code, reply_code) != 0) {
+	if (shm_str_dup(&shm_frr->reply_code, reply_code) != 0) {
 		goto mem_error;
 	}
 	
-	shm_rr->flags = flags;
-	shm_rr->mask = mask;
-	shm_rr->next_domain = next_domain;
+	shm_frr->flags = flags;
+	shm_frr->mask = mask;
+	shm_frr->next_domain = next_domain;
 	
-	if (shm_str_dup(&shm_rr->comment, comment) != 0) {
+	if (shm_str_dup(&shm_frr->comment, comment) != 0) {
 		goto mem_error;
 	}
 	
 	/* before inserting into list, check priorities! */
-	rr=failure_tree->rule_list;
-	prev=NULL;
-	while ((rr != NULL) && (rule_prio_cmp(shm_rr, rr) > 0)) {
-		prev=rr;
-		rr=rr->next;
+	if (frr_head) {
+		frr=*frr_head;
+		prev=NULL;
+		while ((frr != NULL) && (failure_rule_prio_cmp(shm_frr, frr) > 0)) {
+			prev=frr;
+			frr=frr->next;
+		}
 	}
+
+	shm_frr->next = frr;
+
 	if(prev){
-		shm_rr->next = prev->next;
-		prev->next = shm_rr;
-	} else {
-		shm_rr->next = failure_tree->rule_list;
-		failure_tree->rule_list = shm_rr;
+		prev->next = shm_frr;
+	}
+	else {
+		if (frr_head) *frr_head=shm_frr;
 	}
-	
-	return 0;
 
+	return shm_frr;
+	
 mem_error:
 	LM_ERR("out of shared memory\n");
-	destroy_failure_route_rule(shm_rr);
-	return -1;
-}
-
-
-
-/**
- * Fixes the route rules by creating an array for accessing
- * route rules by hash index directly
- *
- * @param rd route data to be fixed
- *
- * @return 0 on success, -1 on failure
- */
-int rule_fixup(struct rewrite_data * rd) {
-	int i,j;
-	for (i=0; i<rd->tree_num; i++) {
-		for (j=0; j<rd->carriers[i]->tree_num; j++) {
-			if (rd->carriers[i]->trees[j] && rd->carriers[i]->trees[j]->tree) {
-				LM_INFO("fixing tree %.*s\n", rd->carriers[i]->trees[j]->name.len, rd->carriers[i]->trees[j]->name.s);
-				if (rule_fixup_recursor(rd->carriers[i]->trees[j]->tree) < 0) {
-					return -1;
-				}
-			} else {
-				LM_NOTICE("empty tree at [%i][%i]\n", i, j);
-			}
-		}
-	}
-	return 0;
+	destroy_failure_route_rule(shm_frr);
+	return NULL;
 }
 
 
 /**
- * Does the work for rule_fixup recursively.
- * First, it tries to set a pointer the rules with an existing hash index
- * at the marching array index. Afterward, remaining rules are populated
- * with incrementing hash indices.
- *
- * @param rt the route tree node to be fixed up
+ * Destroys failure route rule frr by freeing all its memory.
  *
- * @return 0 on success, -1 on failure
+ * @param rr route rule to be destroyed
  */
-static int rule_fixup_recursor(struct route_tree_item * rt) {
-	struct route_rule * rr;
-	struct route_flags * rf;
-	int i, p_dice, ret = 0;
-
-	for (rf=rt->flag_list; rf!=NULL; rf=rf->next) {
-		p_dice = 0;
-		if (rf->rule_list) {
-			rr = rf->rule_list;
-			rf->rule_num = 0;
-			while (rr) {
-				rf->rule_num++;
-				rf->dice_max += rr->prob * DICE_MAX;
-				rr = rr->next;
-			}
-			rr = rf->rule_list;
-			while (rr) {
-				rr->dice_to = (rr->prob * DICE_MAX) + p_dice;
-				p_dice = rr->dice_to;
-				rr = rr->next;
-			}
-			
-			if (rf->rule_num != rf->max_targets) {
-				LM_ERR("number of rules(%i) differs from max_targets(%i), maybe your config is wrong?\n", rf->rule_num, rf->max_targets);
-				return -1;
-			}
-			if(rf->rules) {
-				shm_free(rf->rules);
-				rf->rules = NULL;
-			}
-			if ((rf->rules = shm_malloc(sizeof(struct route_rule *) * rf->rule_num)) == NULL) {
-				LM_ERR("out of shared memory\n");
-				return -1;
-			}
-			memset(rf->rules, 0, sizeof(struct route_rule *) * rf->rule_num);
-			for (rr = rf->rule_list; rr; rr = rr->next) {
-				if (rr->hash_index) {
-					if (rr->hash_index > rf->rule_num) {
-						LM_ERR("too large hash index %i, max is %i\n", rr->hash_index, rf->rule_num);
-						shm_free(rf->rules);
-						return -1;
-					}
-					if (rf->rules[rr->hash_index - 1]) {
-						LM_ERR("duplicate hash index %i\n", rr->hash_index);
-						shm_free(rf->rules);
-						return -1;
-					}
-					rf->rules[rr->hash_index - 1] = rr;
-					LM_INFO("rule with host %.*s hash has hashindex %i.\n", rr->host.len, rr->host.s, rr->hash_index);
-				}
-			}
-			
-			rr = rf->rule_list;
-			i=0;
-			while (rr && i < rf->rule_num) {
-				if (!rr->hash_index) {
-					if (rf->rules[i]) {
-						i++;
-					} else {
-						rf->rules[i] = rr;
-						rr->hash_index = i + 1;
-						LM_INFO("hashless rule with host %.*s hash hash_index %i\n", rr->host.len, rr->host.s, i+1);
-						rr = rr->next;
-					}
-				} else {
-					rr = rr->next;
-				}
-			}
-			if (rr) {
-				LM_ERR("Could not populate rules: rr: %p\n", rr);
-				return -1;
-			}
-			for(i=0; i<rf->rule_num; i++){
-				ret += fixup_rule_backup(rf, rf->rules[i]);
-			}
-		}
+void destroy_failure_route_rule(struct failure_route_rule * frr) {
+	if (frr->host.s) {
+		shm_free(frr->host.s);
 	}
-
-	for (i=0; i<10; i++) {
-		if (rt->nodes[i]) {
-			ret += rule_fixup_recursor(rt->nodes[i]);
-		}
+	if (frr->comment.s) {
+		shm_free(frr->comment.s);
 	}
-
-	return ret;
-}
-
-static int fixup_rule_backup(struct route_flags * rf, struct route_rule * rr){
-	struct route_rule_p_list * rl;
-	if(!rr->status && rr->backup){
-		if((rr->backup->rr = find_rule_by_hash(rf, rr->backup->hash_index)) == NULL){
-			LM_ERR("didn't find backup route\n");
-			return -1;
-		}
+	if (frr->prefix.s) {
+		shm_free(frr->prefix.s);
 	}
-	rl = rr->backed_up;
-	while(rl){
-		if((rl->rr = find_rule_by_hash(rf, rl->hash_index)) == NULL){
-			LM_ERR("didn't find backed up route\n");
-			return -1;
-		}
-		rl = rl->next;
+	if (frr->reply_code.s) {
+		shm_free(frr->reply_code.s);
 	}
-	return 0;
+	shm_free(frr);
+	return;
 }
 
 
@@ -457,7 +440,8 @@ struct route_rule * find_rule_by_host(struct route_flags * rf, str * host){
 	return NULL;
 }
 
-int add_backup_route(struct route_rule * rule, struct route_rule * backup){
+
+int add_backup_rule(struct route_rule * rule, struct route_rule * backup){
 	struct route_rule_p_list * tmp = NULL;
 	if(!backup->status){
 		LM_ERR("desired backup route is inactive\n");
@@ -540,60 +524,3 @@ struct route_rule * find_auto_backup(struct route_flags * rf, struct route_rule
 	}
 	return NULL;
 }
-
-/**
- * Destroys route rule rr by freeing all its memory.
- *
- * @param rr route rule to be destroyed
- */
-void destroy_route_rule(struct route_rule * rr) {
-	struct route_rule_p_list * t_rl;
-	if (rr->host.s) {
-		shm_free(rr->host.s);
-	}
-	if (rr->local_prefix.s) {
-		shm_free(rr->local_prefix.s);
-	}
-	if (rr->local_suffix.s) {
-		shm_free(rr->local_suffix.s);
-	}
-	if (rr->comment.s) {
-		shm_free(rr->comment.s);
-	}
-	if (rr->prefix.s) {
-		shm_free(rr->prefix.s);
-	}
-	if(rr->backup){
-		shm_free(rr->backup);
-	}
-	while(rr->backed_up){
-		t_rl = rr->backed_up->next;
-		shm_free(rr->backed_up);
-		rr->backed_up = t_rl;
-	}
-	shm_free(rr);
-	return;
-}
-
-
-/**
- * Destroys failure route rule rr by freeing all its memory.
- *
- * @param rr route rule to be destroyed
- */
-void destroy_failure_route_rule(struct failure_route_rule * rr) {
-	if (rr->host.s) {
-		shm_free(rr->host.s);
-	}
-	if (rr->comment.s) {
-		shm_free(rr->comment.s);
-	}
-	if (rr->prefix.s) {
-		shm_free(rr->prefix.s);
-	}
-	if (rr->reply_code.s) {
-		shm_free(rr->reply_code.s);
-	}
-	shm_free(rr);
-	return;
-}

+ 98 - 76
modules/carrierroute/route.h → modules/carrierroute/cr_rule.h

@@ -21,21 +21,20 @@
  */
 
 /**
- * \file
+ * \file cr_rule.h
  * \brief Contains the functions to manage routing rule data.
  * \ingroup carrierroute
  * - Module; \ref carrierroute
  */
 
-#ifndef SP_ROUTE_ROUTE_H
-#define SP_ROUTE_ROUTE_H
-
-#include <sys/types.h>
+#ifndef CR_RULE_H
+#define CR_RULE_H
 
 #include "../../str.h"
-#include "../../locking.h"
 #include "../../flags.h"
 
+
+/*! list of rules */
 struct route_rule_p_list;
 
 /**
@@ -51,7 +50,7 @@ struct route_rule {
 	str local_prefix; /*!< the pefix to be attached to the new destination */
 	str local_suffix; /*!< the suffix to be appended to the localpart of the new destination */
 	str comment; /*!< A comment for the route rule */
-	str prefix; /*!< The prefix for which the route ist valid */
+	str prefix; /*!< The prefix for which the route is valid */
 	int status; /*!< The status of the route rule, only useful when using prime number hashing */
 	struct route_rule_p_list * backed_up; /*!< indicates if the rule is already backup route for another */
 	struct route_rule_p_list * backup; /*!< if not NULL, it points to a route rule which shall be used instead (only used if status is 0) */
@@ -59,21 +58,6 @@ struct route_rule {
 	struct route_rule * next; /*!< A pointer to the next route rule */
 };
 
-/**
- * Second stage of processing: Try to map the end of the user part of the URI
- * to a given suffix. Then rewrite with given parameters.
- */
-struct failure_route_rule {
-	str host; /*!< The new target host for the request */
-	str comment; /*!< A comment for the route rule */
-	str prefix; /*!< The prefix for which the route ist valid */
-	str reply_code;  /*!< The reply code for which the route ist valid */
-	int next_domain;  /*!< The domain id where to continue routing */
-	flag_t flags;  /*!< The flags for which the route ist valid */
-	flag_t mask;  /*!< The mask for the flags field */
-	struct failure_route_rule * next; /*!< A pointer to the next route rule */
-};
-
 /**
  * list of routing rules with hash index
  */
@@ -98,80 +82,118 @@ struct route_flags {
 };
 
 /**
- * First stage of processing: The actual route tree.
- * Take one digit after another off the user part of the uri until the pointer
- * for the digit is NULL.
- * Note: We can only handle digits right now, ie., no letters or symbols.
- * Seems okay since this is for PSTN routing.
+ * Second stage of processing: Try to map the end of the user part of the URI
+ * to a given suffix. Then rewrite with given parameters.
  */
-struct route_tree_item {
-	struct route_tree_item * nodes[10]; /*!< The Array points to child nodes if present */
-	struct route_flags *flag_list;
+struct failure_route_rule {
+	str host; /*!< The new target host for the request */
+	str comment; /*!< A comment for the route rule */
+	str prefix; /*!< The prefix for which the route ist valid */
+	str reply_code;  /*!< The reply code for which the route ist valid */
+	int next_domain;  /*!< The domain id where to continue routing */
+	flag_t flags;  /*!< The flags for which the route ist valid */
+	flag_t mask;  /*!< The mask for the flags field */
+	struct failure_route_rule * next; /*!< A pointer to the next route rule */
 };
 
+
 /**
- * First stage of processing: The actual route tree. Take one digit after
- * another of the user part of the uri until the pointer for the digit is NULL.
- * Note: We can only handle digits right now, ie., no letters or symbols.
- * Seems okay since this is for PSTN routing.
+ * Adds a route rule to rf
+ *
+ * @param rf the current route_flags struct
+ * @param prefix the whole scan prefix
+ * @param max_targets the number of targets
+ * @param prob the weight of the rule
+ * @param rewrite_hostpart the rewrite_host of the rule
+ * @param strip the number of digits to be stripped off userpart before prepending prefix
+ * @param rewrite_local_prefix the rewrite prefix
+ * @param rewrite_local_suffix the rewrite suffix
+ * @param status the status of the rule
+ * @param hash_index the hash index of the rule
+ * @param backup indicates if the route is backed up by another. only
+                 useful if status==0, if set, it is the hash value
+                 of another rule
+ * @param backed_up an NULL-termintated array of hash indices of the route
+                    for which this route is backup
+ * @param comment a comment for the route rule
+ *
+ * @return 0 on success, -1 on failure
+ *
+ * @see add_route_to_tree()
  */
-struct failure_route_tree_item {
-	struct failure_route_tree_item * nodes[10]; /*!< The Array points to child nodes if present */
-	struct failure_route_rule * rule_list; /*!< Each node MAY contain a failure rule list */
-};
+int add_route_rule(struct route_flags *rf, const str * prefix,
+		int max_targets, double prob, const str * rewrite_hostpart, int strip,
+		const str * rewrite_local_prefix, const str * rewrite_local_suffix,
+		int status, int hash_index, int backup, int * backed_up,
+		const str * comment);
+
 
 /**
- * The head of each route tree.
+ * Destroys route rule rr by freeing all its memory.
+ *
+ * @param rr route rule to be destroyed
  */
-struct route_tree {
-	int id; /*!< the numerical id of the routing tree */
-	str name; /*!< the name of the routing tree */
-	struct route_tree_item * tree; /*!< the root node of the routing tree */
-	struct failure_route_tree_item * failure_tree; /*!< the root node of the failure routing tree */
-};
+void destroy_route_rule(struct route_rule * rr);
+
 
 /**
- * The struct for a carrier routing tree.
+ * Try to find a matching route_flags struct in rt and return it, add it if not found.
+ *
+ * @param rf_head pointer to the head of the route flags list, might be changed during insert
+ * @param flags user defined flags
+ * @param mask mask for user defined flags
+ *
+ * @return pointer to the route_flags struct on success, NULL on failure.
+ *
  */
-struct carrier_tree {
-	struct route_tree ** trees; /*!< array of route trees */
-	size_t tree_num; /*!< number of routing trees/domains */
-	str name; /*!< name of the carrier */
-	int id; /*!< id of the carrier */
-	int index; /*!< index of the tree */
-};
+struct route_flags * add_route_flags(struct route_flags **rf_head, const flag_t flags, const flag_t mask);
+
 
 /**
- * contains all routing trees.
+ * Destroys route_flags in shared memory by freing all its memory.
+ *
+ * @param rf route_flags struct to be destroyed
  */
-struct rewrite_data {
-	struct carrier_tree ** carriers; /*!< array of carrier trees */
-	size_t tree_num; /*!< number of carrier trees */
-	int default_carrier_index;
-	int proc_cnt; /*!< a ref counter for the shm data */
-	gen_lock_t lock; /*!< lock for ref counter updates */
-};
+void destroy_route_flags(struct route_flags *rf);
+
 
 /**
- * used to map routing domain names to numbers for
- * faster access.
+ * Adds a failure route rule to rule list. prefix, host, reply_code, and comment
+ * must not contain NULL pointers.
+ *
+ * @param frr_head pointer to the head of the failure route rule list, might be changed during insert
+ * @param prefix the whole scan prefix
+ * @param host the hostname last tried
+ * @param reply_code the reply code 
+ * @param flags user defined flags
+ * @param mask mask for user defined flags
+ * @param next_domain continue routing with this domain
+ * @param comment a comment for the route rule
+ *
+ * @return pointer to the failure_route_rul struct on success, NULL on failure.
+ *
+ * @see add_failure_route_to_tree()
  */
-struct route_map {
-	str name; /*!< name of the routing domain */
-	int no; /*!< number of domain */
-	struct route_map * next; /*!< pointer to the next element */
-};
+struct failure_route_rule *add_failure_route_rule(struct failure_route_rule **frr_head,
+		const str * prefix, const str * host, const str * reply_code,
+		flag_t flags, flag_t mask, const int next_domain, const str * comment);
+
 
 /**
- * used to map carrier tree names to numbers for
- * faster access.
+ * Destroys failure route rule frr by freeing all its memory.
+ *
+ * @param rr route rule to be destroyed
  */
-struct tree_map {
-	str name; /*!< name of the carrier tree */
-	int id; /*!< id of the carrier tree */
-	int no; /*!< number of carrier array index for rewrite_data.trees  */
-	struct tree_map * next; /*!< pointer to the next element */
-};
+void destroy_failure_route_rule(struct failure_route_rule * frr);
+
+struct route_rule * find_rule_by_hash(struct route_flags * rf, int hash);
+
+struct route_rule * find_rule_by_host(struct route_flags * rf, str * host);
+
+int add_backup_rule(struct route_rule * rule, struct route_rule * backup);
+
+int remove_backed_up(struct route_rule * rule);
 
+struct route_rule * find_auto_backup(struct route_flags * rf, struct route_rule * rule);
 
 #endif

+ 0 - 108
modules/carrierroute/load_data.c

@@ -1,108 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2007-2008 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * \file load_data.c
- * \brief API to bind a data loading function.
- * \ingroup carrierroute
- * - Module; \ref carrierroute
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include "../../globals.h"
-#include "load_data.h"
-#include "route_db.h"
-#include "route_config.h"
-#include "carrierroute.h"
-#include "db_carrierroute.h"
-
-/**
- * Binds the loader function pointer api to the matching loader
- * function depending on source
- *
- * @param source the configuration data source, at the moment 
- * it can be db or file
- * @param api pointer to the api where the loader function is
- * bound to
- *
- * @return 0 means everything is ok, -1 means an error
- */
-int bind_data_loader(const char * source, route_data_load_func_t * api){
-	struct stat fs;
-	if(strcmp(source, "db") == 0){
-		LM_INFO("use database as configuration source");
-		*api = load_route_data;
-		mode = SP_ROUTE_MODE_DB;
-		if(carrierroute_db_init() < 0){
-			return -1;
-		}
-		// FIXME, move data initialization into child process
-		if(carrierroute_db_open() < 0){
-			return -1;
-		}
-		return 0;
-	}
-	if(strcmp(source, "file") == 0){
-		LM_INFO("use file as configuration source");
-		*api = load_config;
-		mode = SP_ROUTE_MODE_FILE;
-		if(stat(config_file, &fs) != 0){
-			LM_ERR("can't stat config file\n");
-			return -1;
-		}
-		if(fs.st_mode & S_IWOTH){
-			LM_WARN("insecure file permissions, routing data is world writeable");
-		}
-		if( !( fs.st_mode & S_IWOTH) &&
-			!((fs.st_mode & S_IWGRP) && (fs.st_gid == getegid())) &&
-			!((fs.st_mode & S_IWUSR) && (fs.st_uid == geteuid())) ) {
-				LM_ERR("config file not writable\n");
-				return -1;
-			}
-		return 0;
-	}
-	LM_ERR("could not bind configuration source <%s>", source);
-	return -1;
-}
-
-int data_main_finalize(void){
-	if(mode == SP_ROUTE_MODE_DB){
-		carrierroute_db_close();
-	}
-	return 0;
-}
-
-int data_child_init(void){
-	if(mode == SP_ROUTE_MODE_DB){
-		return carrierroute_db_open();
-	}
-	return 0;
-}
-
-void data_destroy(void){
-	if(mode == SP_ROUTE_MODE_DB){
-		carrierroute_db_close();
-	}
-	return;
-}

+ 0 - 56
modules/carrierroute/load_data.h

@@ -1,56 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2007-2008 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * \file load_data.h
- * \brief API to bind a data loading function.
- * \ingroup carrierroute
- * - Module; \ref carrierroute
- */
-
-#ifndef SP_ROUTE_LOAD_DATA_H
-#define SP_ROUTE_LOAD_DATA_H
-
-#include "route_tree.h"
-
-typedef int (*route_data_load_func_t)(struct rewrite_data * rd);
-
-/**
- * Binds the loader function pointer api to the matching loader
- * functionm depending on source
- *
- * @param source the configuration data source, at the moment 
- * it can be db or file
- * @param api pointer to the api where the loader function is
- * bound to
- *
- * @return 0 means everything is ok, -1 means an error
- */
-int bind_data_loader(const char * source, route_data_load_func_t * api);
-
-int data_main_finalize(void);
-
-int data_child_init(void);
-
-void data_destroy(void);
-
-#endif

+ 0 - 119
modules/carrierroute/route_rule.h

@@ -1,119 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2007-2008 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * \file route_rule.h
- * \brief Contains the functions to manage routing rule data.
- * \ingroup carrierroute
- * - Module; \ref carrierroute
- */
-
-#ifndef SP_ROUTE_ROUTE_RULE_H
-#define SP_ROUTE_ROUTE_RULE_H
-
-#include "route.h"
-
-/**
- * Adds a route rule to rf
- *
- * @param rf the current route_flags struct
- * @param prefix the whole scan prefix
- * @param max_targets the number of targets
- * @param prob the weight of the rule
- * @param rewrite_hostpart the rewrite_host of the rule
- * @param strip the number of digits to be stripped off userpart before prepending prefix
- * @param rewrite_local_prefix the rewrite prefix
- * @param rewrite_local_suffix the rewrite suffix
- * @param status the status of the rule
- * @param hash_index the hash index of the rule
- * @param backup indicates if the route is backed up by another. only
-                 useful if status==0, if set, it is the hash value
-                 of another rule
- * @param backed_up an NULL-termintated array of hash indices of the route
-                    for which this route is backup
- * @param comment a comment for the route rule
- *
- * @return 0 on success, -1 on failure
- *
- * @see add_route_to_tree()
- */
-int add_route_rule(struct route_flags *rf, const str * prefix,
-		int max_targets, double prob, const str * rewrite_hostpart, int strip,
-		const str * rewrite_local_prefix, const str * rewrite_local_suffix,
-		int status, int hash_index, int backup, int * backed_up,
-		const str * comment);
-
-/**
- * Adds a failure route rule to rt
- *
- * @param failure_tree the current route tree node
- * @param prefix the whole scan prefix
- * @param host the hostname last tried
- * @param reply_code the reply code 
- * @param flags user defined flags
- * @param mask mask for user defined flags
- * @param next_domain continue routing with this domain id
- * @param comment a comment for the route rule
- *
- * @return 0 on success, -1 on failure
- *
- * @see add_failure_route_to_tree()
- */
-int add_failure_route_rule(struct failure_route_tree_item * failure_tree,
-		const str * prefix, const str * host, const str * reply_code,
-		flag_t flags, flag_t mask, const int next_domain, const str * comment);
-
-/**
- * Destroys route rule rr by freeing all its memory.
- *
- * @param rr route rule to be destroyed
- */
-void destroy_route_rule(struct route_rule * rr);
-
-/**
- * Destroys failure route rule rr by freeing all its memory.
- *
- * @param rr route rule to be destroyed
- */
-void destroy_failure_route_rule(struct failure_route_rule * rr);
-
-/**
- * Fixes the route rules by creating an array for accessing
- * route rules by hash index directly
- *
- * @param rd route data to be fixed
- *
- * @return 0 on success, -1 on failure
- */
-int rule_fixup(struct rewrite_data * rd);
-
-struct route_rule * find_rule_by_hash(struct route_flags * rf, int hash);
-
-struct route_rule * find_rule_by_host(struct route_flags * rf, str * host);
-
-int add_backup_route(struct route_rule * rule, struct route_rule * backup);
-
-int remove_backed_up(struct route_rule * rule);
-
-struct route_rule * find_auto_backup(struct route_flags * rf, struct route_rule * rule);
-
-#endif

+ 0 - 518
modules/carrierroute/route_tree.c

@@ -1,518 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2007-2008 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * \file route_tree.c
- * \brief Contains the functions to manage routing tree data in a digital tree.
- * \ingroup carrierroute
- * - Module; \ref carrierroute
- */
-
-#include "../../mem/shm_mem.h"
-#include "../../mem/mem.h"
-#include "../../ut.h"
-#include "carrierroute.h"
-#include "route.h"
-#include "route_rule.h"
-#include "load_data.h"
-
-
-/**
- * holds the map between routing domain names and numbers
- */
-struct route_map ** script_routes = NULL;
-
-static void destroy_route_tree_item(struct route_tree_item *route_tree);
-
-static void destroy_failure_route_tree_item(struct failure_route_tree_item *route_tree_item);
-
-static struct route_tree_item * create_route_tree_item(void);
-
-static struct failure_route_tree_item * create_failure_route_tree_item(void);
-
-static int add_route_tree(struct carrier_tree * ct, struct route_tree * rt);
-
-
-/**
- * returns the routing tree for the given domain, if domain's tree
- * doesnt exist, it will be created. If the trees are completely
- * filled and a not existing domain shall be added, an error is
- * returned
- *
- * @param domain the domain name of desired routing tree
- * @param rd route data to be searched
- *
- * @return a pointer to the desired routing tree,
- * NULL on failure
- */
-struct route_tree * get_route_tree(const str * domain, struct carrier_tree * rd) {
-	int i, id;
-	struct route_tree * rt = NULL;
-	if (!rd) {
-		LM_ERR("NULL pointer in parameter\n");
-		return NULL;
-	}
-	for (i=0; i<rd->tree_num; i++) {
-		if (rd->trees[i] && rd->trees[i]->name.s) {
-			if (str_strcmp(&rd->trees[i]->name, domain) == 0) {
-				LM_INFO("found domain %.*s\n", rd->trees[i]->name.len, rd->trees[i]->name.s);
-				return rd->trees[i];
-			}
-		}
-	}
-	LM_INFO("domain %.*s not found, add it\n", domain->len, domain->s);
-	if ((id = add_domain(domain)) < 0) {
-		LM_ERR("could not add domain\n");
-		return NULL;
-	}
-	if ((rt = create_route_tree(domain, id)) == NULL) {
-		return NULL;
-	}
-	if ((rt->tree = create_route_tree_item()) == NULL) {
-		return NULL;
-	}
-	if ((rt->failure_tree = create_failure_route_tree_item()) == NULL) {
-		return NULL;
-	}
-	if (add_route_tree(rd, rt) < 0) {
-		LM_ERR("couldn't add route tree\n");
-		destroy_route_tree(rt);
-		return NULL;
-	}
-	LM_INFO("created route tree: %.*s, with id %i\n", rt->name.len, rt->name.s, rt->id);
-	return rt;
-}
-
-
-static int add_route_tree(struct carrier_tree * ct, struct route_tree * rt) {
-	int i;
-	LM_INFO("tree %.*s has %ld trees\n",
-			ct->name.len, ct->name.s, (long)ct->tree_num);
-	for (i=0; i<ct->tree_num; i++) {
-		LM_DBG("tree %p", ct->trees[i]);
-		if (ct->trees[i] == 0) {
-			ct->trees[i] = rt;
-			return 0;
-		}
-	}
-	return -1;
-}
-
-
-struct route_tree * get_route_tree_by_id(struct carrier_tree * ct, int id) {
-	int i;
-	LM_DBG("searching in carrier %.*s, id %d\n", ct->name.len, ct->name.s, ct->id);
-	for (i=0; i<ct->tree_num; i++) {
-		if (ct->trees[i]) {
-			LM_DBG("tree %.*s, domain %.*s : %i\n", ct->name.len, ct->name.s, ct->trees[i]->name.len, ct->trees[i]->name.s, ct->trees[i]->id);
-			if (ct->trees[i]->id == id) {
-				return ct->trees[i];
-			}
-		}
-	}
-	return NULL;
-}
-
-
-/**
- * creates a routing tree node in shared memory and sets it up.
- *
- * @return a pointer to the newly allocated route tree item, NULL
- * on error, in which case it LOGs an error message.
- */
-static struct route_tree_item * create_route_tree_item(void) {
-	struct route_tree_item *ret;
-
-	ret = (struct route_tree_item *)
-	      shm_malloc(sizeof(struct route_tree_item));
-	if (ret == NULL) {
-		LM_ERR("out of shared memory while building route tree.\n");
-	} else {
-		memset(ret, 0, sizeof(struct route_tree_item));
-	}
-	return ret;
-}
-
-
-/**
- * creates a routing tree node in shared memory and sets it up.
- *
- * @return a pointer to the newly allocated route tree item, NULL
- * on error, in which case it LOGs an error message.
- */
-static struct failure_route_tree_item * create_failure_route_tree_item(void) {
-	struct failure_route_tree_item *ret;
-	
-	ret = (struct failure_route_tree_item *)
-		shm_malloc(sizeof(struct failure_route_tree_item));
-	if (ret == NULL) {
-		LM_ERR("out of shared memory while building route tree.\n");
-	} else {
-		memset(ret, 0, sizeof(struct failure_route_tree_item));
-	}
-	return ret;
-}
-
-
-/**
- * Create a new route tree root in shared memory and set it up.
- *
- * @param domain the domain name of the route tree
- * @param id the domain id of the route tree
- *
- * @return a pointer to the newly allocated route tree or NULL on
- * error, in which case it LOGs an error message.
- */
-struct route_tree * create_route_tree(const str * domain, int id) {
-	struct route_tree * tmp;
-	if ((tmp = shm_malloc(sizeof(struct route_tree))) == NULL) {
-		LM_ERR("out of shared memory\n");
-		return NULL;
-	}
-	memset(tmp, 0, sizeof(struct route_tree));
-	if (shm_str_dup(&tmp->name, domain)!=0) {
-		LM_ERR("cannot duplicate string\n");
-		shm_free(tmp);
-		return NULL;
-	}
-	tmp->id = id;
-	return tmp;
-}
-
-
-/**
- * Try to find a matching route_flags struct in rt and return it, add it if not found.
- *
- * @param route_tree the current route tree node
- * @param flags user defined flags
- * @param mask mask for user defined flags
- *
- * @return the route_flags struct on success, NULL on failure.
- *
- */
-struct route_flags * add_route_flags(struct route_tree_item * route_tree, const flag_t flags, const flag_t mask)
-{
-	struct route_flags *shm_rf;
-	struct route_flags *prev_rf, *tmp_rf;
-	prev_rf = tmp_rf = NULL;
-
-	/* search for matching route_flags struct */
-	for (tmp_rf=route_tree->flag_list; tmp_rf!=NULL; tmp_rf=tmp_rf->next) {
-		if ((tmp_rf->flags == flags) && (tmp_rf->mask == mask)) return tmp_rf;
-	}
-
-	/* not found, insert one */
-	for (tmp_rf=route_tree->flag_list; tmp_rf!=NULL; tmp_rf=tmp_rf->next) {
-		if (tmp_rf->mask < mask) break;
-		prev_rf=tmp_rf;
-	}
-
-	if ((shm_rf = shm_malloc(sizeof(struct route_flags))) == NULL) {
-		LM_ERR("out of shared memory\n");
-		return NULL;
-	}
-	memset(shm_rf, 0, sizeof(struct route_flags));
-
-	shm_rf->flags=flags;
-	shm_rf->mask=mask;
-	shm_rf->next=tmp_rf;
-	
-	if (prev_rf) prev_rf->next = shm_rf;
-	else route_tree->flag_list = shm_rf;
-
-	return shm_rf;
-}
-
-
-/**
- * Adds the given route information to the route tree identified by
- * route_tree. scan_prefix identifies the number for which the information
- * is and the rewrite_* parameters define what to do in case of a match.
- * prob gives the probability with which this rule applies if there are
- * more than one for a given prefix.
- *
- * Note that this is a recursive function. It strips off digits from the
- * beginning of scan_prefix and calls itself.
- *
- * @param route_tree the current route tree node
- * @param scan_prefix the prefix at the current position
- * @param flags user defined flags
- * @param mask mask for user defined flags
- * @param full_prefix the whole scan prefix
- * @param max_targets the number of targets
- * @param prob the weight of the rule
- * @param rewrite_hostpart the rewrite_host of the rule
- * @param strip the number of digits to be stripped off userpart before prepending prefix
- * @param rewrite_local_prefix the rewrite prefix
- * @param rewrite_local_suffix the rewrite suffix
- * @param status the status of the rule
- * @param hash_index the hash index of the rule
- * @param backup indicates if the route is backed up by another. only 
-                 useful if status==0, if set, it is the hash value
-                 of another rule
-  * @param backed_up an -1-termintated array of hash indices of the route 
-                    for which this route is backup
- * @param comment a comment for the route rule
- *
- * @return 0 on success, -1 on failure
- *
- * @see add_route()
- */
-int add_route_to_tree(struct route_tree_item * route_tree, const str * scan_prefix,
-		flag_t flags, flag_t mask, const str * full_prefix, int max_targets, double prob,
-		const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix,
-		const str * rewrite_local_suffix, int status, int hash_index, 
-		int backup, int * backed_up, const str * comment) {
-	str next_prefix;
-	struct route_flags *rf;
-
-	if (scan_prefix->len == 0) {
-		rf = add_route_flags(route_tree, flags, mask);
-		if (rf==NULL) {
-			LM_ERR("cannot add route_flags struct to route_tree\n");
-			return -1;
-		}
-		return add_route_rule(rf, full_prefix, max_targets, prob, rewrite_hostpart, strip,
-		                      rewrite_local_prefix, rewrite_local_suffix, status, hash_index,
-		                      backup, backed_up, comment);
-	} else {
-		if (route_tree->nodes[*scan_prefix->s - '0'] == NULL) {
-			route_tree->nodes[*scan_prefix->s - '0']
-			= create_route_tree_item();
-			if (route_tree->nodes[*scan_prefix->s - '0'] == NULL) {
-				return -1;
-			}
-		}
-		next_prefix.s = scan_prefix->s + 1;
-		next_prefix.len = scan_prefix->len - 1;
-		return add_route_to_tree(route_tree->nodes[*scan_prefix->s - '0'],
-		                         &next_prefix, flags, mask, full_prefix, max_targets, prob,
-		                         rewrite_hostpart, strip, rewrite_local_prefix,
-		                         rewrite_local_suffix, status, hash_index,
-		                         backup, backed_up, comment);
-	}
-}
-
-
-/**
- * Adds the given failure route information to the failure route tree identified by
- * route_tree. scan_prefix, host, reply_code, flags identifies the number for which
- * the information is and the next_domain parameters defines where to continue
- * routing in case of a match.
- *
- * Note that this is a recursive function. It strips off digits from the
- * beginning of scan_prefix and calls itself.
- *
- * @param failure_tree the current route tree node
- * @param scan_prefix the prefix at the current position
- * @param full_prefix the whole scan prefix
- * @param host the hostname last tried
- * @param reply_code the reply code 
- * @param flags user defined flags
- * @param mask mask for user defined flags
- * @param next_domain continue routing with this domain id
- * @param comment a comment for the route rule
- *
- * @return 0 on success, -1 on failure
- *
- * @see add_route()
- */
-int add_failure_route_to_tree(struct failure_route_tree_item * failure_tree, const str * scan_prefix,
-		const str * full_prefix, const str * host, const str * reply_code,
-		const flag_t flags, const flag_t mask, const int next_domain, const str * comment) {
-	str next_prefix;
-
-	if (!scan_prefix || !scan_prefix->s || *scan_prefix->s == '\0') {
-		return add_failure_route_rule(failure_tree, full_prefix, host, reply_code, flags, mask, next_domain, comment);
-	} else {
-		if (failure_tree->nodes[*scan_prefix->s - '0'] == NULL) {
-			failure_tree->nodes[*scan_prefix->s - '0']
-				= create_failure_route_tree_item();
-			if (failure_tree->nodes[*scan_prefix->s - '0'] == NULL) {
-				return -1;
-			}
-		}
-		next_prefix.s = scan_prefix->s + 1;
-		next_prefix.len = scan_prefix->len - 1;
-		return add_failure_route_to_tree(failure_tree->nodes[*scan_prefix->s - '0'],
-																		 &next_prefix, full_prefix, host, reply_code,
-																		 flags, mask, next_domain, comment);
-	}
-}
-
-/**
- * Destroy the route map by freeing its memory.
- */
-void destroy_route_map(void) {
-	struct route_map * tmp, *tmp2;
-	if (script_routes) {
-		tmp = *script_routes;
-		while (tmp) {
-			tmp2 = tmp;
-			tmp = tmp->next;
-			shm_free(tmp2);
-		}
-		*script_routes = NULL;
-		shm_free(script_routes);
-		script_routes = NULL;
-	}
-}
-
-/**
- * Destroys route_tree by freeing all its memory.
- *
- * @param route_tree route tree to be destroyed
- */
-void destroy_route_tree(struct route_tree *route_tree) {
-	destroy_route_tree_item(route_tree->tree);
-	destroy_failure_route_tree_item(route_tree->failure_tree);
-	shm_free(route_tree->name.s);
-	shm_free(route_tree);
-	return;
-}
-
-/**
- * Destroys route_flags in shared memory by freing all its memory.
- *
- * @param rf route_flags struct to be destroyed
- */
-static void destroy_route_flags(struct route_flags *rf) {
-	struct route_rule *rs, *rs_tmp;
-
-	if (rf->rules) {
-		shm_free(rf->rules);
-	}
-	rs = rf->rule_list;
-	while (rs != NULL) {
-		rs_tmp = rs->next;
-		destroy_route_rule(rs);
-		rs = rs_tmp;
-	}
-	shm_free(rf);
-}
-
-/**
- * Destroys route_tree_item in shared memory by freing all its memory.
- *
- * @param route_tree_item route tree node to be destroyed
- */
-static void destroy_route_tree_item(struct route_tree_item *route_tree_item) {
-	int i;
-	struct route_flags *rf, *rf_tmp;
-
-	if (!route_tree_item) {
-		LM_ERR("NULL pointer in parameter\n");
-	}
-
-	for (i = 0; i < 10; ++i) {
-		if (route_tree_item->nodes[i] != NULL) {
-			destroy_route_tree_item(route_tree_item->nodes[i]);
-		}
-	}
-
-	rf=route_tree_item->flag_list;
-	while (rf!=NULL) {
-		rf_tmp = rf->next;
-		destroy_route_flags(rf);
-		rf = rf_tmp;
-	}
-}
-
-
-/**
- * Destroys failure_route_tree_item in shared memory by freing all its memory.
- *
- * @param route_tree_item route tree node to be destroyed
- */
-static void destroy_failure_route_tree_item(struct failure_route_tree_item *route_tree_item) {
-	int i;
-	struct failure_route_rule *rs, *rs_tmp;
-	
-	if (!route_tree_item) {
-		LM_ERR("NULL pointer in parameter\n");
-	}
-	
-	for (i = 0; i < 10; ++i) {
-		if (route_tree_item->nodes[i] != NULL) {
-			destroy_failure_route_tree_item(route_tree_item->nodes[i]);
-		}
-	}
-	rs = route_tree_item->rule_list;
-	while (rs != NULL) {
-		rs_tmp = rs->next;
-		destroy_failure_route_rule(rs);
-		rs = rs_tmp;
-	}
-	shm_free(route_tree_item);
-	return;
-}
-
-
-/**
- * Tries to add a domain to the domain map. If the given domain doesn't
- * exist, it is added. Otherwise, nothing happens.
- *
- * @param domain the domain to be added
- *
- * @return values: on succcess the numerical index of the given domain,
- * -1 on failure
- */
-int add_domain(const str * domain) {
-	struct route_map * tmp, * prev = NULL;
-	int id = 0;
-	if (!script_routes) {
-		if ((script_routes = shm_malloc(sizeof(struct route_map *))) == NULL) {
-			LM_ERR("out of shared memory\n");
-			return -1;
-		}
-		memset(script_routes, 0, sizeof(struct route_map *));
-	}
-
-	tmp = *script_routes;
-
-	while (tmp) {
-		if (str_strcmp(&tmp->name, domain) == 0) {
-			return tmp->no;
-		}
-		id = tmp->no + 1;
-		prev = tmp;
-		tmp = tmp->next;
-	}
-	if ((tmp = shm_malloc(sizeof(struct route_map))) == NULL) {
-		LM_ERR("out of shared memory\n");
-		return -1;
-	}
-	memset(tmp, 0, sizeof(struct route_map));
-	if (shm_str_dup(&tmp->name, domain) != 0) {
-		LM_ERR("cannot duplicate string\n");
-		shm_free(tmp);
-		return -1;
-	}
-	tmp->no = id;
-	if (!prev) {
-		*script_routes = tmp;
-	} else {
-		prev->next = tmp;
-	}
-	LM_INFO("domain %.*s has id %i\n", domain->len, domain->s, id);
-	return id;
-}

+ 0 - 144
modules/carrierroute/route_tree.h

@@ -1,144 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2007-2008 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * \file route_tree.h
- * \brief Contains the functions to manage routing tree data in a digital tree.
- * \ingroup carrierroute
- * - Module; \ref carrierroute
- */
-
-#ifndef SP_ROUTE_ROUTE_TREE_H
-#define SP_ROUTE_ROUTE_TREE_H
-
-#include "route.h"
-
-/**
- * Adds the given route information to the route tree identified by
- * route_tree. scan_prefix identifies the number for which the information
- * is and the rewrite_* parameters define what to do in case of a match.
- * prob gives the probability with which this rule applies if there are
- * more than one for a given prefix.
- *
- * Note that this is a recursive function. It strips of digits from the
- * beginning of scan_prefix and calls itself.
- *
- * @param route_tree the current route tree node
- * @param scan_prefix the prefix at the current position
- * @param flags user defined flags
- * @param mask mask for user defined flags
- * @param full_prefix the whole scan prefix
- * @param max_targets the number of targets
- * @param prob the weight of the rule
- * @param rewrite_hostpart the rewrite_host of the rule
- * @param strip the number of digits to be stripped off userpart before prepending prefix
- * @param rewrite_local_prefix the rewrite prefix
- * @param rewrite_local_suffix the rewrite suffix
- * @param status the status of the rule
- * @param hash_index the hash index of the rule
- * @param backup indicates if the route is backed up by another. only 
-                 useful if status==0, if set, it is the hash value
-                 of another rule
- * @param backed_up an -1-termintated array of hash indices of the route 
-                    for which this route is backup
- * @param comment a comment for the route rule
- *
- * @return 0 on success, -1 on failure
- *
- * @see add_route()
- */
-int add_route_to_tree(struct route_tree_item * route_tree, const str * scan_prefix,
-		flag_t flags, flag_t mask, const str * full_prefix, int max_targets, double prob,
-		const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix,
-		const str * rewrite_local_suffix, int status, int hash_index,
-		int backup, int * backed_up, const str * comment);
-
-/**
- * Adds the given failure route information to the failure route tree identified by
- * route_tree. scan_prefix, host, reply_code, flags identifies the number for which
- * the information is and the next_domain parameters defines where to continue
- * routing in case of a match.
- *
- * Note that this is a recursive function. It strips of digits from the
- * beginning of scan_prefix and calls itself.
- *
- * @param failure_tree the current route tree node
- * @param scan_prefix the prefix at the current position
- * @param full_prefix the whole scan prefix
- * @param host the hostname last tried
- * @param reply_code the reply code 
- * @param flags user defined flags
- * @param mask mask for user defined flags
- * @param next_domain continue routing with this domain id
- * @param comment a comment for the route rule
- *
- * @return 0 on success, -1 on failure
- *
- * @see add_route()
- */
-int add_failure_route_to_tree(struct failure_route_tree_item * failure_tree, const str * scan_prefix,
-		const str * full_prefix, const str * host, const str * reply_code,
-		const flag_t flags, const flag_t mask, const int next_domain, const str * comment);
-
-/**
- * Create a new route tree root in shared memory and set it up.
- *
- * @param domain the domain name of the route tree
- * @param id the domain id of the route tree
- *
- * @return a pointer to the newly allocated route tree or NULL on
- * error, in which case it LOGs an error message.
- */
-struct route_tree * create_route_tree(const str * domain, int id);
-
-
-
-/**
- * Tries to add a domain to the domain map. If the given domain doesn't
- * exist, it is added. Otherwise, nothing happens.
- *
- * @param domain the domain to be added
- *
- * @return values: on succcess the numerical index of the given domain,
- * -1 on failure
- */
-int add_domain(const str * domain);
-
-/**
- * returns the routing tree for the given domain, if domain's tree doesn't
- * exist, it will be created. If the trees are completely filled and a not
- * existing domain shall be added, an error is returned.
- *
- * @param domain the domain name of desired routing tree
- * @param rd route data to be searched
- *
- * @return a pointer to the desired routing tree, NULL on failure
- */
-struct route_tree * get_route_tree(const str * domain, struct carrier_tree * rd);
-
-struct route_tree * get_route_tree_by_id(struct carrier_tree * ct, int id);
-
-void destroy_route_tree(struct route_tree *route_tree);
-
-void destroy_route_map(void);
-
-#endif