Browse Source

- finish refactoring of carrierroute module
- replace O(n) matching logic for carrier and domain names with a efficient
binary search implementation
- use qsort and bsearch of glibc in most of the cases, where its possible
(basically all carrier/domain searches are O(log n) now, only when dynamic
strings for are used in the cfg, it needs to search the whole list)
- change carrier and domain names from string to integer, to allow the lookup
- instead of storing the carrier/domain name string in the memory structure,
a pointer to the name is used to save space
- get rid of this internal ID vs. external ID stuff, we use now only one
- rename the route_tree table to carrier_name
- add a new table domain_name, to hold the domain names (like route_tree tbl)
- adapt tests for the new or changed functionality
- extend documentation with a paragraph about the used matching logic
- Credits for this work belongs to Hardy Kahl, hardy dot kahl at 1und1 dot de
- fix a few errors in the postgres cr test, fix a few doxygen statements
- move some parts of log messages to DBG log level
- update documentation and database schemes


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

Henning Westerholt 17 năm trước cách đây
mục cha
commit
8efd99bc89

+ 128 - 52
modules/carrierroute/README

@@ -96,9 +96,12 @@ Henning Westerholt
         2.23. carrierfailureroute_mask_col (string)
         2.23. carrierfailureroute_mask_col (string)
         2.24. carrierfailureroute_next_domain_col (string)
         2.24. carrierfailureroute_next_domain_col (string)
         2.25. carrierfailureroute_description_col (string)
         2.25. carrierfailureroute_description_col (string)
-        2.26. route_tree_table (String)
-        2.27. route_tree_id_col (string)
-        2.28. route_tree_carrier_col (string)
+        2.26. carrier_name_table (String)
+        2.27. carrier_name_id_col (string)
+        2.28. carrier_name_carrier_col (string)
+        2.29. domain_name_table (String)
+        2.30. domain_name_id_col (string)
+        2.31. domain_name_domain_col (string)
 
 
    List of Examples
    List of Examples
 
 
@@ -127,7 +130,7 @@ Henning Westerholt
    1.21. Example database content - more complex
    1.21. Example database content - more complex
           carrierfailureroute table
           carrierfailureroute table
 
 
-   1.22. Example database content - route_tree table
+   1.22. Example database content - carrier_name table
    1.23. Necessary extensions for the user table
    1.23. Necessary extensions for the user table
    2.1. Set db_url parameter
    2.1. Set db_url parameter
    2.2. Set carrierroute_table parameter
    2.2. Set carrierroute_table parameter
@@ -154,9 +157,12 @@ Henning Westerholt
    2.23. Set carrierfailureroute_mask_col parameter
    2.23. Set carrierfailureroute_mask_col parameter
    2.24. Set carrierfailureroute_next_domain_col parameter
    2.24. Set carrierfailureroute_next_domain_col parameter
    2.25. Set carrierfailureroute_description_col parameter
    2.25. Set carrierfailureroute_description_col parameter
-   2.26. Set route_tree_table parameter
-   2.27. Set route_tree_id_col parameter
-   2.28. Set route_tree_carrier_col parameter
+   2.26. Set carrier_name_table parameter
+   2.27. Set carrier_name_id_col parameter
+   2.28. Set carrier_name_carrier_col parameter
+   2.29. Set domain_name_table parameter
+   2.30. Set domain_name_id_col parameter
+   2.31. Set domain_name_domain_col parameter
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -183,10 +189,13 @@ Chapter 1. Admin Guide
 
 
    This modules scales up to more than a few million users, and is
    This modules scales up to more than a few million users, and is
    able to handle more than several hundred thousand routing table
    able to handle more than several hundred thousand routing table
-   entries. It should be able to handle more, but this is not that
-   much tested at the moment. In load balancing scenarios the
-   usage of the config file mode is recommended, to avoid the
-   additional complexity that the database driven routing creates.
+   entries. We recieved reports of some setups that used more than
+   a million routing table entries. It also supports a large
+   number of carriers and domains which can be efficiently looked
+   up in most of the cases (see below for more informations). In
+   load balancing scenarios the usage of the config file mode is
+   recommended, to avoid the additional complexity that the
+   database driven routing creates.
 
 
    Routing tables can be reloaded and edited (in config file mode)
    Routing tables can be reloaded and edited (in config file mode)
    with the MI interface, the config file is updated according the
    with the MI interface, the config file is updated according the
@@ -201,6 +210,17 @@ Chapter 1. Admin Guide
    sections. For user based routing or LCR you should use the
    sections. For user based routing or LCR you should use the
    database mode.
    database mode.
 
 
+   In database mode, this module supports names and IDs for the
+   carriers and domains. When using IDs for the routing functions,
+   efficient binary search is used to find the needed data
+   structures. If you are using constant strings as parameter,
+   these will be converted to IDs during the fixup procedure.
+   However, if you are using AVPs as parameter and they contain
+   strings, this cannot be converted to IDs during the fixup
+   procedure. In that case linear search is performed to find the
+   needed data structures. So from a performance point of view it
+   is better to pass only IDs in AVPs to the routing functions.
+
    Basically this module could be used as an replacement for the
    Basically this module could be used as an replacement for the
    lcr and the dispatcher module, if you have certain performance,
    lcr and the dispatcher module, if you have certain performance,
    flexibility and/or integration requirements that these modules
    flexibility and/or integration requirements that these modules
@@ -800,8 +820,8 @@ domain register {
 | 9  |       2 |      0 | 49          |     0 |  0.5 | de-2.carrier2 |
 | 9  |       2 |      0 | 49          |     0 |  0.5 | de-2.carrier2 |
 | 10 |       2 |      0 |             |     0 |    1 | gw.carrier2   |
 | 10 |       2 |      0 |             |     0 |    1 | gw.carrier2   |
 | 11 |       2 |      1 | 49          |     0 |    1 | gw.carrier2   |
 | 11 |       2 |      1 | 49          |     0 |    1 | gw.carrier2   |
-| 12 |       3 |  start | 49          |     0 |    1 | de-gw.default |
-| 13 |       3 |  start |             |     0 |    1 | gw.default    |
+| 12 |       3 |      8 | 49          |     0 |    1 | de-gw.default |
+| 13 |       3 |      8 |             |     0 |    1 | gw.default    |
 +----+---------+--------+-------------+-------+------+---------------+
 +----+---------+--------+-------------+-------+------+---------------+
 ...
 ...
 
 
@@ -854,7 +874,7 @@ domain register {
 |  1 |      99 |           | 408        |    16 |   16 |             |
 |  1 |      99 |           | 408        |    16 |   16 |             |
 |  2 |      99 | gw1       | 404        |     0 |    0 | 100         |
 |  2 |      99 | gw1       | 404        |     0 |    0 | 100         |
 |  3 |      99 | gw2       | 50.        |     0 |    0 | 100         |
 |  3 |      99 | gw2       | 50.        |     0 |    0 | 100         |
-|  4 |      99 |           | 404        |  2048 | 2112 | asterisk-1  |
+|  4 |      99 |           | 404        |  2048 | 2112 | 101         |
 +----+---------+-----------+------------+-------+------+-------------+
 +----+---------+-----------+------------+-------+------+-------------+
 ...
 ...
 
 
@@ -872,7 +892,7 @@ domain register {
    holds domain entries for this routing rules. Not all table
    holds domain entries for this routing rules. Not all table
    colums are show here for brevity.
    colums are show here for brevity.
 
 
-   Example 1.22. Example database content - route_tree table
+   Example 1.22. Example database content - carrier_name table
 ...
 ...
 +----+----------+
 +----+----------+
 | id | carrier  |
 | id | carrier  |
@@ -926,7 +946,7 @@ modparam("carrierroute", "carrierroute_table", "carrierroute")
 
 
 2.3. carrierroute_id_col (string)
 2.3. carrierroute_id_col (string)
 
 
-   unique ID
+   Name of the column contains the unique identifier of a route.
 
 
    Example 2.3. Set carrierroute_id_col parameter
    Example 2.3. Set carrierroute_id_col parameter
 ...
 ...
@@ -944,8 +964,10 @@ modparam("carrierroute", "carrierroute_carrier_col", "carrier")
 
 
 2.5. carrierroute_domain_col (string)
 2.5. carrierroute_domain_col (string)
 
 
-   This column contains the route domain. Additional domains could
-   be used for example as fallback.
+   This column contains the routing domain id. You can define
+   several routing domains to have different routing rules. Maybe
+   you use domain 0 for normal routing and domain 1 if domain 0
+   failed.
 
 
    Example 2.5. Set carrierroute_domain_col parameter
    Example 2.5. Set carrierroute_domain_col parameter
 ...
 ...
@@ -954,8 +976,12 @@ modparam("carrierroute", "carrierroute_domain_col", "domain")
 
 
 2.6. carrierroute_scan_prefix_col (string)
 2.6. carrierroute_scan_prefix_col (string)
 
 
-   This column contains the scan prefix, which define the matching
-   portion of a phone number.
+   Name of column contains the scan prefixes. Scan prefixes define
+   the matching portion of a phone number, e.g. when we have the
+   scan prefixes 49721 and 49, the called number is 49721913740,
+   it matches 49721, because the longest match is taken. If no
+   prefix matches, the number is not routed. To prevent this, an
+   empty prefix value of could be added.
 
 
    Example 2.6. Set carrierroute_scan_prefix_col parameter
    Example 2.6. Set carrierroute_scan_prefix_col parameter
 ...
 ...
@@ -983,9 +1009,18 @@ modparam("carrierroute", "carrierroute_mask_col", "mask")
 
 
 2.9. carrierroute_prob_col (string)
 2.9. carrierroute_prob_col (string)
 
 
-   Name of column containing the probability. The probability
-   value is used to distribute the traffic between several
-   gateways.
+   Name of column contains the probability. The probability value
+   is used to distribute the traffic between several gateways.
+   Let's say 70 % of the traffic shall be routed to gateway A, the
+   other 30 % shall be routed to gateway B, we define a rule for
+   gateway A with a prob value of 0.7 and a rule for gateway B
+   with a prob value of 0.3. If all probabilities for a given
+   prefix, tree and domain don't add to 100%, the prefix values
+   will be adjusted according the given prob values. E.g. if three
+   hosts with prob values of 0.5, 0.5 and 0.4 are defined, the
+   resulting probabilities are 35.714, 35.714 and 28.571%. But its
+   better to choose meaningful values in the first place because
+   of clarity.
 
 
    Example 2.9. Set carrierroute_prob_col parameter
    Example 2.9. Set carrierroute_prob_col parameter
 ...
 ...
@@ -994,9 +1029,8 @@ modparam("carrierroute", "carrierroute_prob_col", "prob")
 
 
 2.10. carrierroute_strip_col (string)
 2.10. carrierroute_strip_col (string)
 
 
-   Name of the column containing the number of digits to be
-   stripped of the userpart of an URI before prepending
-   rewrite_prefix.
+   Name of the column contains the number of digits to be stripped
+   of the userpart of an URI before prepending rewrite_prefix.
 
 
    Example 2.10. Set carrierroute_strip_col parameter
    Example 2.10. Set carrierroute_strip_col parameter
 ...
 ...
@@ -1005,8 +1039,10 @@ modparam("carrierroute", "carrierroute_strip_col", "strip")
 
 
 2.11. carrierroute_rewrite_host_col (string)
 2.11. carrierroute_rewrite_host_col (string)
 
 
-   Name of column containing rewrite prefixes. Here you can define
-   a rewrite prefix for the localpart of the SIP URI.
+   Name of column contains the rewrite prefixes. Here you can
+   define a rewrite prefix for the localpart of the SIP URI. An
+   empty field represents a blacklist entry, anything else is put
+   as domain part into the Request URI of the SIP message.
 
 
    Example 2.11. Set carrierroute_rewrite_host_col parameter
    Example 2.11. Set carrierroute_rewrite_host_col parameter
 ...
 ...
@@ -1016,7 +1052,8 @@ modparam("carrierroute", "carrierroute_rewrite_host_col", "rewrite_host"
 
 
 2.12. carrierroute_rewrite_prefix_col (string)
 2.12. carrierroute_rewrite_prefix_col (string)
 
 
-   Rewrite prefix for the localpart of the SIP URI.
+   Name of column contains the rewrite prefixes. Here you can
+   define a rewrite prefix for the localpart of the SIP URI.
 
 
    Example 2.12. Set carrierroute_rewrite_prefix_col parameter
    Example 2.12. Set carrierroute_rewrite_prefix_col parameter
 ...
 ...
@@ -1026,7 +1063,8 @@ fix")
 
 
 2.13. carrierroute_rewrite_suffix_col (string)
 2.13. carrierroute_rewrite_suffix_col (string)
 
 
-   Rewrite suffix for the localpart of the SIP URI.
+   Name of column contains the rewrite suffixes. Here you can
+   define a rewrite suffix for the localpart of the SIP URI.
 
 
    Example 2.13. Set carrierroute_rewrite_suffix_col parameter
    Example 2.13. Set carrierroute_rewrite_suffix_col parameter
 ...
 ...
@@ -1037,7 +1075,8 @@ fix")
 2.14. carrierroute_description_col (string)
 2.14. carrierroute_description_col (string)
 
 
    A comment for the route entry, useful for larger routing
    A comment for the route entry, useful for larger routing
-   tables.
+   tables. The comment is also displayed by the fifo cmd
+   "cr_dump_routes".
 
 
    Example 2.14. Set carrierroute_description_col parameter
    Example 2.14. Set carrierroute_description_col parameter
 ...
 ...
@@ -1059,7 +1098,7 @@ te")
 
 
 2.16. carrierfailureroute_id_col (string)
 2.16. carrierfailureroute_id_col (string)
 
 
-   unique ID
+   This column contains the unique identifier of a failure route.
 
 
    Example 2.16. Set carrierfailureroute_id_col parameter
    Example 2.16. Set carrierfailureroute_id_col parameter
 ...
 ...
@@ -1077,8 +1116,10 @@ modparam("carrierroute", "carrierfailureroute_carrier_col", "carrier")
 
 
 2.18. carrierfailureroute_domain_col (string)
 2.18. carrierfailureroute_domain_col (string)
 
 
-   This column contains the route domain. Additional domains could
-   be used for example as fallback.
+   This column contains the routing domain id. You can define
+   several routing domains to have different routing rules. Maybe
+   you use domain 0 for normal routing and domain 1 if domain 0
+   failed.
 
 
    Example 2.18. Set carrierfailureroute_domain_col parameter
    Example 2.18. Set carrierfailureroute_domain_col parameter
 ...
 ...
@@ -1087,8 +1128,12 @@ modparam("carrierroute", "carrierfailureroute_domain_col", "domain")
 
 
 2.19. carrierfailureroute_scan_prefix_col (string)
 2.19. carrierfailureroute_scan_prefix_col (string)
 
 
-   This column contains the scan prefix, which define the matching
-   portion of a phone number.
+   Name of column contains the the scan prefixes. Scan prexies
+   define the matching portion of a phone number, e.g. we have the
+   scan prefixes 49721 and 49, the called number is 49721913740,
+   it matches 49721, because the longest match is taken. If no
+   prefix matches, the number is not failure routed. To prevent
+   this, an empty prefix value of could be added.
 
 
    Example 2.19. Set carrierfailureroute_scan_prefix_col parameter
    Example 2.19. Set carrierfailureroute_scan_prefix_col parameter
 ...
 ...
@@ -1098,8 +1143,8 @@ efix")
 
 
 2.20. carrierfailureroute_host_name_col (string)
 2.20. carrierfailureroute_host_name_col (string)
 
 
-   This column contains the routing destination used for rule
-   matching.
+   Name of the column containing the host name of the last routing
+   destination, using for rules matching.
 
 
    Example 2.20. Set carrierfailureroute_host_name_col parameter
    Example 2.20. Set carrierfailureroute_host_name_col parameter
 ...
 ...
@@ -1138,8 +1183,8 @@ modparam("carrierroute", "carrierfailureroute_mask_col", "mask")
 
 
 2.24. carrierfailureroute_next_domain_col (string)
 2.24. carrierfailureroute_next_domain_col (string)
 
 
-   This column contains the route domain that should be used for
-   the next routing attempt.
+   This column contains the route domain id that should be used
+   for the next routing attempt.
 
 
    Example 2.24. Set carrierfailureroute_next_domain_col parameter
    Example 2.24. Set carrierfailureroute_next_domain_col parameter
 ...
 ...
@@ -1158,31 +1203,62 @@ modparam("carrierroute", "carrierfailureroute_description_col", "descrip
 tion")
 tion")
 ...
 ...
 
 
-2.26. route_tree_table (String)
+2.26. carrier_name_table (String)
 
 
-   Name of the route_tree table for the carrierroute module.
+   Name of the carrier_name table for the carrierroute module.
 
 
-   Default value is "route_tree".
+   Default value is "carrier_name".
 
 
-   Example 2.26. Set route_tree_table parameter
+   Example 2.26. Set carrier_name_table parameter
 ...
 ...
-modparam("carrierroute", "route_tree_table", "route_tree")
+modparam("carrierroute", "carrier_name_table", "carrier_name")
 ...
 ...
 
 
-2.27. route_tree_id_col (string)
+2.27. carrier_name_id_col (string)
 
 
-   unique ID
+   Name of the column containing the unique identifier of a
+   carrier.
 
 
-   Example 2.27. Set route_tree_id_col parameter
+   Example 2.27. Set carrier_name_id_col parameter
 ...
 ...
-modparam("carrierroute", "route_tree_id_col", "id")
+modparam("carrierroute", "carrier_name_id_col", "id")
 ...
 ...
 
 
-2.28. route_tree_carrier_col (string)
+2.28. carrier_name_carrier_col (string)
 
 
    This column contains the carrier name.
    This column contains the carrier name.
 
 
-   Example 2.28. Set route_tree_carrier_col parameter
+   Example 2.28. Set carrier_name_carrier_col parameter
+...
+modparam("carrierroute", "carrier_name_carrier_col", "carrier")
+...
+
+2.29. domain_name_table (String)
+
+   Name of the domain_name table for the carrierroute module.
+
+   Default value is "domain_name".
+
+   Example 2.29. Set domain_name_table parameter
+...
+modparam("carrierroute", "domain_name_table", "domain_name")
+...
+
+2.30. domain_name_id_col (string)
+
+   Name of the column containing the unique identifier of a
+   domain.
+
+   Example 2.30. Set domain_name_id_col parameter
+...
+modparam("carrierroute", "domain_name_id_col", "id")
+...
+
+2.31. domain_name_domain_col (string)
+
+   This column contains the domain name.
+
+   Example 2.31. Set domain_name_domain_col parameter
 ...
 ...
-modparam("carrierroute", "route_tree_carrier_col", "carrier")
+modparam("carrierroute", "domain_name_domain_col", "domain")
 ...
 ...

+ 4 - 4
modules/carrierroute/carrierroute.c

@@ -98,10 +98,12 @@ static param_export_t params[]= {
 	carrierroute_DB_URL
 	carrierroute_DB_URL
 	carrierroute_DB_TABLE
 	carrierroute_DB_TABLE
 	carrierfailureroute_DB_TABLE
 	carrierfailureroute_DB_TABLE
-	route_tree_DB_TABLE
+	carrier_name_DB_TABLE
+	domain_name_DB_TABLE
 	carrierroute_DB_COLS
 	carrierroute_DB_COLS
 	carrierfailureroute_DB_COLS
 	carrierfailureroute_DB_COLS
-	route_tree_DB_COLS
+	carrier_name_DB_COLS
+	domain_name_DB_COLS
 	{"subscriber_table",       STR_PARAM, &subscriber_table.s },
 	{"subscriber_table",       STR_PARAM, &subscriber_table.s },
 	{"subscriber_user_col",    STR_PARAM, &subscriber_username_col.s },
 	{"subscriber_user_col",    STR_PARAM, &subscriber_username_col.s },
 	{"subscriber_domain_col",  STR_PARAM, &subscriber_domain_col.s },
 	{"subscriber_domain_col",  STR_PARAM, &subscriber_domain_col.s },
@@ -234,6 +236,4 @@ static void mod_destroy(void) {
 		carrierroute_db_close();
 		carrierroute_db_close();
 	}
 	}
 	destroy_route_data();
 	destroy_route_data();
-	destroy_domain_map();
-	destroy_carrier_map();
 }
 }

+ 71 - 385
modules/carrierroute/cr_carrier.c

@@ -27,201 +27,37 @@
  * - Module; \ref carrierroute
  * - Module; \ref carrierroute
  */
  */
 
 
+#include <stdlib.h>
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../ut.h"
 #include "../../ut.h"
 #include "cr_carrier.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"
 #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];
-}
+#include "cr_map.h"
 
 
 
 
 /**
 /**
  * Create a new carrier_data struct in shared memory and set it up.
  * 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 carrier_id id of carrier
- * @param index the index for that carrier
+ * @param carrier_name pointer to the name of the carrier
  * @param domains number of domains for that carrier
  * @param domains number of domains for that carrier
  *
  *
  * @return a pointer to the newly allocated carrier data or NULL on
  * @return a pointer to the newly allocated carrier data or NULL on
  * error, in which case it LOGs an error message.
  * 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 * create_carrier_data(int carrier_id, str *carrier_name, int domains) {
 	struct carrier_data_t * tmp;
 	struct carrier_data_t * tmp;
 	if ((tmp = shm_malloc(sizeof(struct carrier_data_t))) == NULL) {
 	if ((tmp = shm_malloc(sizeof(struct carrier_data_t))) == NULL) {
-		LM_ERR("out of shared memory\n");
+		SHM_MEM_ERROR;
 		return NULL;
 		return NULL;
 	}
 	}
 	memset(tmp, 0, sizeof(struct carrier_data_t));
 	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->id = carrier_id;
-	tmp->index = index;
+	tmp->name = carrier_name;
 	tmp->domain_num = domains;
 	tmp->domain_num = domains;
 	if(domains > 0){
 	if(domains > 0){
 		if ((tmp->domains = shm_malloc(sizeof(struct domain_data_t *) * domains)) == NULL) {
 		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_MEM_ERROR;
 			shm_free(tmp);
 			shm_free(tmp);
 			return NULL;
 			return NULL;
 		}
 		}
@@ -232,253 +68,103 @@ struct carrier_data_t * create_carrier_data(const str *carrier_name, int carrier
 
 
 
 
 /**
 /**
- * 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
+ * Destroys the given carrier and frees the used memory.
  *
  *
- * @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
+ * @param carrier_data the structure to be destroyed.
  */
  */
-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) {
+void destroy_carrier_data(struct carrier_data_t *carrier_data) {
 	int i;
 	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;
+	if (carrier_data) {
+		if (carrier_data->domains != NULL) {
+			for (i=0; i<carrier_data->domain_num; i++) {
+				destroy_domain_data(carrier_data->domains[i]);
+			}
+			shm_free(carrier_data->domains);
 		}
 		}
+		shm_free(carrier_data);
 	}
 	}
-	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
+ * Adds a domain_data struct to the given carrier data structure at the given index.
+ * Other etries are moved one position up to make space for the new one.
  *
  *
- * @param carrier_data carrier data to be searched
- * @param domain the name of desired domain
+ * @param carrier_data the carrier data struct where domain_data should be inserted
+ * @param domain_data the domain data struct to be inserted
+ * @param index the index where to insert the domain_data structure in the domain array
  *
  *
- * @return a pointer to the desired domain data, NULL on failure.
+ * @return 0 on success, -1 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;
+int add_domain_data(struct carrier_data_t * carrier_data, struct domain_data_t * domain_data, int index) {
+	LM_INFO("adding domain %d '%.*s' to carrier %d '%.*s'", domain_data->id, domain_data->name->len, domain_data->name->s, carrier_data->id, carrier_data->name->len, carrier_data->name->s);
+ 	LM_DBG("domain position %d (domain_num=%d, first_empty_domain=%d)", index, carrier_data->domain_num, carrier_data->first_empty_domain);
+
+	if ((index < 0) || (index > carrier_data->first_empty_domain)) {
+		LM_ERR("got invalid index during binary search\n");
+		return -1;
 	}
 	}
-	if (add_domain_data(carrier_data, domain_data) < 0) {
-		LM_ERR("couldn't add domain data\n");
-		destroy_domain_data(domain_data);
-		return NULL;
+		
+	if (carrier_data->first_empty_domain >= carrier_data->domain_num) {
+		LM_ERR("cannot add new domain '%.*s' into carrier '%.*s' - array already full\n", domain_data->name->len, domain_data->name->s, carrier_data->name->len, carrier_data->name->s);
+		return -1;
 	}
 	}
-	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];
-			}
-		}
+	if (index < carrier_data->first_empty_domain) {
+		/* move other entries one position up */
+		memmove(&carrier_data->domains[index+1], &carrier_data->domains[index], sizeof(struct domain_data_t *)*(carrier_data->first_empty_domain-index));
 	}
 	}
-	return NULL;
-}
-
+	carrier_data->domains[index] = domain_data;
+	carrier_data->first_empty_domain++;
 
 
-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;
 	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.
+ * Returns the domain data for the given id by doing a binary search.
+ * @note The domain array must be sorted!
  *
  *
- * @param node the prefix tree node to be fixed up
+ * @param carrier_data carrier data to be searched
+ * @param domain_id the id of desired domain
  *
  *
- * @return 0 on success, -1 on failure
+ * @return a pointer to the desired domain data, NULL if not found.
  */
  */
-static int rule_fixup_recursor(struct dtrie_node_t *node) {
-	struct route_rule * rr;
-	struct route_flags * rf;
-	int i, p_dice, ret = 0;
+struct domain_data_t * get_domain_data(struct carrier_data_t * carrier_data, int domain_id) {
+	struct domain_data_t **ret;
+	struct domain_data_t key;
+	struct domain_data_t *pkey = &key;
 
 
-	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]);
-		}
+	if (!carrier_data) {
+		LM_ERR("NULL pointer in parameter\n");
+		return NULL;
 	}
 	}
-
-	return ret;
+	key.id = domain_id;
+	ret = bsearch(&pkey, carrier_data->domains, carrier_data->domain_num, sizeof(carrier_data->domains[0]), compare_domain_data);
+	if (ret) return *ret;
+	return NULL;
 }
 }
 
 
 
 
 /**
 /**
- * Fixes the route rules by creating an array for accessing
- * route rules by hash index directly
- *
- * @param rd route data to be fixed
+ * Compares the IDs of two carrier data structures.
+ * A NULL pointer is always greater than any ID.
  *
  *
- * @return 0 on success, -1 on failure
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
  */
  */
-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);
-			}
+int compare_carrier_data(const void *v1, const void *v2) {
+  struct carrier_data_t *c1 = *(struct carrier_data_t * const *)v1;
+	struct carrier_data_t *c2 = *(struct carrier_data_t * const *)v2;
+	if (c1 == NULL) {
+		if (c2 == NULL) return 0;
+		else return 1;
+	}
+	else {
+		if (c2 == NULL) return -1;
+		else {
+			if (c1->id < c2->id) return -1;
+			else if (c1->id > c2->id) return 1;
+			else return 0;
 		}
 		}
 	}
 	}
-	return 0;
 }
 }

+ 24 - 111
modules/carrierroute/cr_carrier.h

@@ -32,160 +32,73 @@
 
 
 #include <sys/types.h>
 #include <sys/types.h>
 #include "../../str.h"
 #include "../../str.h"
-#include "../../locking.h"
-#include "../../flags.h"
-#include "cr_data.h"
 
 
 
 
 /**
 /**
  * The struct for a carrier.
  * The struct for a carrier.
  */
  */
 struct carrier_data_t {
 struct carrier_data_t {
+	int id; /*!< id of the carrier */
+	str * name; /*!< name of the carrier. This points to the name in carrier_map to avoid duplication. */
 	struct domain_data_t ** domains; /*!< array of routing domains */
 	struct domain_data_t ** domains; /*!< array of routing domains */
 	size_t domain_num; /*!< number 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 */
+	size_t first_empty_domain; /*!< the index of the first empty entry in domains */
 };
 };
 
 
 
 
 /**
 /**
  * Create a new carrier_data struct in shared memory and set it up.
  * 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 carrier_id id of carrier
- * @param index the index for that carrier
+ * @param carrier_name pointer to the name of the carrier
  * @param domains number of domains for that carrier
  * @param domains number of domains for that carrier
  *
  *
  * @return a pointer to the newly allocated carrier data or NULL on
  * @return a pointer to the newly allocated carrier data or NULL on
  * error, in which case it LOGs an error message.
  * 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);
-
-
-/**
- * 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 strip the number of digits to be stripped off userpart before prepending prefix
- * @param rewrite_hostpart the rewrite_host of the rule
- * @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 * create_carrier_data(int carrier_id, str *carrier_name, int domains);
 
 
 
 
 /**
 /**
- * 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 mask for user defined flags
- * @param next_domain continue routing with this domain
- * @param comment a comment for the failure route rule
+ * Destroys the given carrier and frees the used memory.
  *
  *
- * @return 0 on success, -1 on error in which case it LOGs a message.
+ * @param carrier_data the structure to be destroyed.
  */
  */
-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);
+void destroy_carrier_data(struct carrier_data_t *carrier_data);
 
 
 
 
 /**
 /**
- * adds a carrier_data struct for given carrier
+ * Adds a domain_data struct to the given carrier data structure at the given index.
+ * Other etries are moved one position up to make space for the new one.
  *
  *
- * @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
+ * @param carrier_data the carrier data struct where domain_data should be inserted
+ * @param domain_data the domain data struct to be inserted
+ * @param index the index where to insert the domain_data structure in the domain array
  *
  *
- * @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);
-
-
-/**
- * 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
- * @param rd route data to be searched
- *
- * @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);
-
-
-/**
- * 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.
+ * @return 0 on success, -1 on failure
  */
  */
-struct domain_data_t *get_domain_data_by_name(struct carrier_data_t * carrier_data, const str * domain);
+int add_domain_data(struct carrier_data_t * carrier_data, struct domain_data_t * domain_data, int index);
 
 
 
 
 /**
 /**
- * Returns the domain data for the given id.
+ * Returns the domain data for the given id by doing a binary search.
+ * @note The domain array must be sorted!
  *
  *
  * @param carrier_data carrier data to be searched
  * @param carrier_data carrier data to be searched
- * @param domain the name of desired domain
+ * @param domain_id the id of desired domain
  *
  *
  * @return a pointer to the desired domain data, NULL if not found.
  * @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);
+struct domain_data_t *get_domain_data(struct carrier_data_t * carrier_data, int domain_id);
 
 
 
 
 /**
 /**
- * Fixes the route rules by creating an array for accessing
- * route rules by hash index directly
+ * Compares the IDs of two carrier data structures.
+ * A NULL pointer is always greater than any ID.
  *
  *
- * @param rd route data to be fixed
- *
- * @return 0 on success, -1 on failure
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
  */
  */
-int rule_fixup(struct route_data_t * rd);
+int compare_carrier_data(const void *v1, const void *v2);
+
 
 
 #endif
 #endif

+ 67 - 8
modules/carrierroute/cr_config.c

@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../mem/mem.h"
 #include "../../mem/mem.h"
 #include "../../ut.h"
 #include "../../ut.h"
@@ -180,8 +181,10 @@ errout:
  */
  */
 int load_config(struct route_data_t * rd) {
 int load_config(struct route_data_t * rd) {
 	cfg_t * cfg = NULL;
 	cfg_t * cfg = NULL;
-	int n, m, o, i, j, k,l, status, hash_index, max_targets, strip;
+	int m, o, i, j, k,l, status, hash_index, max_targets, strip;
 	cfg_t * d, * p, * t;
 	cfg_t * d, * p, * t;
+	struct carrier_data_t * tmp_carrier_data;
+	int domain_id;
 	str domain, prefix, rewrite_prefix, rewrite_suffix, rewrite_host, comment;
 	str domain, prefix, rewrite_prefix, rewrite_suffix, rewrite_host, comment;
 	double prob;
 	double prob;
 	int * backed_up = NULL;
 	int * backed_up = NULL;
@@ -192,21 +195,68 @@ int load_config(struct route_data_t * rd) {
 		return -1;
 		return -1;
 	}
 	}
 
 
+	rd->carrier_num = 1;
+	rd->first_empty_carrier = 0;
+	rd->domain_num = cfg_size(cfg, "domain");
+
 	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *))) == NULL) {
 	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *))) == NULL) {
 		SHM_MEM_ERROR;
 		SHM_MEM_ERROR;
 		return -1;
 		return -1;
 	}
 	}
 	memset(rd->carriers, 0, sizeof(struct carrier_data_t *));
 	memset(rd->carriers, 0, sizeof(struct carrier_data_t *));
 
 
-	rd->carrier_num = 1;
-	n = cfg_size(cfg, "domain");
-	if (add_carrier_data(rd, &default_tree, 1, n) == NULL) {
+	/* Create carrier map */
+	if ((rd->carrier_map = shm_malloc(sizeof(struct name_map_t))) == NULL) {
+		SHM_MEM_ERROR;
+		return -1;
+	}
+	memset(rd->carrier_map, 0, sizeof(struct name_map_t));
+	rd->carrier_map[0].id = 1;
+	rd->carrier_map[0].name.len = default_tree.len;
+	rd->carrier_map[0].name.s = shm_malloc(rd->carrier_map[0].name.len);
+	if (rd->carrier_map[0].name.s == NULL) {
+		SHM_MEM_ERROR;
+		return -1;
+	}
+	memcpy(rd->carrier_map[0].name.s, default_tree.s, rd->carrier_map[0].name.len);
+
+	/* Create domain map */
+	if ((rd->domain_map = shm_malloc(sizeof(struct name_map_t) * rd->domain_num)) == NULL) {
+		SHM_MEM_ERROR;
+		return -1;
+	}
+	memset(rd->domain_map, 0, sizeof(struct name_map_t) * rd->domain_num);
+	for (i=0; i<rd->domain_num; i++) {
+		d = cfg_getnsec(cfg, "domain", i);
+		domain.s = (char *)cfg_title(d);
+		if (domain.s==NULL) domain.s="";
+		domain.len = strlen(domain.s);
+		rd->domain_map[i].id = i+1;
+		rd->domain_map[i].name.len = domain.len;
+		rd->domain_map[i].name.s = shm_malloc(rd->domain_map[i].name.len);
+		if (rd->domain_map[i].name.s == NULL) {
+			SHM_MEM_ERROR;
+			return -1;
+		}
+		memcpy(rd->domain_map[i].name.s, domain.s, rd->domain_map[i].name.len);
+	}
+	/* sort domain map by id for faster access */
+	qsort(rd->domain_map, rd->domain_num, sizeof(rd->domain_map[0]), compare_name_map);
+
+	/* Create and insert carrier data structure */
+	tmp_carrier_data = create_carrier_data(1, &rd->carrier_map[0].name, rd->domain_num);
+	if (tmp_carrier_data == NULL) {
+		LM_ERR("can't create new carrier\n");
+		return -1;
+	}
+	if (add_carrier_data(rd, tmp_carrier_data) < 0) {
 		LM_ERR("couldn't add carrier data\n");
 		LM_ERR("couldn't add carrier data\n");
+		destroy_carrier_data(tmp_carrier_data);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	memset(rd->carriers[0]->domains, 0, sizeof(struct domain_data_t *) * n);
-	for (i = 0; i < n; i++) {
+	/* add all routes */
+	for (i = 0; i < rd->domain_num; i++) {
 		d = cfg_getnsec(cfg, "domain", i);
 		d = cfg_getnsec(cfg, "domain", i);
 		domain.s = (char *)cfg_title(d);
 		domain.s = (char *)cfg_title(d);
 		if (domain.s==NULL) domain.s="";
 		if (domain.s==NULL) domain.s="";
@@ -264,9 +314,18 @@ int load_config(struct route_data_t * rd) {
 				}
 				}
 				backup = cfg_getint(t, "backup");
 				backup = cfg_getint(t, "backup");
 
 
+				domain_id = map_name2id(rd->domain_map, rd->domain_num, &domain);
+				if (domain_id < 0) {
+					LM_ERR("cannot find id for domain '%.*s'", domain.len, domain.s);
+					if (backed_up) {
+						pkg_free(backed_up);
+					}
+					return -1;
+				}
+
 				LM_INFO("adding route for prefix %.*s, to host %.*s, prob %f, backed up: %i, backup: %i\n",
 				LM_INFO("adding route for prefix %.*s, to host %.*s, prob %f, backed up: %i, backup: %i\n",
 				    prefix.len, prefix.s, rewrite_host.len, rewrite_host.s, prob, backed_up_size, backup);
 				    prefix.len, prefix.s, rewrite_host.len, rewrite_host.s, prob, backed_up_size, backup);
-				if (add_route(rd, 1, &domain, &prefix, 0, 0, max_targets, prob, &rewrite_host,
+				if (add_route(rd, 1, domain_id, &prefix, 0, 0, max_targets, prob, &rewrite_host,
 				              strip, &rewrite_prefix, &rewrite_suffix, status,
 				              strip, &rewrite_prefix, &rewrite_suffix, status,
 				              hash_index, backup, backed_up, &comment) < 0) {
 				              hash_index, backup, backed_up, &comment) < 0) {
 					LM_INFO("Error while adding route\n");
 					LM_INFO("Error while adding route\n");
@@ -386,7 +445,7 @@ int save_config(struct route_data_t * rd) {
 	i = 0;
 	i = 0;
 	if (rd->carrier_num>=1) {
 	if (rd->carrier_num>=1) {
 		for (j=0; j< rd->carriers[i]->domain_num; j++) {
 		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);
+			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) {
 			if (save_route_data_recursor(rd->carriers[i]->domains[j]->tree, outfile) < 0) {
 				goto errout;
 				goto errout;
 			}
 			}

+ 451 - 39
modules/carrierroute/cr_data.c

@@ -27,6 +27,7 @@
  * - Module; \ref carrierroute
  * - Module; \ref carrierroute
  */
  */
 
 
+#include <stdlib.h>
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "cr_data.h"
 #include "cr_data.h"
 #include "carrierroute.h"
 #include "carrierroute.h"
@@ -34,6 +35,7 @@
 #include "cr_db.h"
 #include "cr_db.h"
 #include "cr_carrier.h"
 #include "cr_carrier.h"
 #include "cr_domain.h"
 #include "cr_domain.h"
+#include "cr_rule.h"
 
 
 
 
 /**
 /**
@@ -42,46 +44,19 @@
 struct route_data_t ** global_data = NULL;
 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){
 static int carrier_data_fixup(struct route_data_t * rd){
 	int i;
 	int i;
 	str tmp;
 	str tmp;
 	tmp = default_tree;
 	tmp = default_tree;
-	rd->default_carrier_index = -1;
+	rd->default_carrier_id = -1;
 	for(i=0; i<rd->carrier_num; i++){
 	for(i=0; i<rd->carrier_num; i++){
 		if(rd->carriers[i]){
 		if(rd->carriers[i]){
-			if(str_strcmp(&(rd->carriers[i]->name), &tmp) == 0){
-				rd->default_carrier_index = i;
+			if(str_strcmp(rd->carriers[i]->name, &tmp) == 0){
+				rd->default_carrier_id = rd->carriers[i]->id;
 			}
 			}
 		}
 		}
 	}
 	}
-	if(rd->default_carrier_index < 0){
+	if(rd->default_carrier_id < 0){
 		LM_ERR("default_carrier not found\n");
 		LM_ERR("default_carrier not found\n");
 	}
 	}
 	return 0;
 	return 0;
@@ -98,7 +73,7 @@ int init_route_data(void) {
 		global_data = (struct route_data_t **)
 		global_data = (struct route_data_t **)
 		              shm_malloc(sizeof(struct route_data_t *));
 		              shm_malloc(sizeof(struct route_data_t *));
 		if (global_data == NULL) {
 		if (global_data == NULL) {
-			LM_ERR("Out of shared memory before even doing anything.\n");
+			SHM_MEM_ERROR;
 			return -1;
 			return -1;
 		}
 		}
 	}
 	}
@@ -140,11 +115,48 @@ void clear_route_data(struct route_data_t *data) {
 		}
 		}
 		shm_free(data->carriers);
 		shm_free(data->carriers);
 	}
 	}
+	if (data->carrier_map) {
+		for (i = 0; i < data->carrier_num; ++i) {
+			if (data->carrier_map[i].name.s) shm_free(data->carrier_map[i].name.s);
+		}
+		shm_free(data->carrier_map);
+	}
+	if (data->domain_map) {
+		for (i = 0; i < data->domain_num; ++i) {
+			if (data->domain_map[i].name.s) shm_free(data->domain_map[i].name.s);
+		}
+		shm_free(data->domain_map);
+	}
 	shm_free(data);
 	shm_free(data);
 	return;
 	return;
 }
 }
 
 
 
 
+/**
+ * adds a carrier_data struct for given carrier.
+ *
+ * @param rd route data to be searched
+ * @param carrier_data the carrier data struct to be inserted
+ *
+ * @return 0 on success, -1 on failure
+ */
+int add_carrier_data(struct route_data_t * rd, struct carrier_data_t * carrier_data) {
+	if (rd->first_empty_carrier >= rd->carrier_num) {
+		LM_ERR("carrier array already full");
+		return -1;
+	}
+
+	if (rd->carriers[rd->first_empty_carrier] != 0) {
+		LM_ERR("invalid pointer in first empty carrier entry");
+		return -1;
+	}
+
+	rd->carriers[rd->first_empty_carrier] = carrier_data;
+	rd->first_empty_carrier++;
+	return 0;
+}
+
+
 /**
 /**
  * Loads the routing data into the routing trees and sets the
  * Loads the routing data into the routing trees and sets the
  * global_data pointer to the new data. The old_data is removed
  * global_data pointer to the new data. The old_data is removed
@@ -158,7 +170,7 @@ int reload_route_data(void) {
 	int i;
 	int i;
 
 
 	if ((new_data = shm_malloc(sizeof(struct route_data_t))) == NULL) {
 	if ((new_data = shm_malloc(sizeof(struct route_data_t))) == NULL) {
-		LM_ERR("out of shared memory\n");
+		SHM_MEM_ERROR;
 		return -1;
 		return -1;
 	}
 	}
 	memset(new_data, 0, sizeof(struct route_data_t));
 	memset(new_data, 0, sizeof(struct route_data_t));
@@ -167,32 +179,40 @@ int reload_route_data(void) {
 	case CARRIERROUTE_MODE_DB:
 	case CARRIERROUTE_MODE_DB:
 		if (load_route_data_db(new_data) < 0) {
 		if (load_route_data_db(new_data) < 0) {
 			LM_ERR("could not load routing data\n");
 			LM_ERR("could not load routing data\n");
-			return -1;
+			goto errout;
 		}
 		}
 		break;
 		break;
 	case CARRIERROUTE_MODE_FILE:
 	case CARRIERROUTE_MODE_FILE:
 		if (load_config(new_data) < 0) {
 		if (load_config(new_data) < 0) {
 			LM_ERR("could not load routing data\n");
 			LM_ERR("could not load routing data\n");
-			return -1;
+			goto errout;
 		}
 		}
 		break;
 		break;
 	default:
 	default:
 		LM_ERR("invalid mode");
 		LM_ERR("invalid mode");
-		return -1;
+		goto errout;
 	}
 	}
 	if (new_data == NULL) {
 	if (new_data == NULL) {
 		LM_ERR("loading routing data failed (NULL pointer)");
 		LM_ERR("loading routing data failed (NULL pointer)");
-		return -1;
+		goto errout;
+	}
+
+	/* sort carriers by id for faster access */
+	qsort(new_data->carriers, new_data->carrier_num, sizeof(new_data->carriers[0]), compare_carrier_data);
+
+	/* sort domains by id for faster access */
+	for (i=0; i<new_data->carrier_num; i++) {
+		qsort(new_data->carriers[i]->domains, new_data->carriers[i]->domain_num, sizeof(new_data->carriers[i]->domains[0]), compare_domain_data);
 	}
 	}
 
 
 	if (rule_fixup(new_data) < 0) {
 	if (rule_fixup(new_data) < 0) {
 		LM_ERR("could not fixup rules\n");
 		LM_ERR("could not fixup rules\n");
-		return -1;
+		goto errout;
 	}
 	}
 
 
 	if (carrier_data_fixup(new_data) < 0){
 	if (carrier_data_fixup(new_data) < 0){
 		LM_ERR("could not fixup trees\n");
 		LM_ERR("could not fixup trees\n");
-		return -1;
+		goto errout;
 	}
 	}
 
 
 	new_data->proc_cnt = 0;
 	new_data->proc_cnt = 0;
@@ -211,6 +231,10 @@ int reload_route_data(void) {
 		clear_route_data(old_data);
 		clear_route_data(old_data);
 	}
 	}
 	return 0;
 	return 0;
+
+ errout:
+	clear_route_data(new_data);
+	return -1;
 }
 }
 
 
 
 
@@ -251,3 +275,391 @@ void release_data(struct route_data_t *data) {
 	--data->proc_cnt;
 	--data->proc_cnt;
 	lock_release(&data->lock);
 	lock_release(&data->lock);
 }
 }
+
+
+/**
+ * Returns the carrier data for the given id by doing a binary search.
+ * @note The carrier array must be sorted!
+ *
+ * @param rd route data to be searched
+ * @param carrier_id the id of the desired carrier
+ *
+ * @return a pointer to the desired carrier data, NULL if not found.
+ */
+struct carrier_data_t *get_carrier_data(struct route_data_t * rd, int carrier_id) {
+	struct carrier_data_t **ret;
+	struct carrier_data_t key;
+	struct carrier_data_t *pkey = &key;
+
+	if (!rd) {
+		LM_ERR("NULL pointer in parameter\n");
+		return NULL;
+	}
+	key.id = carrier_id;
+	ret = bsearch(&pkey, rd->carriers, rd->carrier_num, sizeof(rd->carriers[0]), compare_carrier_data);
+	if (ret) return *ret;
+	return NULL;
+}
+
+
+typedef int (*cmpfunc_t)(const void *v1, const void *v2);
+
+
+/**
+ * Implements a binary search algorithm using the function cmpfunc
+ * for comparison.
+ *
+ * @param base pointer to the beginning of the array
+ * @param len length of array
+ * @param elemsize size of array elements
+ * @param key pointer to the key we are looking for
+ * @param cmpfunc function to be used for comparison
+ * @param index  If index is not NULL it is set to:
+ *     -1 if an error occured,
+ *     the index of the first entry equal to v
+ *     or the index of the first entry greater than v in the case v was not found.
+ *   Be careful: The index returned can be greater than the length of the array!
+ *
+ * @return -1 on error, 0 if the value was not found, 1 if it was found.
+ */
+static int binary_search(void *base, unsigned int len, int elemsize, void *key, cmpfunc_t cmpfunc, int *index) {
+	int left, right, mid;
+
+	if (index) *index=-1;
+	if (!base) {
+		LM_ERR("NULL pointer in parameter\n");
+		return -1;
+	}
+	if (len == 0) {
+		if (index) *index=0;
+		return 0;
+	}
+
+	left=0;
+	right=len-1;
+	if (cmpfunc(base+elemsize*left, key) > 0) {
+		LM_DBG("not found (out of left bound)\n");
+		if (index) *index=0; /* not found, must be inserted at the beginning of array */
+		return 0;
+	}
+	if (cmpfunc(base+elemsize*right, key) < 0) {
+		LM_DBG("not found (out of right bound)\n");
+		if (index) *index=len; /* not found, must be inserted at the end of array */
+		return 0;
+	}
+
+	while (left < right) {
+		mid = left + ((right - left) / 2);
+		if (cmpfunc(base+elemsize*mid, key) < 0) left = mid + 1;
+		else right = mid;
+	}
+
+	/* left == right here! */
+	if (index) *index=left;
+	if (cmpfunc(base+elemsize*left, key) == 0) return 1;
+	else return 0;
+}
+
+
+/**
+ * Returns the domain data for the given id by doing a binary search.
+ * If not found, a new domain data structure is added.
+ *
+ * @param rd route data to used for name - id mapping
+ * @param carrier_data carrier data to be searched
+ * @param domain_id the id of desired domain
+ *
+ * @return a pointer to the desired domain data, NULL on error.
+ */
+static struct domain_data_t * get_domain_data_or_add(struct route_data_t * rd, struct carrier_data_t * carrier_data, int domain_id) {
+	struct domain_data_t key;
+	struct domain_data_t *pkey = &key;
+	struct domain_data_t *domain_data = NULL;
+	str *domain_name;
+	int i;
+	int res;
+
+	if ((!rd) || (!carrier_data)) {
+		LM_ERR("NULL pointer in parameter\n");
+		return NULL;
+	}
+
+	key.id = domain_id;
+	res = binary_search(carrier_data->domains, carrier_data->first_empty_domain, sizeof(struct domain_data_t *), &pkey, compare_domain_data, &i);
+	if (res<0) {
+		LM_ERR("error while searching for domain_id %d\n", domain_id);
+		return NULL;
+	}
+	else if (res>0) {
+		/* found domain id */
+		domain_data = carrier_data->domains[i];
+	}
+	else {
+		/* did not find domain id - insert new entry! */
+		if ((domain_name = map_id2name(rd->domain_map, rd->domain_num, domain_id)) == NULL) {
+			LM_ERR("could not find domain name for id %d\n", domain_id);
+			return NULL;
+		}
+		if ((domain_data = create_domain_data(domain_id, domain_name)) == NULL) {
+			LM_ERR("could not create new domain data\n");
+			return NULL;
+		}
+
+		/* keep the array sorted! */
+		if (add_domain_data(carrier_data, domain_data, i) < 0) {
+			LM_ERR("could not add domain data\n");
+			destroy_domain_data(domain_data);
+			return NULL;
+		}
+		LM_INFO("added domain %d '%.*s' to carrier %d '%.*s'", domain_id, domain_name->len, domain_name->s, carrier_data->id, carrier_data->name->len, carrier_data->name->s);
+	}
+
+	return domain_data;
+}
+
+
+/**
+ * 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_id the routing domain id 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,
+		int domain_id, 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 for carrier id %d\n", carrier_id);
+		return -1;
+	}
+
+	if ((domain_data = get_domain_data_or_add(rd, carrier_data, domain_id)) == NULL) {
+		LM_ERR("could not retrieve domain data\n");
+		return -1;
+	}
+
+	LM_INFO("found carrier and domain, now adding route\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_id the routing domain id 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_id continue routing with this domain id
+ * @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, int domain_id,
+		const str * scan_prefix, const str * host, const str * reply_code,
+		flag_t flags, flag_t mask, int next_domain_id, const str * comment) {
+	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_or_add(rd, carrier_data, domain_id)) == NULL) {
+		LM_ERR("could not retrieve domain data\n");
+		return -1;
+	}
+
+	LM_INFO("found carrier and domain, now adding failure route\n");
+	return add_failure_route_to_tree(domain_data->failure_tree, scan_prefix, scan_prefix, host, reply_code,
+			flags, mask, next_domain_id, comment);
+}
+
+
+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) {
+				SHM_MEM_ERROR;
+				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;
+}

+ 103 - 1
modules/carrierroute/cr_data.h

@@ -32,15 +32,21 @@
 
 
 #include <sys/types.h>
 #include <sys/types.h>
 #include "../../locking.h"
 #include "../../locking.h"
+#include "../../flags.h"
+#include "cr_map.h"
 
 
 
 
 /**
 /**
  * contains all routing data.
  * contains all routing data.
  */
  */
 struct route_data_t {
 struct route_data_t {
+	struct name_map_t * carrier_map; /*!< holds the map between carrier names and numbers */
+	struct name_map_t * domain_map; /*!< holds the map between domain names and numbers */
 	struct carrier_data_t ** carriers; /*!< array of carriers */
 	struct carrier_data_t ** carriers; /*!< array of carriers */
 	size_t carrier_num; /*!< number of carriers */
 	size_t carrier_num; /*!< number of carriers */
-	int default_carrier_index;
+	size_t first_empty_carrier; /*!< the index of the first empty entry in carriers */
+	size_t domain_num; /*!< total number of different domains */
+	int default_carrier_id;
 	int proc_cnt; /*!< a ref counter for the shm data */
 	int proc_cnt; /*!< a ref counter for the shm data */
 	gen_lock_t lock; /*!< lock for ref counter updates */
 	gen_lock_t lock; /*!< lock for ref counter updates */
 };
 };
@@ -67,6 +73,17 @@ void destroy_route_data(void);
 void clear_route_data(struct route_data_t *data);
 void clear_route_data(struct route_data_t *data);
 
 
 
 
+/**
+ * adds a carrier_data struct for given carrier
+ *
+ * @param rd route data to be searched
+ * @param carrier_data the carrier data struct to be inserted
+ *
+ * @return 0 on success, -1 on failure
+ */
+int add_carrier_data(struct route_data_t * rd, struct carrier_data_t * carrier_data);
+
+
 /**
 /**
  * Loads the routing data into the routing trees and sets the
  * Loads the routing data into the routing trees and sets the
  * global_data pointer to the new data. The old_data is removed
  * global_data pointer to the new data. The old_data is removed
@@ -94,4 +111,89 @@ struct route_data_t * get_data(void);
  */
  */
 void release_data(struct route_data_t *data);
 void release_data(struct route_data_t *data);
 
 
+
+/**
+ * Returns the carrier data for the given id by doing a binary search.
+ * @note The carrier array must be sorted!
+ *
+ * @param rd route data to be searched
+ * @param carrier_id the id of the desired carrier
+ *
+ * @return a pointer to the desired carrier data, NULL if not found.
+ */
+struct carrier_data_t *get_carrier_data(struct route_data_t * rd, int carrier_id);
+
+
+/**
+ * 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_id the routing domain id 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 strip the number of digits to be stripped off userpart before prepending prefix
+ * @param rewrite_hostpart the rewrite_host of the rule
+ * @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,
+		int domain_id, 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 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_id the routing domain id 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_id continue routing with this domain id
+ * @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, int domain_id,
+		const str * scan_prefix, const str * host, const str * reply_code,
+		flag_t flags, flag_t mask, int next_domain_id, const str * comment);
+
+
+/**
+ * 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);
+
+
 #endif
 #endif

+ 140 - 103
modules/carrierroute/cr_db.c

@@ -34,20 +34,10 @@
 #include "cr_db.h"
 #include "cr_db.h"
 #include "cr_carrier.h"
 #include "cr_carrier.h"
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 
 #define QUERY_LEN 2048
 #define QUERY_LEN 2048
 
 
-/*! carrier list */
-struct carrier {
-	int id;
-	char * name;
-	struct carrier * next;
-};
-
-static int store_carriers(struct carrier ** start);
-
-static void destroy_carriers(struct carrier * start);
-
 static char query[QUERY_LEN];
 static char query[QUERY_LEN];
 
 
 str * columns[COLUMN_NUM] = { &carrierroute_id_col, &carrierroute_carrier_col,
 str * columns[COLUMN_NUM] = { &carrierroute_id_col, &carrierroute_carrier_col,
@@ -63,9 +53,14 @@ str * columns[COLUMN_NUM] = { &carrierroute_id_col, &carrierroute_carrier_col,
 	&carrierroute_description_col
 	&carrierroute_description_col
 };
 };
 
 
-str * carrier_columns[CARRIER_COLUMN_NUM] = {
-	&route_tree_id_col,
-	&route_tree_carrier_col
+str * carrier_name_columns[CARRIER_NAME_COLUMN_NUM] = {
+	&carrier_name_id_col,
+	&carrier_name_carrier_col
+};
+
+str * domain_name_columns[DOMAIN_NAME_COLUMN_NUM] = {
+	&domain_name_id_col,
+	&domain_name_domain_col
 };
 };
 
 
 str * failure_columns[FAILURE_COLUMN_NUM] = {
 str * failure_columns[FAILURE_COLUMN_NUM] = {
@@ -82,6 +77,108 @@ str * failure_columns[FAILURE_COLUMN_NUM] = {
 };
 };
 
 
 
 
+static int load_carrier_map(struct route_data_t *rd) {
+	db_res_t * res = NULL;
+	int i, count;
+	if(!rd){
+		LM_ERR("invalid parameter\n");
+		return -1;
+	}
+	if (carrierroute_dbf.use_table(carrierroute_dbh, &carrier_name_table) < 0) {
+		LM_ERR("couldn't use table\n");
+		return -1;
+	}
+
+	if (carrierroute_dbf.query(carrierroute_dbh, 0, 0, 0, (db_key_t *)carrier_name_columns, 0, CARRIER_NAME_COLUMN_NUM, 0, &res) < 0) {
+		LM_ERR("couldn't query table\n");
+		return -1;
+	}
+
+	count = RES_ROW_N(res);
+
+	rd->carrier_map = shm_malloc(sizeof(struct name_map_t) * count);
+	if (rd->carrier_map == NULL) {
+		SHM_MEM_ERROR;
+		carrierroute_dbf.free_result(carrierroute_dbh, res);
+		return -1;
+	}
+	memset(rd->carrier_map, 0, sizeof(struct name_map_t) * count);
+
+	for (i=0; i<count; i++) {
+		rd->carrier_map[i].id = res->rows[i].values[CARRIER_NAME_ID_COL].val.int_val;
+		rd->carrier_map[i].name.len = strlen(res->rows[i].values[CARRIER_NAME_NAME_COL].val.string_val);
+		rd->carrier_map[i].name.s = shm_malloc(rd->carrier_map[i].name.len);
+		if (rd->carrier_map[i].name.s == NULL) {
+			SHM_MEM_ERROR;
+			carrierroute_dbf.free_result(carrierroute_dbh, res);
+			shm_free(rd->carrier_map);
+			rd->carrier_map = NULL;
+			return -1;
+		}
+		memcpy(rd->carrier_map[i].name.s, res->rows[i].values[CARRIER_NAME_NAME_COL].val.string_val, rd->carrier_map[i].name.len);
+	}
+
+	/* sort carrier map by id for faster access */
+	qsort(rd->carrier_map, count, sizeof(rd->carrier_map[0]), compare_name_map);
+
+	carrierroute_dbf.free_result(carrierroute_dbh, res);
+	return count;
+}
+
+
+
+
+static int load_domain_map(struct route_data_t *rd) {
+	db_res_t * res = NULL;
+	int i, count;
+	if(!rd){
+		LM_ERR("invalid parameter\n");
+		return -1;
+	}
+	if (carrierroute_dbf.use_table(carrierroute_dbh, &domain_name_table) < 0) {
+		LM_ERR("couldn't use table\n");
+		return -1;
+	}
+
+	if (carrierroute_dbf.query(carrierroute_dbh, 0, 0, 0, (db_key_t *)domain_name_columns, 0, DOMAIN_NAME_COLUMN_NUM, 0, &res) < 0) {
+		LM_ERR("couldn't query table\n");
+		return -1;
+	}
+
+	count = RES_ROW_N(res);
+
+	rd->domain_map = shm_malloc(sizeof(struct name_map_t) * count);
+	if (rd->domain_map == NULL) {
+		SHM_MEM_ERROR;
+		carrierroute_dbf.free_result(carrierroute_dbh, res);
+		return -1;
+	}
+	memset(rd->domain_map, 0, sizeof(struct name_map_t) * count);
+
+	for (i=0; i<count; i++) {
+		rd->domain_map[i].id = res->rows[i].values[DOMAIN_NAME_ID_COL].val.int_val;
+		rd->domain_map[i].name.len = strlen(res->rows[i].values[DOMAIN_NAME_NAME_COL].val.string_val);
+		rd->domain_map[i].name.s = shm_malloc(rd->domain_map[i].name.len);
+		if (rd->domain_map[i].name.s == NULL) {
+			SHM_MEM_ERROR;
+			carrierroute_dbf.free_result(carrierroute_dbh, res);
+			shm_free(rd->domain_map);
+			rd->domain_map = NULL;
+			return -1;
+		}
+		memcpy(rd->domain_map[i].name.s, res->rows[i].values[DOMAIN_NAME_NAME_COL].val.string_val, rd->domain_map[i].name.len);
+	}
+
+	/* sort domain map by id for faster access */
+	qsort(rd->domain_map, count, sizeof(rd->domain_map[0]), compare_name_map);
+
+	carrierroute_dbf.free_result(carrierroute_dbh, res);
+	return count;
+}
+
+
+
+
 int load_user_carrier(str * user, str * domain) {
 int load_user_carrier(str * user, str * domain) {
 	db_res_t * res;
 	db_res_t * res;
 	db_key_t cols[1];
 	db_key_t cols[1];
@@ -134,6 +231,8 @@ int load_user_carrier(str * user, str * domain) {
 }
 }
 
 
 
 
+
+
 /**
 /**
  * Loads the routing data from the database given in global
  * Loads the routing data from the database given in global
  * variable db_url and stores it in routing tree rd.
  * variable db_url and stores it in routing tree rd.
@@ -147,11 +246,11 @@ int load_user_carrier(str * user, str * domain) {
 int load_route_data_db(struct route_data_t * rd) {
 int load_route_data_db(struct route_data_t * rd) {
 	db_res_t * res = NULL;
 	db_res_t * res = NULL;
 	db_row_t * row = NULL;
 	db_row_t * row = NULL;
-	int i, ret, carrier_count = 0;
-	struct carrier * carriers = NULL, * tmp = NULL;
+	int i, ret;
+	struct carrier_data_t * tmp_carrier_data;
 	static str query_str;
 	static str query_str;
-	str tmp_carrier, tmp_domain, tmp_scan_prefix, tmp_rewrite_host, tmp_rewrite_prefix,
-		tmp_rewrite_suffix, tmp_host_name, tmp_reply_code, tmp_next_domain, tmp_comment;
+	str tmp_scan_prefix, tmp_rewrite_host, tmp_rewrite_prefix,
+		tmp_rewrite_suffix, tmp_host_name, tmp_reply_code, tmp_comment;
 
 
 	if( (strlen("SELECT DISTINCT  FROM  WHERE = ")
 	if( (strlen("SELECT DISTINCT  FROM  WHERE = ")
 			+ carrierroute_table.len + columns[COL_DOMAIN]->len
 			+ carrierroute_table.len + columns[COL_DOMAIN]->len
@@ -160,24 +259,27 @@ int load_route_data_db(struct route_data_t * rd) {
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if((carrier_count = store_carriers(&carriers)) <= 0){
+	if((rd->carrier_num = load_carrier_map(rd)) <= 0){
 		LM_ERR("error while retrieving carriers\n");
 		LM_ERR("error while retrieving carriers\n");
 		goto errout;
 		goto errout;
 	}
 	}
 
 
-	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *) * carrier_count)) == NULL) {
+	if((rd->domain_num = load_domain_map(rd)) <= 0){
+		LM_ERR("error while retrieving domains\n");
+		goto errout;
+	}
+
+	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *) * rd->carrier_num)) == NULL) {
 		SHM_MEM_ERROR;
 		SHM_MEM_ERROR;
 		goto errout;
 		goto errout;
 	}
 	}
-	memset(rd->carriers, 0, sizeof(struct carrier_data_t *) * carrier_count);
-	rd->carrier_num = carrier_count;
+	memset(rd->carriers, 0, sizeof(struct carrier_data_t *) * rd->carrier_num);
 
 
-	tmp = carriers;
-	for (i=0; i<carrier_count; i++) {
+	for (i=0; i<rd->carrier_num; i++) {
 		memset(query, 0, QUERY_LEN);
 		memset(query, 0, QUERY_LEN);
 		ret = snprintf(query, QUERY_LEN, "SELECT DISTINCT %.*s FROM %.*s WHERE %.*s=%i",
 		ret = snprintf(query, QUERY_LEN, "SELECT DISTINCT %.*s FROM %.*s WHERE %.*s=%i",
 		columns[COL_DOMAIN]->len, columns[COL_DOMAIN]->s, carrierroute_table.len,
 		columns[COL_DOMAIN]->len, columns[COL_DOMAIN]->s, carrierroute_table.len,
-		carrierroute_table.s, columns[COL_CARRIER]->len, columns[COL_CARRIER]->s, tmp->id);
+		carrierroute_table.s, columns[COL_CARRIER]->len, columns[COL_CARRIER]->s, rd->carrier_map[i].id);
 		if (ret < 0) {
 		if (ret < 0) {
 			LM_ERR("error in snprintf");
 			LM_ERR("error in snprintf");
 			goto errout;
 			goto errout;
@@ -189,16 +291,19 @@ int load_route_data_db(struct route_data_t * rd) {
 			LM_ERR("Failed to query database.\n");
 			LM_ERR("Failed to query database.\n");
 			goto errout;
 			goto errout;
 		}
 		}
-		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_data(rd, &tmp_carrier, tmp->id, RES_ROW_N(res)) == NULL) {
-			LM_ERR("can't add carrier %s\n", tmp->name);
+		LM_INFO("carrier '%.*s' (id %i) has %i domains\n", rd->carrier_map[i].name.len, rd->carrier_map[i].name.s, rd->carrier_map[i].id, RES_ROW_N(res));
+		tmp_carrier_data = create_carrier_data(rd->carrier_map[i].id, &rd->carrier_map[i].name, RES_ROW_N(res));
+		if (tmp_carrier_data == NULL) {
+			LM_ERR("can't create new carrier '%.*s'\n", rd->carrier_map[i].name.len, rd->carrier_map[i].name.s);
+			goto errout;
+		}
+		if (add_carrier_data(rd, tmp_carrier_data) < 0) {
+			LM_ERR("can't add carrier '%.*s'\n", rd->carrier_map[i].name.len, rd->carrier_map[i].name.s);
+			destroy_carrier_data(tmp_carrier_data);
 			goto errout;
 			goto errout;
 		}
 		}
 		carrierroute_dbf.free_result(carrierroute_dbh, res);
 		carrierroute_dbf.free_result(carrierroute_dbh, res);
 		res = NULL;
 		res = NULL;
-		tmp = tmp->next;
 	}
 	}
 
 
 	if (carrierroute_dbf.use_table(carrierroute_dbh, &carrierroute_table) < 0) {
 	if (carrierroute_dbf.use_table(carrierroute_dbh, &carrierroute_table) < 0) {
@@ -218,7 +323,7 @@ int load_route_data_db(struct route_data_t * rd) {
 		}
 		}
 	} else {
 	} else {
 		if (carrierroute_dbf.query(carrierroute_dbh, NULL, NULL, NULL, (db_key_t *) columns, 0,
 		if (carrierroute_dbf.query(carrierroute_dbh, NULL, NULL, NULL, (db_key_t *) columns, 0,
-					COLUMN_NUM, NULL, &res) < 0) {
+				 COLUMN_NUM, NULL, &res) < 0) {
 			LM_ERR("Failed to query database.\n");
 			LM_ERR("Failed to query database.\n");
 			return -1;
 			return -1;
 		}
 		}
@@ -228,19 +333,16 @@ int load_route_data_db(struct route_data_t * rd) {
 		LM_DBG("loading, cycle %d", n++);
 		LM_DBG("loading, cycle %d", n++);
 		for (i = 0; i < RES_ROW_N(res); ++i) {
 		for (i = 0; i < RES_ROW_N(res); ++i) {
 			row = &RES_ROWS(res)[i];
 			row = &RES_ROWS(res)[i];
-			tmp_domain.s=(char *)row->values[COL_DOMAIN].val.string_val;
 			tmp_scan_prefix.s=(char *)row->values[COL_SCAN_PREFIX].val.string_val;
 			tmp_scan_prefix.s=(char *)row->values[COL_SCAN_PREFIX].val.string_val;
 			tmp_rewrite_host.s=(char *)row->values[COL_REWRITE_HOST].val.string_val;
 			tmp_rewrite_host.s=(char *)row->values[COL_REWRITE_HOST].val.string_val;
 			tmp_rewrite_prefix.s=(char *)row->values[COL_REWRITE_PREFIX].val.string_val;
 			tmp_rewrite_prefix.s=(char *)row->values[COL_REWRITE_PREFIX].val.string_val;
 			tmp_rewrite_suffix.s=(char *)row->values[COL_REWRITE_SUFFIX].val.string_val;
 			tmp_rewrite_suffix.s=(char *)row->values[COL_REWRITE_SUFFIX].val.string_val;
 			tmp_comment.s=(char *)row->values[COL_COMMENT].val.string_val;
 			tmp_comment.s=(char *)row->values[COL_COMMENT].val.string_val;
-			if (tmp_domain.s==NULL) tmp_domain.s="";
 			if (tmp_scan_prefix.s==NULL) tmp_scan_prefix.s="";
 			if (tmp_scan_prefix.s==NULL) tmp_scan_prefix.s="";
 			if (tmp_rewrite_host.s==NULL) tmp_rewrite_host.s="";
 			if (tmp_rewrite_host.s==NULL) tmp_rewrite_host.s="";
 			if (tmp_rewrite_prefix.s==NULL) tmp_rewrite_prefix.s="";
 			if (tmp_rewrite_prefix.s==NULL) tmp_rewrite_prefix.s="";
 			if (tmp_rewrite_suffix.s==NULL) tmp_rewrite_suffix.s="";
 			if (tmp_rewrite_suffix.s==NULL) tmp_rewrite_suffix.s="";
 			if (tmp_comment.s==NULL) tmp_comment.s="";
 			if (tmp_comment.s==NULL) tmp_comment.s="";
-			tmp_domain.len=strlen(tmp_domain.s);
 			tmp_scan_prefix.len=strlen(tmp_scan_prefix.s);
 			tmp_scan_prefix.len=strlen(tmp_scan_prefix.s);
 			tmp_rewrite_host.len=strlen(tmp_rewrite_host.s);
 			tmp_rewrite_host.len=strlen(tmp_rewrite_host.s);
 			tmp_rewrite_prefix.len=strlen(tmp_rewrite_prefix.s);
 			tmp_rewrite_prefix.len=strlen(tmp_rewrite_prefix.s);
@@ -248,7 +350,7 @@ int load_route_data_db(struct route_data_t * rd) {
 			tmp_comment.len=strlen(tmp_comment.s);
 			tmp_comment.len=strlen(tmp_comment.s);
 			if (add_route(rd,
 			if (add_route(rd,
 					row->values[COL_CARRIER].val.int_val,
 					row->values[COL_CARRIER].val.int_val,
-					&tmp_domain,
+					row->values[COL_DOMAIN].val.int_val,
 					&tmp_scan_prefix,
 					&tmp_scan_prefix,
 					row->values[COL_FLAGS].val.int_val,
 					row->values[COL_FLAGS].val.int_val,
 					row->values[COL_MASK].val.int_val,
 					row->values[COL_MASK].val.int_val,
@@ -292,103 +394,38 @@ int load_route_data_db(struct route_data_t * rd) {
 	}
 	}
 	for (i = 0; i < RES_ROW_N(res); ++i) {
 	for (i = 0; i < RES_ROW_N(res); ++i) {
 		row = &RES_ROWS(res)[i];
 		row = &RES_ROWS(res)[i];
-		tmp_domain.s=(char *)row->values[FCOL_DOMAIN].val.string_val;
 		tmp_scan_prefix.s=(char *)row->values[FCOL_SCAN_PREFIX].val.string_val;
 		tmp_scan_prefix.s=(char *)row->values[FCOL_SCAN_PREFIX].val.string_val;
 		tmp_host_name.s=(char *)row->values[FCOL_HOST_NAME].val.string_val;
 		tmp_host_name.s=(char *)row->values[FCOL_HOST_NAME].val.string_val;
 		tmp_reply_code.s=(char *)row->values[FCOL_REPLY_CODE].val.string_val;
 		tmp_reply_code.s=(char *)row->values[FCOL_REPLY_CODE].val.string_val;
-		tmp_next_domain.s=(char *)row->values[FCOL_NEXT_DOMAIN].val.string_val;
 		tmp_comment.s=(char *)row->values[FCOL_COMMENT].val.string_val;
 		tmp_comment.s=(char *)row->values[FCOL_COMMENT].val.string_val;
-		if (tmp_domain.s==NULL) tmp_domain.s="";
 		if (tmp_scan_prefix.s==NULL) tmp_scan_prefix.s="";
 		if (tmp_scan_prefix.s==NULL) tmp_scan_prefix.s="";
 		if (tmp_host_name.s==NULL) tmp_host_name.s="";
 		if (tmp_host_name.s==NULL) tmp_host_name.s="";
 		if (tmp_reply_code.s==NULL) tmp_reply_code.s="";
 		if (tmp_reply_code.s==NULL) tmp_reply_code.s="";
-		if (tmp_next_domain.s==NULL) tmp_next_domain.s="";
 		if (tmp_comment.s==NULL) tmp_comment.s="";
 		if (tmp_comment.s==NULL) tmp_comment.s="";
-		tmp_domain.len=strlen(tmp_domain.s);
 		tmp_scan_prefix.len=strlen(tmp_scan_prefix.s);
 		tmp_scan_prefix.len=strlen(tmp_scan_prefix.s);
 		tmp_host_name.len=strlen(tmp_host_name.s);
 		tmp_host_name.len=strlen(tmp_host_name.s);
 		tmp_reply_code.len=strlen(tmp_reply_code.s);
 		tmp_reply_code.len=strlen(tmp_reply_code.s);
-		tmp_next_domain.len=strlen(tmp_next_domain.s);
 		tmp_comment.len=strlen(tmp_comment.s);
 		tmp_comment.len=strlen(tmp_comment.s);
 		if (add_failure_route(rd,
 		if (add_failure_route(rd,
 				row->values[FCOL_CARRIER].val.int_val,
 				row->values[FCOL_CARRIER].val.int_val,
-				&tmp_domain,
+				row->values[COL_DOMAIN].val.int_val,
 				&tmp_scan_prefix,
 				&tmp_scan_prefix,
 				&tmp_host_name,
 				&tmp_host_name,
 				&tmp_reply_code,
 				&tmp_reply_code,
 				row->values[FCOL_FLAGS].val.int_val,
 				row->values[FCOL_FLAGS].val.int_val,
 				row->values[FCOL_MASK].val.int_val,
 				row->values[FCOL_MASK].val.int_val,
-				&tmp_next_domain,
+				row->values[FCOL_NEXT_DOMAIN].val.int_val,
 				&tmp_comment) == -1) {
 				&tmp_comment) == -1) {
 			goto errout;
 			goto errout;
 		}
 		}
 	}
 	}
 
 
-	destroy_carriers(carriers);
 	carrierroute_dbf.free_result(carrierroute_dbh, res);
 	carrierroute_dbf.free_result(carrierroute_dbh, res);
 	return 0;
 	return 0;
 
 
 errout:
 errout:
-	destroy_carriers(carriers);
 	if (res) {
 	if (res) {
 		carrierroute_dbf.free_result(carrierroute_dbh, res);
 		carrierroute_dbf.free_result(carrierroute_dbh, res);
 	}
 	}
 	return -1;
 	return -1;
 }
 }
-
-
-static int store_carriers(struct carrier ** start){
-	db_res_t * res = NULL;
-	int i, count;
-	struct carrier * nc;
-	if(!start){
-		LM_ERR("invalid parameter\n");
-		return -1;
-	}
-	if (carrierroute_dbf.use_table(carrierroute_dbh, &route_tree_table) < 0) {
-		LM_ERR("couldn't use table\n");
-		return -1;
-	}
-
-	if (carrierroute_dbf.query(carrierroute_dbh, 0, 0, 0, (db_key_t *)carrier_columns, 0, CARRIER_COLUMN_NUM, 0, &res) < 0) {
-		LM_ERR("couldn't query table\n");
-		return -1;
-	}
-	count = RES_ROW_N(res);
-	for(i=0; i<RES_ROW_N(res); i++){
-		if((nc = pkg_malloc(sizeof(struct carrier))) == NULL){
-			PKG_MEM_ERROR;
-			return -1;
-		}
-		nc->id = res->rows[i].values[0].val.int_val;
-		if((nc->name = pkg_malloc(strlen(res->rows[i].values[1].val.string_val) + 1)) == NULL){
-			PKG_MEM_ERROR;
-			pkg_free(nc);
-			goto errout;
-		}
-		strcpy(nc->name, res->rows[i].values[1].val.string_val);
-		nc->next = *start;
-		*start = nc;
-	}
-	carrierroute_dbf.free_result(carrierroute_dbh, res);
-	return count;
-errout:
-if(res){
-	carrierroute_dbf.free_result(carrierroute_dbh, res);
-}
-	return -1;
-}
-
-
-static void destroy_carriers(struct carrier * start){
-	struct carrier * tmp, * tmp2;
-	tmp = start;
-	
-	while(tmp){
-		tmp2 = tmp;
-		tmp = tmp->next;
-		pkg_free(tmp2->name);
-		pkg_free(tmp2);
-	}
-	return;
-}

+ 7 - 3
modules/carrierroute/cr_db.h

@@ -61,9 +61,13 @@
 #define FCOL_NEXT_DOMAIN    8
 #define FCOL_NEXT_DOMAIN    8
 #define FCOL_COMMENT        9
 #define FCOL_COMMENT        9
 
 
-#define CARRIER_COLUMN_NUM 2
-#define CARRIER_ID_COL 0
-#define CARRIER_NAME_COL 1
+#define CARRIER_NAME_COLUMN_NUM 2
+#define CARRIER_NAME_ID_COL 0
+#define CARRIER_NAME_NAME_COL 1
+
+#define DOMAIN_NAME_COLUMN_NUM 2
+#define DOMAIN_NAME_ID_COL 0
+#define DOMAIN_NAME_NAME_COL 1
 
 
 extern str * columns[];
 extern str * columns[];
 extern str * carrier_columns[];
 extern str * carrier_columns[];

+ 34 - 16
modules/carrierroute/cr_domain.c

@@ -31,7 +31,6 @@
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../ut.h"
 #include "../../ut.h"
 #include "cr_domain.h"
 #include "cr_domain.h"
-#include "cr_map.h"
 #include "cr_rule.h"
 #include "cr_rule.h"
 
 
 
 
@@ -72,33 +71,27 @@ static void destroy_failure_route_rule_list(void *data) {
 /**
 /**
  * Create a new domain in shared memory and set it up.
  * Create a new domain in shared memory and set it up.
  *
  *
- * @param domain_name the name of the domain
  * @param domain_id the id of the domain
  * @param domain_id the id of the domain
+ * @param domain_name the name of the domain
  *
  *
  * @return a pointer to the newly allocated domain data or NULL on
  * @return a pointer to the newly allocated domain data or NULL on
  * error, in which case it LOGs an error message.
  * error, in which case it LOGs an error message.
  */
  */
-struct domain_data_t * create_domain_data(const str * domain_name, int domain_id) {
+struct domain_data_t * create_domain_data(int domain_id, str * domain_name) {
 	struct domain_data_t * tmp;
 	struct domain_data_t * tmp;
 	if ((tmp = shm_malloc(sizeof(struct domain_data_t))) == NULL) {
 	if ((tmp = shm_malloc(sizeof(struct domain_data_t))) == NULL) {
-		LM_ERR("out of shared memory\n");
+		SHM_MEM_ERROR;
 		return NULL;
 		return NULL;
 	}
 	}
 	memset(tmp, 0, sizeof(struct domain_data_t));
 	memset(tmp, 0, sizeof(struct domain_data_t));
-	if (shm_str_dup(&tmp->name, domain_name)!=0) {
-		LM_ERR("cannot duplicate string\n");
-		shm_free(tmp);
-		return NULL;
-	}
 	tmp->id = domain_id;
 	tmp->id = domain_id;
+	tmp->name = domain_name;
 	if ((tmp->tree = dtrie_init()) == NULL) {
 	if ((tmp->tree = dtrie_init()) == NULL) {
-		shm_free(tmp->name.s);
 		shm_free(tmp);
 		shm_free(tmp);
 		return NULL;
 		return NULL;
 	}
 	}
 	if ((tmp->failure_tree = dtrie_init()) == NULL) {
 	if ((tmp->failure_tree = dtrie_init()) == NULL) {
 		dtrie_destroy(&tmp->tree, NULL);
 		dtrie_destroy(&tmp->tree, NULL);
-		shm_free(tmp->name.s);
 		shm_free(tmp);
 		shm_free(tmp);
 		return NULL;
 		return NULL;
 	}
 	}
@@ -109,13 +102,14 @@ struct domain_data_t * create_domain_data(const str * domain_name, int domain_id
 /**
 /**
  * Destroys the given domain and frees the used memory.
  * Destroys the given domain and frees the used memory.
  *
  *
- * @param domain_data the to the structure to be destroyed.
+ * @param domain_data the structure to be destroyed.
  */
  */
 void destroy_domain_data(struct domain_data_t *domain_data) {
 void destroy_domain_data(struct domain_data_t *domain_data) {
-	dtrie_destroy(&domain_data->tree, destroy_route_flags_list);
-	dtrie_destroy(&domain_data->failure_tree, destroy_failure_route_rule_list);
-	shm_free(domain_data->name.s);
-	shm_free(domain_data);
+	if (domain_data) {
+		dtrie_destroy(&domain_data->tree, destroy_route_flags_list);
+		dtrie_destroy(&domain_data->failure_tree, destroy_failure_route_rule_list);
+		shm_free(domain_data);
+	}
 }
 }
 
 
 
 
@@ -225,3 +219,27 @@ int add_failure_route_to_tree(struct dtrie_node_t * failure_node, const str * sc
 
 
 	return 0;
 	return 0;
 }
 }
+
+
+/**
+ * Compares the IDs of two domain data structures.
+ * A NULL pointer is always greater than any ID.
+ *
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
+ */
+int compare_domain_data(const void *v1, const void *v2) {
+  struct domain_data_t *d1 = *(struct domain_data_t * const *)v1;
+	struct domain_data_t *d2 = *(struct domain_data_t * const *)v2;
+	if (d1 == NULL) {
+		if (d2 == NULL) return 0;
+		else return 1;
+	}
+	else {
+		if (d2 == NULL) return -1;
+		else {
+			if (d1->id < d2->id) return -1;
+			else if (d1->id > d2->id) return 1;
+			else return 0;
+		}
+	}
+}

+ 13 - 3
modules/carrierroute/cr_domain.h

@@ -41,7 +41,7 @@
  */
  */
 struct domain_data_t {
 struct domain_data_t {
 	int id; /*!< the numerical id of the routing tree */
 	int id; /*!< the numerical id of the routing tree */
-	str name; /*!< the name of the routing tree */
+	str * name; /*!< the name of the routing tree. This points to the name in domain_map to avoid duplication. */
 	struct dtrie_node_t * tree; /*!< the root node of the routing tree. Payload is of type (struct route_flags *) */
 	struct dtrie_node_t * tree; /*!< the root node of the routing tree. Payload is of type (struct route_flags *) */
 	struct dtrie_node_t * failure_tree; /*!< the root node of the failure routing tree. Payload is of type (struct failure_route_rule *) */
 	struct dtrie_node_t * failure_tree; /*!< the root node of the failure routing tree. Payload is of type (struct failure_route_rule *) */
 };
 };
@@ -50,13 +50,13 @@ struct domain_data_t {
 /**
 /**
  * Create a new domain in shared memory and set it up.
  * Create a new domain in shared memory and set it up.
  *
  *
- * @param domain_name the name of the domain
  * @param domain_id the id of the domain
  * @param domain_id the id of the domain
+ * @param domain_name the name of the domain
  *
  *
  * @return a pointer to the newly allocated domain data or NULL on
  * @return a pointer to the newly allocated domain data or NULL on
  * error, in which case it LOGs an error message.
  * error, in which case it LOGs an error message.
  */
  */
-struct domain_data_t * create_domain_data(const str * domain, int id);
+struct domain_data_t * create_domain_data(int id, str * domain);
 
 
 
 
 /**
 /**
@@ -129,4 +129,14 @@ int add_failure_route_to_tree(struct dtrie_node_t * failure_node, const str * sc
 		const str * full_prefix, const str * host, const str * reply_code,
 		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);
 		const flag_t flags, const flag_t mask, const int next_domain, const str * comment);
 
 
+
+/**
+ * Compares the IDs of two domain data structures.
+ * A NULL pointer is always greater than any ID.
+ *
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
+ */
+int compare_domain_data(const void *v1, const void *v2);
+
+
 #endif
 #endif

+ 20 - 14
modules/carrierroute/cr_fifo.c

@@ -131,7 +131,7 @@ struct mi_root* dump_fifo (struct mi_root* cmd_tree, void *param) {
 		LM_ERR("error during retrieve data\n");
 		LM_ERR("error during retrieve data\n");
 		return init_mi_tree(500, "error during command processing", 31);
 		return init_mi_tree(500, "error during command processing", 31);
 	}
 	}
-		
+	
 	struct mi_root* rpl_tree;
 	struct mi_root* rpl_tree;
 	struct mi_node* node = NULL;
 	struct mi_node* node = NULL;
 	rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
 	rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
@@ -145,14 +145,14 @@ struct mi_root* dump_fifo (struct mi_root* cmd_tree, void *param) {
 	int i, j;
 	int i, j;
  	for (i = 0; i < rd->carrier_num; i++) {
  	for (i = 0; i < rd->carrier_num; i++) {
  		if (rd->carriers[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);
+			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)
 			if(node == NULL)
 				goto error;
 				goto error;
  			for (j=0; j<rd->carriers[i]->domain_num; j++) {
  			for (j=0; j<rd->carriers[i]->domain_num; j++) {
  				if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
  				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);
+					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' (%i)\n", tmp_str->len, tmp_str->s, rd->carriers[i]->domains[j]->id);
 					if(node == NULL)
 					if(node == NULL)
 						goto error;
 						goto error;
  					dump_tree_recursor (&rpl_tree->node, rd->carriers[i]->domains[j]->tree, "");
  					dump_tree_recursor (&rpl_tree->node, rd->carriers[i]->domains[j]->tree, "");
@@ -605,6 +605,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(fifo_opt_t * opts) {
 	struct route_data_t * rd;
 	struct route_data_t * rd;
 	int i,j;
 	int i,j;
+	int domain_id;
 	str tmp_domain;
 	str tmp_domain;
 	str tmp_prefix;
 	str tmp_prefix;
 	str tmp_host;
 	str tmp_host;
@@ -613,7 +614,7 @@ static int update_route_data(fifo_opt_t * opts) {
 	str tmp_comment = str_init("");
 	str tmp_comment = str_init("");
 
 
 	if ((rd = shm_malloc(sizeof(struct route_data_t))) == NULL) {
 	if ((rd = shm_malloc(sizeof(struct route_data_t))) == NULL) {
-		LM_ERR("out of shared memory\n");
+		SHM_MEM_ERROR;
 		return -1;
 		return -1;
 	}
 	}
 	memset(rd, 0, sizeof(struct route_data_t));
 	memset(rd, 0, sizeof(struct route_data_t));
@@ -657,7 +658,13 @@ static int update_route_data(fifo_opt_t * opts) {
 			tmp_rewrite_suffix.len=0;
 			tmp_rewrite_suffix.len=0;
 		}
 		}
 
 
-		if (add_route(rd, 1, &tmp_domain, &tmp_prefix, 0, 0, 0, opts->prob,
+		domain_id = map_name2id(rd->domain_map, rd->domain_num, &tmp_domain);
+		if (domain_id < 0) {
+			LM_ERR("cannot find id for domain '%.*s'", tmp_domain.len, tmp_domain.s);
+			goto errout;
+		}
+
+		if (add_route(rd, 1, domain_id, &tmp_prefix, 0, 0, 0, opts->prob,
 		              &tmp_host, opts->strip, &tmp_rewrite_prefix, &tmp_rewrite_suffix,
 		              &tmp_host, opts->strip, &tmp_rewrite_prefix, &tmp_rewrite_suffix,
 		              opts->status, opts->hash_index, -1, NULL, &tmp_comment) < 0) {
 		              opts->status, opts->hash_index, -1, NULL, &tmp_comment) < 0) {
 			goto errout;
 			goto errout;
@@ -666,20 +673,19 @@ static int update_route_data(fifo_opt_t * opts) {
 		if (rule_fixup(rd) < 0) {
 		if (rule_fixup(rd) < 0) {
 			LM_ERR("could not fixup rules after route appending");
 			LM_ERR("could not fixup rules after route appending");
 			FIFO_ERR(E_RULEFIXUP);
 			FIFO_ERR(E_RULEFIXUP);
-			return -1;
+			goto errout;
 		}
 		}
-
 	} else {
 	} else {
 		for (i=0; i<rd->carrier_num; i++) {
 		for (i=0; i<rd->carrier_num; i++) {
 			if(rd->carriers[i]){
 			if(rd->carriers[i]){
-			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;
+				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;
+						}
 					}
 					}
 				}
 				}
 			}
 			}
-			}
 		}
 		}
 	}
 	}
 
 

+ 67 - 6
modules/carrierroute/cr_fixup.c

@@ -34,6 +34,55 @@
 #include "cr_map.h"
 #include "cr_map.h"
 #include "cr_domain.h"
 #include "cr_domain.h"
 #include "prime_hash.h"
 #include "prime_hash.h"
+#include "cr_data.h"
+
+
+/**
+ * The fixup funcions will use the initial mapping.
+ * If the mapping changes afterwards (eg. due to cr_reload_routes),
+ * the names used in the routing script will not be mapped
+ * to the correct IDs!
+ * @param name carrier name
+ * @return carrier id
+ */
+static int carrier_name_2_id(const str *name) {
+	int id;
+	struct route_data_t * rd;
+	
+	do {
+		rd = get_data();
+	} while (rd == NULL);
+
+	id = map_name2id(rd->carrier_map, rd->carrier_num, name);
+	
+	release_data(rd);
+
+	return id;
+}
+
+
+/**
+ * The fixup funcions will use the initial mapping.
+ * If the mapping changes afterwards (eg. due to cr_reload_routes),
+ * the names used in the routing script will not be mapped
+ * to the correct IDs!
+ * @param name domain name
+ * @return domain id 
+ */
+static int domain_name_2_id(const str *name) {
+	int id;
+	struct route_data_t * rd;
+
+	do {
+		rd = get_data();
+	} while (rd == NULL);
+	
+	id = map_name2id(rd->domain_map, rd->domain_num, name);
+	
+	release_data(rd);
+
+	return id;
+}
 
 
 
 
 /**
 /**
@@ -69,6 +118,7 @@ static enum hash_source hash_fixup(const char * my_hash_source) {
  * @return 0 on success, -1 on failure
  * @return 0 on success, -1 on failure
  */
  */
 static int carrier_fixup(void ** param) {
 static int carrier_fixup(void ** param) {
+	int id;
 
 
 	if (fixup_spve_null(param, 1) !=0) {
 	if (fixup_spve_null(param, 1) !=0) {
 		LM_ERR("could not fixup parameter");
 		LM_ERR("could not fixup parameter");
@@ -79,11 +129,12 @@ static int carrier_fixup(void ** param) {
 		/* This is a name string, convert to a int */
 		/* This is a name string, convert to a int */
 		((gparam_p)(*param))->type=GPARAM_TYPE_INT;
 		((gparam_p)(*param))->type=GPARAM_TYPE_INT;
 		/* get carrier id */
 		/* get carrier id */
-		if ((((gparam_p)(*param))->v.ival = find_carrier(&((gparam_p)(*param))->v.sval)) < 0) {
-			LM_ERR("could not add carrier\n");
+		if ((id = carrier_name_2_id(&((gparam_p)(*param))->v.sval)) < 0) {
+			LM_ERR("could not find carrier name '%.*s' in map\n", ((gparam_p)(*param))->v.sval.len, ((gparam_p)(*param))->v.sval.s);
 			pkg_free(*param);
 			pkg_free(*param);
 			return -1;
 			return -1;
 		}
 		}
+		((gparam_p)(*param))->v.ival = id;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -98,7 +149,8 @@ static int carrier_fixup(void ** param) {
  * @return 0 on success, -1 on failure
  * @return 0 on success, -1 on failure
  */
  */
 static int domain_fixup(void ** param) {
 static int domain_fixup(void ** param) {
-	
+	int id;
+
 	if (fixup_spve_null(param, 1) !=0) {
 	if (fixup_spve_null(param, 1) !=0) {
 		LM_ERR("could not fixup parameter");
 		LM_ERR("could not fixup parameter");
 		return -1;
 		return -1;
@@ -108,11 +160,12 @@ static int domain_fixup(void ** param) {
 		/* This is a name string, convert to a int */
 		/* This is a name string, convert to a int */
 		((gparam_p)(*param))->type=GPARAM_TYPE_INT;
 		((gparam_p)(*param))->type=GPARAM_TYPE_INT;
 		/* get domain id */
 		/* get domain id */
-		if ((((gparam_p)(*param))->v.ival = add_domain(&(((gparam_p)(*param))->v.sval))) < 0) {
-			LM_ERR("could not add domain\n");
+		if ((id = domain_name_2_id(&(((gparam_p)(*param))->v.sval))) < 0) {
+			LM_ERR("could not find domain name '%.*s' in map\n", ((gparam_p)(*param))->v.sval.len, ((gparam_p)(*param))->v.sval.s);
 			pkg_free(*param);
 			pkg_free(*param);
 			return -1;
 			return -1;
 		}
 		}
+		((gparam_p)(*param))->v.ival = id;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -142,7 +195,7 @@ static int avp_name_fixup(void ** param) {
 
 
 
 
 /**
 /**
- * fixes the module functions' parameters, i.e. it maps
+ * Fixes the module functions' parameters, i.e. it maps
  * the routing domain names to numbers for faster access
  * the routing domain names to numbers for faster access
  * at runtime
  * at runtime
  *
  *
@@ -240,6 +293,14 @@ int cr_load_next_domain_fixup(void ** param, int param_no) {
 }
 }
 
 
 
 
+/**
+ * Fixes the module functions' parameters.
+ *
+ * @param param the parameter
+ * @param param_no the number of the parameter
+ *
+ * @return 0 on success, -1 on failure
+ */
 int cr_load_user_carrier_fixup(void ** param, int param_no) {
 int cr_load_user_carrier_fixup(void ** param, int param_no) {
 	if (mode == CARRIERROUTE_MODE_FILE) {
 	if (mode == CARRIERROUTE_MODE_FILE) {
 		LM_ERR("command cr_user_rewrite_uri can't be used in file mode\n");
 		LM_ERR("command cr_user_rewrite_uri can't be used in file mode\n");

+ 30 - 0
modules/carrierroute/cr_fixup.h

@@ -32,10 +32,40 @@
 #define CR_FIXUP_H
 #define CR_FIXUP_H
 
 
 
 
+/**
+ * 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
+ */
 int cr_route_fixup(void ** param, int param_no);
 int cr_route_fixup(void ** param, int param_no);
 
 
+
+/**
+ * Fixes the module functions' parameters.
+ *
+ * @param param the parameter
+ * @param param_no the number of the parameter
+ *
+ * @return 0 on success, -1 on failure
+ */
 int cr_load_user_carrier_fixup(void ** param, int param_no);
 int cr_load_user_carrier_fixup(void ** param, int param_no);
 
 
+
+/**
+ * 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
+ */
 int cr_load_next_domain_fixup(void ** param, int param_no);
 int cr_load_next_domain_fixup(void ** param, int param_no);
 
 
 #endif
 #endif

+ 39 - 25
modules/carrierroute/cr_func.c

@@ -71,7 +71,7 @@ static const str AT_SIGN  = { .s="@",     .len=1 };
  * @param search_if lookup function
  * @param search_if lookup function
  * @return id on success, -1 otherwise
  * @return id on success, -1 otherwise
  */
  */
-static inline int cr_gp2id(struct sip_msg *_msg, gparam_t *gp, int (*search_id)(const str* name)) {
+static inline int cr_gp2id(struct sip_msg *_msg, gparam_t *gp, struct name_map_t *map, int size) {
 	int id;
 	int id;
 	struct usr_avp *avp;
 	struct usr_avp *avp;
 	int_str avp_val;
 	int_str avp_val;
@@ -94,7 +94,7 @@ static inline int cr_gp2id(struct sip_msg *_msg, gparam_t *gp, int (*search_id)(
 			if ((avp->flags&AVP_VAL_STR)==0) {
 			if ((avp->flags&AVP_VAL_STR)==0) {
 				return avp_val.n;
 				return avp_val.n;
 			} else {
 			} else {
-				id = search_id(&avp_val.s);
+				id = map_name2id(map, size, &avp_val.s);
 				if (id < 0) {
 				if (id < 0) {
 					LM_ERR("could not find id '%.*s' from AVP\n",
 					LM_ERR("could not find id '%.*s' from AVP\n",
 							gp->v.pve->spec.pvp.pvn.u.isname.name.s.len,
 							gp->v.pve->spec.pvp.pvn.u.isname.name.s.len,
@@ -109,7 +109,7 @@ static inline int cr_gp2id(struct sip_msg *_msg, gparam_t *gp, int (*search_id)(
 				LM_ERR("cannot print the name from PV\n");
 				LM_ERR("cannot print the name from PV\n");
 				return -1;
 				return -1;
 			}
 			}
-			id = search_id(&tmp);
+			id = map_name2id(map, size, &tmp);
 			if (id < 0) {
 			if (id < 0) {
 				LM_ERR("could not find id '%.*s' from PV\n", tmp.len, tmp.s);
 				LM_ERR("could not find id '%.*s' from PV\n", tmp.len, tmp.s);
 				return -1;
 				return -1;
@@ -493,13 +493,6 @@ int cr_do_route(struct sip_msg * _msg, gparam_t *_carrier,
 	struct domain_data_t * domain_data;
 	struct domain_data_t * domain_data;
 	struct action act;
 	struct action act;
 
 
-	carrier_id = cr_gp2id(_msg, _carrier, find_carrier);
-	domain_id = cr_gp2id(_msg, _domain, add_domain);
-	if (domain_id < 0) {
-		LM_ERR("invalid domain id %d\n", domain_id);
-		return -1;
-	}
-
 	if (fixup_get_svalue(_msg, _rewrite_user, &rewrite_user)<0) {
 	if (fixup_get_svalue(_msg, _rewrite_user, &rewrite_user)<0) {
 		LM_ERR("cannot print the rewrite_user\n");
 		LM_ERR("cannot print the rewrite_user\n");
 		return -1;
 		return -1;
@@ -515,21 +508,35 @@ int cr_do_route(struct sip_msg * _msg, gparam_t *_carrier,
 	do {
 	do {
 		rd = get_data();
 		rd = get_data();
 	} while (rd == NULL);
 	} while (rd == NULL);
+
+	carrier_id = cr_gp2id(_msg, _carrier, rd->carrier_map, rd->carrier_num);
+	if (carrier_id < 0) {
+		LM_ERR("invalid carrier id %d\n", carrier_id);
+		release_data(rd);
+		return -1;
+	}
+
+	domain_id = cr_gp2id(_msg, _domain, rd->domain_map, rd->domain_num);
+	if (domain_id < 0) {
+		LM_ERR("invalid domain id %d\n", domain_id);
+		release_data(rd);
+		return -1;
+	}
 	
 	
 	carrier_data=NULL;
 	carrier_data=NULL;
 	if (carrier_id < 0) {
 	if (carrier_id < 0) {
 		if (fallback_default) {
 		if (fallback_default) {
 			LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
 			LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-			carrier_data = rd->carriers[rd->default_carrier_index];
+			carrier_data = get_carrier_data(rd, rd->default_carrier_id);
 		}
 		}
 	} else if (carrier_id == 0) {
 	} else if (carrier_id == 0) {
-		carrier_data = rd->carriers[rd->default_carrier_index];
+		carrier_data = get_carrier_data(rd, rd->default_carrier_id);
 	} else {
 	} else {
 		carrier_data = get_carrier_data(rd, carrier_id);
 		carrier_data = get_carrier_data(rd, carrier_id);
 		if (carrier_data == NULL) {
 		if (carrier_data == NULL) {
 			if (fallback_default) {
 			if (fallback_default) {
 				LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
 				LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-				carrier_data = rd->carriers[rd->default_carrier_index];
+				carrier_data = get_carrier_data(rd, rd->default_carrier_id);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -538,7 +545,7 @@ int cr_do_route(struct sip_msg * _msg, gparam_t *_carrier,
 		goto unlock_and_out;
 		goto unlock_and_out;
 	}
 	}
 
 
-	domain_data = get_domain_data_by_id(carrier_data, domain_id);
+	domain_data = get_domain_data(carrier_data, domain_id);
 	if (domain_data == NULL) {
 	if (domain_data == NULL) {
 		LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n",
 		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);
 			prefix_matching.len, prefix_matching.s, carrier_id, domain_id);
@@ -683,13 +690,6 @@ int cr_load_next_domain(struct sip_msg * _msg, gparam_t *_carrier,
 	struct carrier_data_t * carrier_data;
 	struct carrier_data_t * carrier_data;
 	struct domain_data_t * domain_data;
 	struct domain_data_t * domain_data;
 
 
-	carrier_id = cr_gp2id(_msg, _carrier, find_carrier);
-	domain_id = cr_gp2id(_msg, _domain, add_domain);
-	if (domain_id < 0) {
-		LM_ERR("invalid domain id %d\n", domain_id);
-		return -1;
-	}
-
 	if (fixup_get_svalue(_msg, _prefix_matching, &prefix_matching)<0) {
 	if (fixup_get_svalue(_msg, _prefix_matching, &prefix_matching)<0) {
 		LM_ERR("cannot print the prefix_matching\n");
 		LM_ERR("cannot print the prefix_matching\n");
 		return -1;
 		return -1;
@@ -709,20 +709,34 @@ int cr_load_next_domain(struct sip_msg * _msg, gparam_t *_carrier,
 		rd = get_data();
 		rd = get_data();
 	} while (rd == NULL);
 	} while (rd == NULL);
 	
 	
+	carrier_id = cr_gp2id(_msg, _carrier, rd->carrier_map, rd->carrier_num);
+	if (carrier_id < 0) {
+		LM_ERR("invalid carrier id %d\n", carrier_id);
+		release_data(rd);
+		return -1;
+	}
+
+	domain_id = cr_gp2id(_msg, _domain, rd->domain_map, rd->domain_num);
+	if (domain_id < 0) {
+		LM_ERR("invalid domain id %d\n", domain_id);
+		release_data(rd);
+		return -1;
+	}
+
 	carrier_data=NULL;
 	carrier_data=NULL;
 	if (carrier_id < 0) {
 	if (carrier_id < 0) {
 		if (fallback_default) {
 		if (fallback_default) {
 			LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
 			LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-			carrier_data = rd->carriers[rd->default_carrier_index];
+			carrier_data = get_carrier_data(rd, rd->default_carrier_id);
 		}
 		}
 	} else if (carrier_id == 0) {
 	} else if (carrier_id == 0) {
-		carrier_data = rd->carriers[rd->default_carrier_index];
+		carrier_data = get_carrier_data(rd, rd->default_carrier_id);
 	} else {
 	} else {
 		carrier_data = get_carrier_data(rd, carrier_id);
 		carrier_data = get_carrier_data(rd, carrier_id);
 		if (carrier_data == NULL) {
 		if (carrier_data == NULL) {
 			if (fallback_default) {
 			if (fallback_default) {
 				LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
 				LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
-				carrier_data = rd->carriers[rd->default_carrier_index];
+				carrier_data = get_carrier_data(rd, rd->default_carrier_id);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -731,7 +745,7 @@ int cr_load_next_domain(struct sip_msg * _msg, gparam_t *_carrier,
 		goto unlock_and_out;
 		goto unlock_and_out;
 	}
 	}
 
 
-	domain_data = get_domain_data_by_id(carrier_data, domain_id);
+	domain_data = get_domain_data(carrier_data, domain_id);
 	if (domain_data == NULL) {
 	if (domain_data == NULL) {
 		LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n",
 		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);
 			prefix_matching.len, prefix_matching.s, carrier_id, domain_id);

+ 31 - 175
modules/carrierroute/cr_map.c

@@ -27,207 +27,63 @@
  * - Module; \ref carrierroute
  * - Module; \ref carrierroute
  */
  */
 
 
+#include <stdlib.h>
 #include "cr_map.h"
 #include "cr_map.h"
 #include "../../mem/shm_mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../ut.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.
+ * Searches for the ID of a name
  *
  *
- * @param domain the domain to be added
+ * @param map the mapping list to search in
+ * @param size the size of the list
+ * @param name the name, we are looking for
  *
  *
- * @return values: on succcess the numerical index of the given domain,
- * -1 on failure
+ * @return values: on succcess the id for this name, -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 *));
-	}
+int map_name2id(struct name_map_t * map, int size, const str * name) {
+	int i;
 
 
-	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);
+	if ((!name) || (name->len <= 0)) {
 		return -1;
 		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;
+	for (i=0; i<size; i++) {
+		if (str_strcmp(&map[i].name, name) == 0) return map[i].id;
 	}
 	}
+	return -1;
 }
 }
 
 
 
 
 /**
 /**
- * Tries to add a carrier name to the carrier map. If the given carrier
- * doesn't exist, it is added. Otherwise, nothing happens.
+ * Searches for the name of an ID
  *
  *
- * @param carrier_name the carrier name to be added
- * @param carrier_id the corresponding id
+ * @param map the mapping list to search in
+ * @param size the size of the list
+ * @param id the id, we are looking for
  *
  *
- * @return values: on succcess the numerical index of the given carrier,
- * -1 on failure
+ * @return values: on succcess the name for this id, NULL 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;
+str * map_id2name(struct name_map_t * map, int size, int id) {
+	struct name_map_t key;
+	struct name_map_t * tmp;
+
+	key.id = id;
+	tmp = bsearch(&key, map, size, sizeof(struct name_map_t), compare_name_map);
+	if (tmp == NULL) return NULL;
+	return &tmp->name;
 }
 }
 
 
 
 
 /**
 /**
- * Searches for the ID for a Carrier-Name
+ * Compares the IDs of two name_map_t structures.
  *
  *
- * @param carrier_name the carrier name, we are looking for
- *
- * @return values: on succcess the id for this carrier name,
- * -1 on failure
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
  */
  */
-int find_carrier(const 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;
-	}
+int compare_name_map(const void *v1, const void *v2) {
+	if (((struct name_map_t *)v1)->id < ((struct name_map_t *)v2)->id) return -1;
+	else if (((struct name_map_t *)v1)->id > ((struct name_map_t *)v2)->id) return 1;
+	else return 0;
 }
 }

+ 22 - 26
modules/carrierroute/cr_map.h

@@ -34,50 +34,46 @@
 
 
 
 
 /**
 /**
- * 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
+ * used to map names to numbers for faster access.
  */
  */
-int add_domain(const str * domain);
+struct name_map_t {
+	str name; /*!< name of the routing domain or carrier */
+	int id; /*!< the corresponding id */
+};
 
 
 
 
-/**
- * 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.
+ * Searches for the ID of a name
  *
  *
- * @param carrier_name the carrier name to be added
- * @param carrier_id the corresponding id
+ * @param map the mapping list to search in
+ * @param size the size of the list
+ * @param name the name, we are looking for
  *
  *
- * @return values: on succcess the numerical index of the given carrier,
- * -1 on failure
+ * @return values: on succcess the id for this name, -1 on failure
  */
  */
-int add_carrier(const str * tree, int carrier_id);
+int map_name2id(struct name_map_t * map, int size, const str * name);
 
 
 
 
 /**
 /**
- * Searches for the ID for a Carrier-Name
+ * Searches for the name of an ID
  *
  *
- * @param carrier_name the carrier name, we are looking for
+ * @param map the mapping list to search in
+ * @param size the size of the list
+ * @param id the id, we are looking for
  *
  *
- * @return values: on succcess the id for this carrier name,
- * -1 on failure
+ * @return values: on succcess the name for this id, NULL on failure
  */
  */
-int find_carrier(const str * carrier_name);
+str * map_id2name(struct name_map_t * map, int size, int id);
 
 
 
 
 /**
 /**
- * Destroy the carrier map by freeing its memory.
+ * Compares the IDs of two name_map_t structures.
+ *
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
  */
  */
-void destroy_carrier_map(void);
+int compare_name_map(const void *v1, const void *v2);
+
 
 
 #endif
 #endif

+ 1 - 1
modules/carrierroute/cr_rule.c

@@ -386,7 +386,7 @@ struct failure_route_rule *add_failure_route_rule(struct failure_route_rule **fr
 	return shm_frr;
 	return shm_frr;
 	
 	
 mem_error:
 mem_error:
-	LM_ERR("out of shared memory\n");
+	SHM_MEM_ERROR;
 	destroy_failure_route_rule(shm_frr);
 	destroy_failure_route_rule(shm_frr);
 	return NULL;
 	return NULL;
 }
 }

+ 21 - 8
modules/carrierroute/db_carrierroute.c

@@ -62,14 +62,23 @@ str carrierfailureroute_description_col = str_init("description");
 /* table version */
 /* table version */
 const unsigned int carrierfailureroute_version = 1;
 const unsigned int carrierfailureroute_version = 1;
 
 
-str route_tree_table = str_init("route_tree");
+str carrier_name_table = str_init("carrier_name");
 
 
 /* column names */
 /* column names */
-str route_tree_id_col = str_init("id");
-str route_tree_carrier_col = str_init("carrier");
+str carrier_name_id_col = str_init("id");
+str carrier_name_carrier_col = str_init("carrier");
 
 
 /* table version */
 /* table version */
-const unsigned int route_tree_version = 1;
+const unsigned int carrier_name_version = 1;
+
+str domain_name_table = str_init("domain_name");
+
+/* column names */
+str domain_name_id_col = str_init("id");
+str domain_name_domain_col = str_init("domain");
+
+/* table version */
+const unsigned int domain_name_version = 1;
 
 
 
 
 /*
 /*
@@ -105,7 +114,8 @@ int carrierroute_db_init(void) {
 	if (
 	if (
 	(db_check_table_version(&carrierroute_dbf, carrierroute_dbh, &carrierroute_table, carrierroute_version) < 0) ||
 	(db_check_table_version(&carrierroute_dbf, carrierroute_dbh, &carrierroute_table, carrierroute_version) < 0) ||
 	(db_check_table_version(&carrierroute_dbf, carrierroute_dbh, &carrierfailureroute_table, carrierfailureroute_version) < 0) ||
 	(db_check_table_version(&carrierroute_dbf, carrierroute_dbh, &carrierfailureroute_table, carrierfailureroute_version) < 0) ||
-	(db_check_table_version(&carrierroute_dbf, carrierroute_dbh, &route_tree_table, route_tree_version) < 0)
+	(db_check_table_version(&carrierroute_dbf, carrierroute_dbh, &carrier_name_table, carrier_name_version) < 0) ||
+	(db_check_table_version(&carrierroute_dbf, carrierroute_dbh, &domain_name_table, domain_name_version) < 0)
 	) {
 	) {
 		LM_ERR("during table version check.\n");
 		LM_ERR("during table version check.\n");
 		carrierroute_db_close();
 		carrierroute_db_close();
@@ -165,8 +175,11 @@ void carrierroute_db_vars(void) {
 	carrierfailureroute_mask_col.len = strlen(carrierfailureroute_mask_col.s);
 	carrierfailureroute_mask_col.len = strlen(carrierfailureroute_mask_col.s);
 	carrierfailureroute_next_domain_col.len = strlen(carrierfailureroute_next_domain_col.s);
 	carrierfailureroute_next_domain_col.len = strlen(carrierfailureroute_next_domain_col.s);
 	carrierfailureroute_description_col.len = strlen(carrierfailureroute_description_col.s);
 	carrierfailureroute_description_col.len = strlen(carrierfailureroute_description_col.s);
-	route_tree_table.len = strlen(route_tree_table.s);
-	route_tree_id_col.len = strlen(route_tree_id_col.s);
-	route_tree_carrier_col.len = strlen(route_tree_carrier_col.s);
+	carrier_name_table.len = strlen(carrier_name_table.s);
+	carrier_name_id_col.len = strlen(carrier_name_id_col.s);
+	carrier_name_carrier_col.len = strlen(carrier_name_carrier_col.s);
+	domain_name_table.len = strlen(domain_name_table.s);
+	domain_name_id_col.len = strlen(domain_name_id_col.s);
+	domain_name_domain_col.len = strlen(domain_name_domain_col.s);
 }
 }
 
 

+ 22 - 8
modules/carrierroute/db_carrierroute.h

@@ -101,19 +101,33 @@ extern str carrierfailureroute_description_col;
 /* table version */
 /* table version */
 extern const unsigned int carrierfailureroute_version;
 extern const unsigned int carrierfailureroute_version;
 
 
-#define route_tree_DB_TABLE { "route_tree_table", STR_PARAM, &carrierroute_table.s },
+#define carrier_name_DB_TABLE { "carrier_name_table", STR_PARAM, &carrierroute_table.s },
 
 
-extern str route_tree_table;
+extern str carrier_name_table;
 
 
 /* column names */
 /* column names */
-extern str route_tree_id_col;
-extern str route_tree_carrier_col;
-#define route_tree_DB_COLS \
-{ "route_tree_id_col", STR_PARAM, &route_tree_id_col.s }, \
-{ "route_tree_carrier_col", STR_PARAM, &route_tree_carrier_col.s }, \
+extern str carrier_name_id_col;
+extern str carrier_name_carrier_col;
+#define carrier_name_DB_COLS \
+{ "carrier_name_id_col", STR_PARAM, &carrier_name_id_col.s }, \
+{ "carrier_name_carrier_col", STR_PARAM, &carrier_name_carrier_col.s }, \
 
 
 /* table version */
 /* table version */
-extern const unsigned int route_tree_version;
+extern const unsigned int carrier_name_version;
+
+#define domain_name_DB_TABLE { "domain_name_table", STR_PARAM, &carrierroute_table.s },
+
+extern str domain_name_table;
+
+/* column names */
+extern str domain_name_id_col;
+extern str domain_name_domain_col;
+#define domain_name_DB_COLS \
+{ "domain_name_id_col", STR_PARAM, &domain_name_id_col.s }, \
+{ "domain_name_domain_col", STR_PARAM, &domain_name_domain_col.s }, \
+
+/* table version */
+extern const unsigned int domain_name_version;
 
 
 
 
 /*
 /*

+ 25 - 13
modules/carrierroute/doc/carrierroute_admin.xml

@@ -12,7 +12,7 @@
 		startup. It can uses one routing tree (for one carrier), or if needed for every user
 		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.
 		a different routing tree (unique for each carrier) for number prefix based routing.
 		It supports several route tree domains,	e.g. for failback routes or different routing
 		It supports several route tree domains,	e.g. for failback routes or different routing
-		rules for VoIP and PSTN targets. 
+		rules for VoIP and PSTN targets.
 	</para>
 	</para>
 	<para>
 	<para>
 		Based on the tree, the module decides which number prefixes are forwarded to which
 		Based on the tree, the module decides which number prefixes are forwarded to which
@@ -22,16 +22,18 @@
 	</para>
 	</para>
 	<para>
 	<para>
 		This modules scales up to more than a few million users, and is able to handle
 		This modules scales up to more than a few million users, and is able to handle
-		more than several hundred thousand routing table entries. It should be able to handle
-		more, but this is not that much tested at the moment. In load balancing scenarios the
-		usage of the config file mode is recommended, to avoid the additional complexity that
-		the database driven routing creates.
+		more than several hundred thousand routing table entries. We recieved reports of
+		some setups that used more than a million routing table entries. It also supports
+		a large number of carriers and domains which can be efficiently looked up in most of
+		the cases (see below for more informations). In load balancing scenarios the usage
+		of the config file mode is recommended, to avoid the additional complexity that the
+		database driven routing creates.
 	</para>
 	</para>
 	<para>
 	<para>
-		Routing tables can be reloaded and edited (in config file mode) with the MI 
-		interface, the config file is updated according the changes. This is not 
-		implemented for the db interface, because its easier to do the changes 
-		directly on the db. But the reload and dump functions works of course here 
+		Routing tables can be reloaded and edited (in config file mode) with the MI
+		interface, the config file is updated according the changes. This is not
+		implemented for the db interface, because its easier to do the changes
+		directly on the db. But the reload and dump functions works of course here
 		too.
 		too.
 	</para>
 	</para>
 	<para>
 	<para>
@@ -40,6 +42,16 @@
 		tables in the config file. Further information about these limitations is given
 		tables in the config file. Further information about these limitations is given
 		in later sections. For user based routing or LCR you should use the database mode.
 		in later sections. For user based routing or LCR you should use the database mode.
 	</para>
 	</para>
+	<para>
+		In database mode, this module supports names and IDs for the carriers and domains.
+		When using IDs for the routing functions, efficient binary search is used to find the
+		needed data structures. If you are using constant strings as parameter, these will
+		be converted to IDs during the fixup procedure. However, if you are using AVPs as
+		parameter and they contain strings, this cannot be converted to IDs during the
+		fixup procedure. In that case linear search is performed to find the needed data
+		structures. So from a performance point of view it is better to pass only IDs in
+		AVPs to the routing functions.
+	</para>
 	<para>
 	<para>
 		Basically this module could be used as an replacement for the lcr and the 
 		Basically this module could be used as an replacement for the lcr and the 
 		dispatcher module, if you have certain performance, flexibility and/or 
 		dispatcher module, if you have certain performance, flexibility and/or 
@@ -943,8 +955,8 @@ domain register {
 | 9  |       2 |      0 | 49          |     0 |  0.5 | de-2.carrier2 |
 | 9  |       2 |      0 | 49          |     0 |  0.5 | de-2.carrier2 |
 | 10 |       2 |      0 |             |     0 |    1 | gw.carrier2   |
 | 10 |       2 |      0 |             |     0 |    1 | gw.carrier2   |
 | 11 |       2 |      1 | 49          |     0 |    1 | gw.carrier2   |
 | 11 |       2 |      1 | 49          |     0 |    1 | gw.carrier2   |
-| 12 |       3 |  start | 49          |     0 |    1 | de-gw.default |
-| 13 |       3 |  start |             |     0 |    1 | gw.default    |
+| 12 |       3 |      8 | 49          |     0 |    1 | de-gw.default |
+| 13 |       3 |      8 |             |     0 |    1 | gw.default    |
 +----+---------+--------+-------------+-------+------+---------------+
 +----+---------+--------+-------------+-------+------+---------------+
 ...
 ...
 		</programlisting>
 		</programlisting>
@@ -1003,7 +1015,7 @@ domain register {
 |  1 |      99 |           | 408        |    16 |   16 |             |
 |  1 |      99 |           | 408        |    16 |   16 |             |
 |  2 |      99 | gw1       | 404        |     0 |    0 | 100         |
 |  2 |      99 | gw1       | 404        |     0 |    0 | 100         |
 |  3 |      99 | gw2       | 50.        |     0 |    0 | 100         |
 |  3 |      99 | gw2       | 50.        |     0 |    0 | 100         |
-|  4 |      99 |           | 404        |  2048 | 2112 | asterisk-1  |
+|  4 |      99 |           | 404        |  2048 | 2112 | 101         |
 +----+---------+-----------+------------+-------+------+-------------+
 +----+---------+-----------+------------+-------+------+-------------+
 ...
 ...
 </programlisting>
 </programlisting>
@@ -1023,7 +1035,7 @@ domain register {
 		</para>
 		</para>
 
 
 	<example>
 	<example>
-		<title>Example database content - route_tree table</title>
+		<title>Example database content - carrier_name table</title>
 		<programlisting format="linespecific">
 		<programlisting format="linespecific">
 ...
 ...
 +----+----------+
 +----+----------+

+ 98 - 27
modules/carrierroute/doc/carrierroute_db.xml

@@ -42,7 +42,7 @@ modparam("carrierroute", "carrierroute_table", "carrierroute")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_id_col</varname> (string)</title>
     <title><varname>carrierroute_id_col</varname> (string)</title>
-    <para>unique ID</para>
+    <para>Name of the column contains the unique identifier of a route.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_id_col</varname> parameter</title>
       <title>Set <varname>carrierroute_id_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -66,7 +66,9 @@ modparam("carrierroute", "carrierroute_carrier_col", "carrier")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_domain_col</varname> (string)</title>
     <title><varname>carrierroute_domain_col</varname> (string)</title>
-    <para>This column contains the route domain. Additional domains could be used for example as fallback.</para>
+    <para>This column contains the routing domain id. You can define several routing
+			  domains to have different routing rules. Maybe you use domain 0 for normal routing and
+			  domain 1 if domain 0 failed.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_domain_col</varname> parameter</title>
       <title>Set <varname>carrierroute_domain_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -78,7 +80,11 @@ modparam("carrierroute", "carrierroute_domain_col", "domain")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_scan_prefix_col</varname> (string)</title>
     <title><varname>carrierroute_scan_prefix_col</varname> (string)</title>
-    <para>This column contains the scan prefix, which define the matching portion of a phone number.</para>
+    <para>Name of column contains the scan prefixes. Scan prefixes define
+			  the matching portion of a phone number, e.g. when we have the scan prefixes 49721
+			  and 49, the called number is 49721913740, it matches 49721, because the longest
+			  match is taken. If no prefix matches, the number is not routed. To prevent this,
+			  an empty prefix value of  could be added.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_scan_prefix_col</varname> parameter</title>
       <title>Set <varname>carrierroute_scan_prefix_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -102,7 +108,8 @@ modparam("carrierroute", "carrierroute_flags_col", "flags")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_mask_col</varname> (string)</title>
     <title><varname>carrierroute_mask_col</varname> (string)</title>
-    <para>This column contains the mask that is applied to the message flags before rule matching.</para>
+    <para>This column contains the mask that is applied to the message flags before rule 
+			  matching.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_mask_col</varname> parameter</title>
       <title>Set <varname>carrierroute_mask_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -114,7 +121,20 @@ modparam("carrierroute", "carrierroute_mask_col", "mask")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_prob_col</varname> (string)</title>
     <title><varname>carrierroute_prob_col</varname> (string)</title>
-    <para>Name of column containing the probability. The probability value is used to distribute the traffic between several gateways.</para>
+    <para>
+			  Name of column contains the probability. The probability value is used to
+			  distribute the traffic between several gateways. Let's say 70 % of the
+			  traffic shall be routed to gateway A, the other 30 % shall be routed to
+			  gateway B, we define a rule for gateway A with a prob value of 0.7 and a
+			  rule for gateway B with a prob value of 0.3.
+			  
+			  
+			  If all probabilities for a given prefix, tree and domain don't add to 100%,
+			  the prefix values will be adjusted according the given prob values. E.g. if
+			  three hosts with prob values of 0.5, 0.5 and 0.4 are defined, the resulting
+			  probabilities are 35.714, 35.714 and 28.571%. But its better to choose meaningful
+			  values in the first place because of clarity.
+			  </para>
     <example>
     <example>
       <title>Set <varname>carrierroute_prob_col</varname> parameter</title>
       <title>Set <varname>carrierroute_prob_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -126,7 +146,7 @@ modparam("carrierroute", "carrierroute_prob_col", "prob")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_strip_col</varname> (string)</title>
     <title><varname>carrierroute_strip_col</varname> (string)</title>
-    <para>Name of the column containing the number of digits to be stripped of the userpart of an URI before prepending rewrite_prefix.</para>
+    <para>Name of the column contains the number of digits to be stripped of the userpart of an URI before prepending rewrite_prefix.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_strip_col</varname> parameter</title>
       <title>Set <varname>carrierroute_strip_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -138,7 +158,9 @@ modparam("carrierroute", "carrierroute_strip_col", "strip")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_rewrite_host_col</varname> (string)</title>
     <title><varname>carrierroute_rewrite_host_col</varname> (string)</title>
-    <para>Name of column containing rewrite prefixes. Here you can define a rewrite prefix for the localpart of the SIP URI.</para>
+    <para>Name of column contains the rewrite prefixes. Here you can define a rewrite prefix
+			  for the localpart of the SIP URI. An empty field represents a blacklist entry, anything else
+			  is put as domain part into the Request URI of the SIP message.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_rewrite_host_col</varname> parameter</title>
       <title>Set <varname>carrierroute_rewrite_host_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -150,7 +172,8 @@ modparam("carrierroute", "carrierroute_rewrite_host_col", "rewrite_host")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_rewrite_prefix_col</varname> (string)</title>
     <title><varname>carrierroute_rewrite_prefix_col</varname> (string)</title>
-    <para>Rewrite prefix for the localpart of the SIP URI.</para>
+    <para>Name of column contains the rewrite prefixes. Here you can define a rewrite
+			  prefix for the localpart of the SIP URI.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_rewrite_prefix_col</varname> parameter</title>
       <title>Set <varname>carrierroute_rewrite_prefix_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -162,7 +185,8 @@ modparam("carrierroute", "carrierroute_rewrite_prefix_col", "rewrite_prefix")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_rewrite_suffix_col</varname> (string)</title>
     <title><varname>carrierroute_rewrite_suffix_col</varname> (string)</title>
-    <para>Rewrite suffix for the localpart of the SIP URI.</para>
+    <para>Name of column contains the rewrite suffixes. Here you can define a rewrite
+			  suffix for the localpart of the SIP URI.</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_rewrite_suffix_col</varname> parameter</title>
       <title>Set <varname>carrierroute_rewrite_suffix_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -174,7 +198,8 @@ modparam("carrierroute", "carrierroute_rewrite_suffix_col", "rewrite_suffix")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierroute_description_col</varname> (string)</title>
     <title><varname>carrierroute_description_col</varname> (string)</title>
-    <para>A comment for the route entry, useful for larger routing tables.</para>
+    <para>A comment for the route entry, useful for larger routing tables.
+			  The comment is also displayed by the fifo cmd "cr_dump_routes".</para>
     <example>
     <example>
       <title>Set <varname>carrierroute_description_col</varname> parameter</title>
       <title>Set <varname>carrierroute_description_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -201,7 +226,7 @@ modparam("carrierroute", "carrierfailureroute_table", "carrierfailureroute")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierfailureroute_id_col</varname> (string)</title>
     <title><varname>carrierfailureroute_id_col</varname> (string)</title>
-    <para>unique ID</para>
+    <para>This column contains the unique identifier of a failure route.</para>
     <example>
     <example>
       <title>Set <varname>carrierfailureroute_id_col</varname> parameter</title>
       <title>Set <varname>carrierfailureroute_id_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -225,7 +250,9 @@ modparam("carrierroute", "carrierfailureroute_carrier_col", "carrier")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierfailureroute_domain_col</varname> (string)</title>
     <title><varname>carrierfailureroute_domain_col</varname> (string)</title>
-    <para>This column contains the route domain. Additional domains could be used for example as fallback.</para>
+    <para>This column contains the routing domain id. You can define several routing domains
+			  to have different routing rules. Maybe you use domain 0 for normal routing and domain 1 if
+			  domain 0 failed.</para>
     <example>
     <example>
       <title>Set <varname>carrierfailureroute_domain_col</varname> parameter</title>
       <title>Set <varname>carrierfailureroute_domain_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -237,7 +264,11 @@ modparam("carrierroute", "carrierfailureroute_domain_col", "domain")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierfailureroute_scan_prefix_col</varname> (string)</title>
     <title><varname>carrierfailureroute_scan_prefix_col</varname> (string)</title>
-    <para>This column contains the scan prefix, which define the matching portion of a phone number.</para>
+    <para>Name of column contains the the scan prefixes. Scan prexies define the matching
+			  portion of a phone number, e.g. we have the scan prefixes 49721 and 49, the called number is
+			  49721913740, it matches 49721, because the longest match is taken. If no prefix matches,
+			  the number is not failure routed. To prevent this, an empty prefix value of 
+			  could be added.</para>
     <example>
     <example>
       <title>Set <varname>carrierfailureroute_scan_prefix_col</varname> parameter</title>
       <title>Set <varname>carrierfailureroute_scan_prefix_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -249,7 +280,8 @@ modparam("carrierroute", "carrierfailureroute_scan_prefix_col", "scan_prefix")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierfailureroute_host_name_col</varname> (string)</title>
     <title><varname>carrierfailureroute_host_name_col</varname> (string)</title>
-    <para>This column contains the routing destination used for rule matching.</para>
+    <para>Name of the column containing the host name of the last routing destination,
+			  using for rules matching.</para>
     <example>
     <example>
       <title>Set <varname>carrierfailureroute_host_name_col</varname> parameter</title>
       <title>Set <varname>carrierfailureroute_host_name_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -297,7 +329,7 @@ modparam("carrierroute", "carrierfailureroute_mask_col", "mask")
   </section>
   </section>
   <section>
   <section>
     <title><varname>carrierfailureroute_next_domain_col</varname> (string)</title>
     <title><varname>carrierfailureroute_next_domain_col</varname> (string)</title>
-    <para>This column contains the route domain that should be used for the next routing attempt.</para>
+    <para>This column contains the route domain id that should be used for the next routing attempt.</para>
     <example>
     <example>
       <title>Set <varname>carrierfailureroute_next_domain_col</varname> parameter</title>
       <title>Set <varname>carrierfailureroute_next_domain_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
@@ -320,40 +352,79 @@ modparam("carrierroute", "carrierfailureroute_description_col", "description")
     </example>
     </example>
   </section>
   </section>
   <section>
   <section>
-    <title><varname>route_tree_table</varname> (String)</title>
-    <para>Name of the route_tree table for the carrierroute module.</para>
+    <title><varname>carrier_name_table</varname> (String)</title>
+    <para>Name of the carrier_name table for the carrierroute module.</para>
     <para>
     <para>
-      <emphasis>Default value is <quote>route_tree</quote>.</emphasis>
+      <emphasis>Default value is <quote>carrier_name</quote>.</emphasis>
     </para>
     </para>
     <example>
     <example>
-      <title>Set <varname>route_tree_table</varname> parameter</title>
+      <title>Set <varname>carrier_name_table</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
 ...
 ...
-modparam("carrierroute", "route_tree_table", "route_tree")
+modparam("carrierroute", "carrier_name_table", "carrier_name")
 ...
 ...
 </programlisting>
 </programlisting>
     </example>
     </example>
   </section>
   </section>
   <section>
   <section>
-    <title><varname>route_tree_id_col</varname> (string)</title>
-    <para>unique ID</para>
+    <title><varname>carrier_name_id_col</varname> (string)</title>
+    <para>Name of the column containing the unique identifier of a carrier.</para>
     <example>
     <example>
-      <title>Set <varname>route_tree_id_col</varname> parameter</title>
+      <title>Set <varname>carrier_name_id_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
 ...
 ...
-modparam("carrierroute", "route_tree_id_col", "id")
+modparam("carrierroute", "carrier_name_id_col", "id")
 ...
 ...
 </programlisting>
 </programlisting>
     </example>
     </example>
   </section>
   </section>
   <section>
   <section>
-    <title><varname>route_tree_carrier_col</varname> (string)</title>
+    <title><varname>carrier_name_carrier_col</varname> (string)</title>
     <para>This column contains the carrier name.</para>
     <para>This column contains the carrier name.</para>
     <example>
     <example>
-      <title>Set <varname>route_tree_carrier_col</varname> parameter</title>
+      <title>Set <varname>carrier_name_carrier_col</varname> parameter</title>
+      <programlisting format="linespecific">
+...
+modparam("carrierroute", "carrier_name_carrier_col", "carrier")
+...
+</programlisting>
+    </example>
+  </section>
+  <section>
+    <title><varname>domain_name_table</varname> (String)</title>
+    <para>Name of the domain_name table for the carrierroute module.</para>
+    <para>
+      <emphasis>Default value is <quote>domain_name</quote>.</emphasis>
+    </para>
+    <example>
+      <title>Set <varname>domain_name_table</varname> parameter</title>
+      <programlisting format="linespecific">
+...
+modparam("carrierroute", "domain_name_table", "domain_name")
+...
+</programlisting>
+    </example>
+  </section>
+  <section>
+    <title><varname>domain_name_id_col</varname> (string)</title>
+    <para>Name of the column containing the unique identifier of a domain.</para>
+    <example>
+      <title>Set <varname>domain_name_id_col</varname> parameter</title>
+      <programlisting format="linespecific">
+...
+modparam("carrierroute", "domain_name_id_col", "id")
+...
+</programlisting>
+    </example>
+  </section>
+  <section>
+    <title><varname>domain_name_domain_col</varname> (string)</title>
+    <para>This column contains the domain name.</para>
+    <example>
+      <title>Set <varname>domain_name_domain_col</varname> parameter</title>
       <programlisting format="linespecific">
       <programlisting format="linespecific">
 ...
 ...
-modparam("carrierroute", "route_tree_carrier_col", "carrier")
+modparam("carrierroute", "domain_name_domain_col", "domain")
 ...
 ...
 </programlisting>
 </programlisting>
     </example>
     </example>