Browse code

- 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 authored on 12/11/2008 15:53:01
Showing 22 changed files
... ...
@@ -96,9 +96,12 @@ Henning Westerholt
96 96
         2.23. carrierfailureroute_mask_col (string)
97 97
         2.24. carrierfailureroute_next_domain_col (string)
98 98
         2.25. carrierfailureroute_description_col (string)
99
-        2.26. route_tree_table (String)
100
-        2.27. route_tree_id_col (string)
101
-        2.28. route_tree_carrier_col (string)
99
+        2.26. carrier_name_table (String)
100
+        2.27. carrier_name_id_col (string)
101
+        2.28. carrier_name_carrier_col (string)
102
+        2.29. domain_name_table (String)
103
+        2.30. domain_name_id_col (string)
104
+        2.31. domain_name_domain_col (string)
102 105
 
103 106
    List of Examples
104 107
 
... ...
@@ -127,7 +130,7 @@ Henning Westerholt
127 127
    1.21. Example database content - more complex
128 128
           carrierfailureroute table
129 129
 
130
-   1.22. Example database content - route_tree table
130
+   1.22. Example database content - carrier_name table
131 131
    1.23. Necessary extensions for the user table
132 132
    2.1. Set db_url parameter
133 133
    2.2. Set carrierroute_table parameter
... ...
@@ -154,9 +157,12 @@ Henning Westerholt
154 154
    2.23. Set carrierfailureroute_mask_col parameter
155 155
    2.24. Set carrierfailureroute_next_domain_col parameter
156 156
    2.25. Set carrierfailureroute_description_col parameter
157
-   2.26. Set route_tree_table parameter
158
-   2.27. Set route_tree_id_col parameter
159
-   2.28. Set route_tree_carrier_col parameter
157
+   2.26. Set carrier_name_table parameter
158
+   2.27. Set carrier_name_id_col parameter
159
+   2.28. Set carrier_name_carrier_col parameter
160
+   2.29. Set domain_name_table parameter
161
+   2.30. Set domain_name_id_col parameter
162
+   2.31. Set domain_name_domain_col parameter
160 163
 
161 164
 Chapter 1. Admin Guide
162 165
 
... ...
@@ -183,10 +189,13 @@ Chapter 1. Admin Guide
183 183
 
184 184
    This modules scales up to more than a few million users, and is
185 185
    able to handle more than several hundred thousand routing table
186
-   entries. It should be able to handle more, but this is not that
187
-   much tested at the moment. In load balancing scenarios the
188
-   usage of the config file mode is recommended, to avoid the
189
-   additional complexity that the database driven routing creates.
186
+   entries. We recieved reports of some setups that used more than
187
+   a million routing table entries. It also supports a large
188
+   number of carriers and domains which can be efficiently looked
189
+   up in most of the cases (see below for more informations). In
190
+   load balancing scenarios the usage of the config file mode is
191
+   recommended, to avoid the additional complexity that the
192
+   database driven routing creates.
190 193
 
191 194
    Routing tables can be reloaded and edited (in config file mode)
192 195
    with the MI interface, the config file is updated according the
... ...
@@ -201,6 +210,17 @@ Chapter 1. Admin Guide
201 201
    sections. For user based routing or LCR you should use the
202 202
    database mode.
203 203
 
204
+   In database mode, this module supports names and IDs for the
205
+   carriers and domains. When using IDs for the routing functions,
206
+   efficient binary search is used to find the needed data
207
+   structures. If you are using constant strings as parameter,
208
+   these will be converted to IDs during the fixup procedure.
209
+   However, if you are using AVPs as parameter and they contain
210
+   strings, this cannot be converted to IDs during the fixup
211
+   procedure. In that case linear search is performed to find the
212
+   needed data structures. So from a performance point of view it
213
+   is better to pass only IDs in AVPs to the routing functions.
214
+
204 215
    Basically this module could be used as an replacement for the
205 216
    lcr and the dispatcher module, if you have certain performance,
206 217
    flexibility and/or integration requirements that these modules
... ...
@@ -800,8 +820,8 @@ domain register {
800 800
 | 9  |       2 |      0 | 49          |     0 |  0.5 | de-2.carrier2 |
801 801
 | 10 |       2 |      0 |             |     0 |    1 | gw.carrier2   |
802 802
 | 11 |       2 |      1 | 49          |     0 |    1 | gw.carrier2   |
803
-| 12 |       3 |  start | 49          |     0 |    1 | de-gw.default |
804
-| 13 |       3 |  start |             |     0 |    1 | gw.default    |
803
+| 12 |       3 |      8 | 49          |     0 |    1 | de-gw.default |
804
+| 13 |       3 |      8 |             |     0 |    1 | gw.default    |
805 805
 +----+---------+--------+-------------+-------+------+---------------+
806 806
 ...
807 807
 
... ...
@@ -854,7 +874,7 @@ domain register {
854 854
 |  1 |      99 |           | 408        |    16 |   16 |             |
855 855
 |  2 |      99 | gw1       | 404        |     0 |    0 | 100         |
856 856
 |  3 |      99 | gw2       | 50.        |     0 |    0 | 100         |
857
-|  4 |      99 |           | 404        |  2048 | 2112 | asterisk-1  |
857
+|  4 |      99 |           | 404        |  2048 | 2112 | 101         |
858 858
 +----+---------+-----------+------------+-------+------+-------------+
859 859
 ...
860 860
 
... ...
@@ -872,7 +892,7 @@ domain register {
872 872
    holds domain entries for this routing rules. Not all table
873 873
    colums are show here for brevity.
874 874
 
875
-   Example 1.22. Example database content - route_tree table
875
+   Example 1.22. Example database content - carrier_name table
876 876
 ...
877 877
 +----+----------+
878 878
 | id | carrier  |
... ...
@@ -926,7 +946,7 @@ modparam("carrierroute", "carrierroute_table", "carrierroute")
926 926
 
927 927
 2.3. carrierroute_id_col (string)
928 928
 
929
-   unique ID
929
+   Name of the column contains the unique identifier of a route.
930 930
 
931 931
    Example 2.3. Set carrierroute_id_col parameter
932 932
 ...
... ...
@@ -944,8 +964,10 @@ modparam("carrierroute", "carrierroute_carrier_col", "carrier")
944 944
 
945 945
 2.5. carrierroute_domain_col (string)
946 946
 
947
-   This column contains the route domain. Additional domains could
948
-   be used for example as fallback.
947
+   This column contains the routing domain id. You can define
948
+   several routing domains to have different routing rules. Maybe
949
+   you use domain 0 for normal routing and domain 1 if domain 0
950
+   failed.
949 951
 
950 952
    Example 2.5. Set carrierroute_domain_col parameter
951 953
 ...
... ...
@@ -954,8 +976,12 @@ modparam("carrierroute", "carrierroute_domain_col", "domain")
954 954
 
955 955
 2.6. carrierroute_scan_prefix_col (string)
956 956
 
957
-   This column contains the scan prefix, which define the matching
958
-   portion of a phone number.
957
+   Name of column contains the scan prefixes. Scan prefixes define
958
+   the matching portion of a phone number, e.g. when we have the
959
+   scan prefixes 49721 and 49, the called number is 49721913740,
960
+   it matches 49721, because the longest match is taken. If no
961
+   prefix matches, the number is not routed. To prevent this, an
962
+   empty prefix value of could be added.
959 963
 
960 964
    Example 2.6. Set carrierroute_scan_prefix_col parameter
961 965
 ...
... ...
@@ -983,9 +1009,18 @@ modparam("carrierroute", "carrierroute_mask_col", "mask")
983 983
 
984 984
 2.9. carrierroute_prob_col (string)
985 985
 
986
-   Name of column containing the probability. The probability
987
-   value is used to distribute the traffic between several
988
-   gateways.
986
+   Name of column contains the probability. The probability value
987
+   is used to distribute the traffic between several gateways.
988
+   Let's say 70 % of the traffic shall be routed to gateway A, the
989
+   other 30 % shall be routed to gateway B, we define a rule for
990
+   gateway A with a prob value of 0.7 and a rule for gateway B
991
+   with a prob value of 0.3. If all probabilities for a given
992
+   prefix, tree and domain don't add to 100%, the prefix values
993
+   will be adjusted according the given prob values. E.g. if three
994
+   hosts with prob values of 0.5, 0.5 and 0.4 are defined, the
995
+   resulting probabilities are 35.714, 35.714 and 28.571%. But its
996
+   better to choose meaningful values in the first place because
997
+   of clarity.
989 998
 
990 999
    Example 2.9. Set carrierroute_prob_col parameter
991 1000
 ...
... ...
@@ -994,9 +1029,8 @@ modparam("carrierroute", "carrierroute_prob_col", "prob")
994 994
 
995 995
 2.10. carrierroute_strip_col (string)
996 996
 
997
-   Name of the column containing the number of digits to be
998
-   stripped of the userpart of an URI before prepending
999
-   rewrite_prefix.
997
+   Name of the column contains the number of digits to be stripped
998
+   of the userpart of an URI before prepending rewrite_prefix.
1000 999
 
1001 1000
    Example 2.10. Set carrierroute_strip_col parameter
1002 1001
 ...
... ...
@@ -1005,8 +1039,10 @@ modparam("carrierroute", "carrierroute_strip_col", "strip")
1005 1005
 
1006 1006
 2.11. carrierroute_rewrite_host_col (string)
1007 1007
 
1008
-   Name of column containing rewrite prefixes. Here you can define
1009
-   a rewrite prefix for the localpart of the SIP URI.
1008
+   Name of column contains the rewrite prefixes. Here you can
1009
+   define a rewrite prefix for the localpart of the SIP URI. An
1010
+   empty field represents a blacklist entry, anything else is put
1011
+   as domain part into the Request URI of the SIP message.
1010 1012
 
1011 1013
    Example 2.11. Set carrierroute_rewrite_host_col parameter
1012 1014
 ...
... ...
@@ -1016,7 +1052,8 @@ modparam("carrierroute", "carrierroute_rewrite_host_col", "rewrite_host"
1016 1016
 
1017 1017
 2.12. carrierroute_rewrite_prefix_col (string)
1018 1018
 
1019
-   Rewrite prefix for the localpart of the SIP URI.
1019
+   Name of column contains the rewrite prefixes. Here you can
1020
+   define a rewrite prefix for the localpart of the SIP URI.
1020 1021
 
1021 1022
    Example 2.12. Set carrierroute_rewrite_prefix_col parameter
1022 1023
 ...
... ...
@@ -1026,7 +1063,8 @@ fix")
1026 1026
 
1027 1027
 2.13. carrierroute_rewrite_suffix_col (string)
1028 1028
 
1029
-   Rewrite suffix for the localpart of the SIP URI.
1029
+   Name of column contains the rewrite suffixes. Here you can
1030
+   define a rewrite suffix for the localpart of the SIP URI.
1030 1031
 
1031 1032
    Example 2.13. Set carrierroute_rewrite_suffix_col parameter
1032 1033
 ...
... ...
@@ -1037,7 +1075,8 @@ fix")
1037 1037
 2.14. carrierroute_description_col (string)
1038 1038
 
1039 1039
    A comment for the route entry, useful for larger routing
1040
-   tables.
1040
+   tables. The comment is also displayed by the fifo cmd
1041
+   "cr_dump_routes".
1041 1042
 
1042 1043
    Example 2.14. Set carrierroute_description_col parameter
1043 1044
 ...
... ...
@@ -1059,7 +1098,7 @@ te")
1059 1059
 
1060 1060
 2.16. carrierfailureroute_id_col (string)
1061 1061
 
1062
-   unique ID
1062
+   This column contains the unique identifier of a failure route.
1063 1063
 
1064 1064
    Example 2.16. Set carrierfailureroute_id_col parameter
1065 1065
 ...
... ...
@@ -1077,8 +1116,10 @@ modparam("carrierroute", "carrierfailureroute_carrier_col", "carrier")
1077 1077
 
1078 1078
 2.18. carrierfailureroute_domain_col (string)
1079 1079
 
1080
-   This column contains the route domain. Additional domains could
1081
-   be used for example as fallback.
1080
+   This column contains the routing domain id. You can define
1081
+   several routing domains to have different routing rules. Maybe
1082
+   you use domain 0 for normal routing and domain 1 if domain 0
1083
+   failed.
1082 1084
 
1083 1085
    Example 2.18. Set carrierfailureroute_domain_col parameter
1084 1086
 ...
... ...
@@ -1087,8 +1128,12 @@ modparam("carrierroute", "carrierfailureroute_domain_col", "domain")
1087 1087
 
1088 1088
 2.19. carrierfailureroute_scan_prefix_col (string)
1089 1089
 
1090
-   This column contains the scan prefix, which define the matching
1091
-   portion of a phone number.
1090
+   Name of column contains the the scan prefixes. Scan prexies
1091
+   define the matching portion of a phone number, e.g. we have the
1092
+   scan prefixes 49721 and 49, the called number is 49721913740,
1093
+   it matches 49721, because the longest match is taken. If no
1094
+   prefix matches, the number is not failure routed. To prevent
1095
+   this, an empty prefix value of could be added.
1092 1096
 
1093 1097
    Example 2.19. Set carrierfailureroute_scan_prefix_col parameter
1094 1098
 ...
... ...
@@ -1098,8 +1143,8 @@ efix")
1098 1098
 
1099 1099
 2.20. carrierfailureroute_host_name_col (string)
1100 1100
 
1101
-   This column contains the routing destination used for rule
1102
-   matching.
1101
+   Name of the column containing the host name of the last routing
1102
+   destination, using for rules matching.
1103 1103
 
1104 1104
    Example 2.20. Set carrierfailureroute_host_name_col parameter
1105 1105
 ...
... ...
@@ -1138,8 +1183,8 @@ modparam("carrierroute", "carrierfailureroute_mask_col", "mask")
1138 1138
 
1139 1139
 2.24. carrierfailureroute_next_domain_col (string)
1140 1140
 
1141
-   This column contains the route domain that should be used for
1142
-   the next routing attempt.
1141
+   This column contains the route domain id that should be used
1142
+   for the next routing attempt.
1143 1143
 
1144 1144
    Example 2.24. Set carrierfailureroute_next_domain_col parameter
1145 1145
 ...
... ...
@@ -1158,31 +1203,62 @@ modparam("carrierroute", "carrierfailureroute_description_col", "descrip
1158 1158
 tion")
1159 1159
 ...
1160 1160
 
1161
-2.26. route_tree_table (String)
1161
+2.26. carrier_name_table (String)
1162 1162
 
1163
-   Name of the route_tree table for the carrierroute module.
1163
+   Name of the carrier_name table for the carrierroute module.
1164 1164
 
1165
-   Default value is "route_tree".
1165
+   Default value is "carrier_name".
1166 1166
 
1167
-   Example 2.26. Set route_tree_table parameter
1167
+   Example 2.26. Set carrier_name_table parameter
1168 1168
 ...
1169
-modparam("carrierroute", "route_tree_table", "route_tree")
1169
+modparam("carrierroute", "carrier_name_table", "carrier_name")
1170 1170
 ...
1171 1171
 
1172
-2.27. route_tree_id_col (string)
1172
+2.27. carrier_name_id_col (string)
1173 1173
 
1174
-   unique ID
1174
+   Name of the column containing the unique identifier of a
1175
+   carrier.
1175 1176
 
1176
-   Example 2.27. Set route_tree_id_col parameter
1177
+   Example 2.27. Set carrier_name_id_col parameter
1177 1178
 ...
1178
-modparam("carrierroute", "route_tree_id_col", "id")
1179
+modparam("carrierroute", "carrier_name_id_col", "id")
1179 1180
 ...
1180 1181
 
1181
-2.28. route_tree_carrier_col (string)
1182
+2.28. carrier_name_carrier_col (string)
1182 1183
 
1183 1184
    This column contains the carrier name.
1184 1185
 
1185
-   Example 2.28. Set route_tree_carrier_col parameter
1186
+   Example 2.28. Set carrier_name_carrier_col parameter
1187
+...
1188
+modparam("carrierroute", "carrier_name_carrier_col", "carrier")
1189
+...
1190
+
1191
+2.29. domain_name_table (String)
1192
+
1193
+   Name of the domain_name table for the carrierroute module.
1194
+
1195
+   Default value is "domain_name".
1196
+
1197
+   Example 2.29. Set domain_name_table parameter
1198
+...
1199
+modparam("carrierroute", "domain_name_table", "domain_name")
1200
+...
1201
+
1202
+2.30. domain_name_id_col (string)
1203
+
1204
+   Name of the column containing the unique identifier of a
1205
+   domain.
1206
+
1207
+   Example 2.30. Set domain_name_id_col parameter
1208
+...
1209
+modparam("carrierroute", "domain_name_id_col", "id")
1210
+...
1211
+
1212
+2.31. domain_name_domain_col (string)
1213
+
1214
+   This column contains the domain name.
1215
+
1216
+   Example 2.31. Set domain_name_domain_col parameter
1186 1217
 ...
1187
-modparam("carrierroute", "route_tree_carrier_col", "carrier")
1218
+modparam("carrierroute", "domain_name_domain_col", "domain")
1188 1219
 ...
... ...
@@ -98,10 +98,12 @@ static param_export_t params[]= {
98 98
 	carrierroute_DB_URL
99 99
 	carrierroute_DB_TABLE
100 100
 	carrierfailureroute_DB_TABLE
101
-	route_tree_DB_TABLE
101
+	carrier_name_DB_TABLE
102
+	domain_name_DB_TABLE
102 103
 	carrierroute_DB_COLS
103 104
 	carrierfailureroute_DB_COLS
104
-	route_tree_DB_COLS
105
+	carrier_name_DB_COLS
106
+	domain_name_DB_COLS
105 107
 	{"subscriber_table",       STR_PARAM, &subscriber_table.s },
106 108
 	{"subscriber_user_col",    STR_PARAM, &subscriber_username_col.s },
107 109
 	{"subscriber_domain_col",  STR_PARAM, &subscriber_domain_col.s },
... ...
@@ -234,6 +236,4 @@ static void mod_destroy(void) {
234 234
 		carrierroute_db_close();
235 235
 	}
236 236
 	destroy_route_data();
237
-	destroy_domain_map();
238
-	destroy_carrier_map();
239 237
 }
... ...
@@ -27,201 +27,37 @@
27 27
  * - Module; \ref carrierroute
28 28
  */
29 29
 
30
+#include <stdlib.h>
30 31
 #include "../../mem/shm_mem.h"
31 32
 #include "../../ut.h"
32 33
 #include "cr_carrier.h"
33
-#include "carrierroute.h"
34
-#include "cr_rule.h"
35
-#include "cr_config.h"
36
-#include "cr_db.h"
37
-#include "cr_map.h"
38 34
 #include "cr_domain.h"
39
-
40
-
41
-/**
42
- * Adds the given route information to the routing domain identified by
43
- * domain. scan_prefix identifies the number for which the information
44
- * is and the rewrite_* parameters define what to do in case of a match.
45
- * prob gives the probability with which this rule applies if there are
46
- * more than one for a given prefix.
47
- *
48
- * @param rd the route data to which the route shall be added
49
- * @param carrier_id the carrier id of the route to be added
50
- * @param domain the routing domain of the new route
51
- * @param scan_prefix the number prefix
52
- * @param flags user defined flags
53
- * @param mask mask for user defined flags
54
- * @param max_targets the number of targets
55
- * @param prob the weight of the rule
56
- * @param rewrite_hostpart the rewrite_host of the rule
57
- * @param strip the number of digits to be stripped off userpart before prepending prefix
58
- * @param rewrite_local_prefix the rewrite prefix
59
- * @param rewrite_local_suffix the rewrite suffix
60
- * @param status the status of the rule
61
- * @param hash_index the hash index of the rule
62
- * @param backup indicates if the route is backed up by another. only 
63
-                 useful if status==0, if set, it is the hash value
64
-                 of another rule
65
- * @param backed_up an -1-termintated array of hash indices of the route 
66
-                    for which this route is backup
67
- * @param comment a comment for the route rule
68
- *
69
- * @return 0 on success, -1 on error in which case it LOGs a message.
70
- */
71
-int add_route(struct route_data_t * rd, int carrier_id,
72
-		const str * domain, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
73
-		double prob, const str * rewrite_hostpart, int strip,
74
-		const str * rewrite_local_prefix, const str * rewrite_local_suffix,
75
-		int status, int hash_index, int backup, int * backed_up, const str * comment) {
76
-	struct carrier_data_t * carrier_data = NULL;
77
-	struct domain_data_t * domain_data = NULL;
78
-	LM_INFO("adding prefix %.*s, prob %f\n", scan_prefix->len, scan_prefix->s, prob);
79
-
80
-	if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
81
-		LM_ERR("could not retrieve carrier data\n");
82
-		return -1;
83
-	}
84
-
85
-	if ((domain_data = get_domain_data_by_name(carrier_data,domain)) == NULL) {
86
-		LM_ERR("could not retrieve domain data\n");
87
-		return -1;
88
-	}
89
-	LM_INFO("found route, now adding\n");
90
-	return add_route_to_tree(domain_data->tree, scan_prefix, flags, mask, scan_prefix, max_targets, prob, rewrite_hostpart,
91
-	                         strip, rewrite_local_prefix, rewrite_local_suffix, status,
92
-	                         hash_index, backup, backed_up, comment);
93
-}
94
-
95
-
96
-/**
97
- * Adds the given failure route information to the failure routing domain identified by
98
- * domain. scan_prefix, host, reply_code and flags identifies the number for which
99
- * the information is and the next_domain parameter defines where to continue routing
100
- * in case of a match.
101
- *
102
- * @param rd the route data to which the route shall be added
103
- * @param carrier_id the carrier id of the route to be added
104
- * @param domain the routing domain of the new route
105
- * @param scan_prefix the number prefix
106
- * @param host the hostname last tried
107
- * @param reply_code the reply code 
108
- * @param flags user defined flags
109
- * @param mask for user defined flags
110
- * @param next_domain continue routing with this domain
111
- * @param comment a comment for the failure route rule
112
- *
113
- * @return 0 on success, -1 on error in which case it LOGs a message.
114
- */
115
-int add_failure_route(struct route_data_t * rd, int carrier_id, const str * domain,
116
-		const str * scan_prefix, const str * host, const str * reply_code,
117
-		flag_t flags, flag_t mask, const str * next_domain, const str * comment) {
118
-	int next_domain_id;
119
-	struct carrier_data_t * carrier_data = NULL;
120
-	struct domain_data_t * domain_data = NULL;
121
-	LM_INFO("adding prefix %.*s, reply code %.*s\n", scan_prefix->len, scan_prefix->s, reply_code->len, reply_code->s);
122
-		
123
-	if (reply_code->len!=3) {
124
-		LM_ERR("invalid reply_code '%.*s'!\n", reply_code->len, reply_code->s);
125
-		return -1;
126
-	}
127
-	
128
-	if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
129
-		LM_ERR("could not retrieve carrier data\n");
130
-		return -1;
131
-	}
132
-	
133
-	if ((domain_data = get_domain_data_by_name(carrier_data, domain)) == NULL) {
134
-		LM_ERR("could not retrieve domain data\n");
135
-		return -1;
136
-	}
137
-
138
-	if ((next_domain_id = add_domain(next_domain)) < 0) {
139
-		LM_ERR("add_domain failed\n");
140
-		return -1;
141
-	}
142
-	
143
-	LM_INFO("found failure route, now adding\n");
144
-	return add_failure_route_to_tree(domain_data->failure_tree, scan_prefix, scan_prefix, host, reply_code,
145
-			flags, mask, next_domain_id, comment);
146
-}
147
-
148
-
149
-/**
150
- * adds a carrier_data struct for given carrier
151
- *
152
- * @param rd route data to be searched
153
- * @param carrier the name of desired carrier
154
- * @param carrier_id the id of the carrier
155
- * @param domains number of domains for that carrier
156
- *
157
- * @return a pointer to the root node of the desired routing tree,
158
- * NULL on failure
159
- */
160
-struct carrier_data_t * add_carrier_data(struct route_data_t * rd, const str * carrier, int carrier_id, int domains) {
161
-	int i, index;
162
-	if (!rd) {
163
-		LM_ERR("NULL pointer in parameter\n");
164
-		return NULL;
165
-	}
166
-	LM_INFO("add carrier %.*s\n", carrier->len, carrier->s);
167
-	for (i=0; i<rd->carrier_num; i++) {
168
-		if (rd->carriers[i]) {
169
-			if (rd->carriers[i]->id == carrier_id) {
170
-				LM_INFO("found carrier %i: %.*s\n", rd->carriers[i]->id, rd->carriers[i]->name.len, rd->carriers[i]->name.s);
171
-				return rd->carriers[i];
172
-			}
173
-		}
174
-	}
175
-	LM_INFO("carrier %.*s not found, add it\n", carrier->len, carrier->s);
176
-	if ((index = add_carrier(carrier, carrier_id)) < 0) {
177
-		LM_ERR("could not add carrier\n");
178
-		return NULL;
179
-	}
180
-	if (index > rd->carrier_num) {
181
-		LM_ERR("weird: to large tree index\n");
182
-		return NULL;
183
-	}
184
-	if ((rd->carriers[index] = create_carrier_data(carrier, carrier_id, index, domains)) == NULL) {
185
-		return NULL;
186
-	}
187
-	rd->carriers[index]->index = index;
188
-	LM_INFO("created carrier data: %.*s, with id %i and %ld domains\n", 
189
-		rd->carriers[index]->name.len, rd->carriers[index]->name.s, rd->carriers[index]->id, 
190
-		(long)rd->carriers[index]->domain_num);
191
-	return rd->carriers[index];
192
-}
35
+#include "cr_map.h"
193 36
 
194 37
 
195 38
 /**
196 39
  * Create a new carrier_data struct in shared memory and set it up.
197 40
  *
198
- * @param carrier_name the name of the carrier
199 41
  * @param carrier_id id of carrier
200
- * @param index the index for that carrier
42
+ * @param carrier_name pointer to the name of the carrier
201 43
  * @param domains number of domains for that carrier
202 44
  *
203 45
  * @return a pointer to the newly allocated carrier data or NULL on
204 46
  * error, in which case it LOGs an error message.
205 47
  */
206
-struct carrier_data_t * create_carrier_data(const str *carrier_name, int carrier_id, int index, int domains) {
48
+struct carrier_data_t * create_carrier_data(int carrier_id, str *carrier_name, int domains) {
207 49
 	struct carrier_data_t * tmp;
208 50
 	if ((tmp = shm_malloc(sizeof(struct carrier_data_t))) == NULL) {
209
-		LM_ERR("out of shared memory\n");
51
+		SHM_MEM_ERROR;
210 52
 		return NULL;
211 53
 	}
212 54
 	memset(tmp, 0, sizeof(struct carrier_data_t));
213
-	if (shm_str_dup(&tmp->name, carrier_name)!=0) {
214
-		LM_ERR("cannot duplicate string\n");
215
-		shm_free(tmp);
216
-		return NULL;
217
-	}
218 55
 	tmp->id = carrier_id;
219
-	tmp->index = index;
56
+	tmp->name = carrier_name;
220 57
 	tmp->domain_num = domains;
221 58
 	if(domains > 0){
222 59
 		if ((tmp->domains = shm_malloc(sizeof(struct domain_data_t *) * domains)) == NULL) {
223
-			LM_ERR("out of shared memory\n");
224
-			shm_free(tmp->name.s);
60
+			SHM_MEM_ERROR;
225 61
 			shm_free(tmp);
226 62
 			return NULL;
227 63
 		}
... ...
@@ -232,253 +68,103 @@ struct carrier_data_t * create_carrier_data(const str *carrier_name, int carrier
232 232
 
233 233
 
234 234
 /**
235
- * returns the routing tree for the given domain, if domain's tree
236
- * doesnt exist, it will be created. If the trees are completely
237
- * filled and a not existing domain shall be added, an error is
238
- * returned
235
+ * Destroys the given carrier and frees the used memory.
239 236
  *
240
- * @param rd route data to be searched
241
- * @param carrier_id the id of the desired carrier
242
- *
243
- * @return a pointer to the root node of the desired routing tree,
244
- * NULL on failure
237
+ * @param carrier_data the structure to be destroyed.
245 238
  */
246
-struct carrier_data_t *get_carrier_data(struct route_data_t * rd, int carrier_id) {
247
-	int i;
248
-	if (!rd) {
249
-		LM_ERR("NULL pointer in parameter\n");
250
-		return NULL;
251
-	}
252
-	for (i=0; i<rd->carrier_num; i++) {
253
-		if (rd->carriers[i]->id == carrier_id) {
254
-			return rd->carriers[i];
255
-		}
256
-	}
257
-	return NULL;
258
-}
259
-
260
-
261
-static int add_domain_data(struct carrier_data_t * carrier_data, struct domain_data_t * domain_data) {
239
+void destroy_carrier_data(struct carrier_data_t *carrier_data) {
262 240
 	int i;
263
-	LM_INFO("tree %.*s has %ld trees\n",
264
-			carrier_data->name.len, carrier_data->name.s, (long)carrier_data->domain_num);
265
-	for (i=0; i<carrier_data->domain_num; i++) {
266
-		LM_DBG("tree %p", carrier_data->domains[i]);
267
-		if (carrier_data->domains[i] == 0) {
268
-			carrier_data->domains[i] = domain_data;
269
-			return 0;
241
+	if (carrier_data) {
242
+		if (carrier_data->domains != NULL) {
243
+			for (i=0; i<carrier_data->domain_num; i++) {
244
+				destroy_domain_data(carrier_data->domains[i]);
245
+			}
246
+			shm_free(carrier_data->domains);
270 247
 		}
248
+		shm_free(carrier_data);
271 249
 	}
272
-	return -1;
273 250
 }
274 251
 
275 252
 
276 253
 /**
277
- * Returns the domain data for the given name. If it doesnt exist,
278
- * it will be created. If the domain list is completely
279
- * filled and a not existing domain shall be added, an error is
280
- * returned
254
+ * Adds a domain_data struct to the given carrier data structure at the given index.
255
+ * Other etries are moved one position up to make space for the new one.
281 256
  *
282
- * @param carrier_data carrier data to be searched
283
- * @param domain the name of desired domain
257
+ * @param carrier_data the carrier data struct where domain_data should be inserted
258
+ * @param domain_data the domain data struct to be inserted
259
+ * @param index the index where to insert the domain_data structure in the domain array
284 260
  *
285
- * @return a pointer to the desired domain data, NULL on failure.
261
+ * @return 0 on success, -1 on failure
286 262
  */
287
-struct domain_data_t *get_domain_data_by_name(struct carrier_data_t * carrier_data, const str * domain) {
288
-	int i, id;
289
-	struct domain_data_t * domain_data = NULL;
290
-	if (!carrier_data) {
291
-		LM_ERR("NULL pointer in parameter\n");
292
-		return NULL;
293
-	}
294
-	for (i=0; i<carrier_data->domain_num; i++) {
295
-		if (carrier_data->domains[i] && carrier_data->domains[i]->name.s) {
296
-			if (str_strcmp(&carrier_data->domains[i]->name, domain) == 0) {
297
-				LM_INFO("found domain %.*s\n", carrier_data->domains[i]->name.len, carrier_data->domains[i]->name.s);
298
-				return carrier_data->domains[i];
299
-			}
300
-		}
301
-	}
302
-	LM_INFO("domain %.*s not found, add it\n", domain->len, domain->s);
303
-	if ((id = add_domain(domain)) < 0) {
304
-		LM_ERR("could not add domain\n");
305
-		return NULL;
306
-	}
307
-	if ((domain_data = create_domain_data(domain, id)) == NULL) {
308
-		return NULL;
263
+int add_domain_data(struct carrier_data_t * carrier_data, struct domain_data_t * domain_data, int index) {
264
+	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);
265
+ 	LM_DBG("domain position %d (domain_num=%d, first_empty_domain=%d)", index, carrier_data->domain_num, carrier_data->first_empty_domain);
266
+
267
+	if ((index < 0) || (index > carrier_data->first_empty_domain)) {
268
+		LM_ERR("got invalid index during binary search\n");
269
+		return -1;
309 270
 	}
310
-	if (add_domain_data(carrier_data, domain_data) < 0) {
311
-		LM_ERR("couldn't add domain data\n");
312
-		destroy_domain_data(domain_data);
313
-		return NULL;
271
+		
272
+	if (carrier_data->first_empty_domain >= carrier_data->domain_num) {
273
+		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);
274
+		return -1;
314 275
 	}
315
-	LM_INFO("created domain data: %.*s, with id %i\n", domain_data->name.len, domain_data->name.s, domain_data->id);
316
-	return domain_data;
317
-}
318
-
319 276
 
320
-/**
321
- * Returns the domain data for the given id.
322
- *
323
- * @param carrier_data carrier data to be searched
324
- * @param domain the name of desired domain
325
- *
326
- * @return a pointer to the desired domain data, NULL if not found.
327
- */
328
-struct domain_data_t * get_domain_data_by_id(struct carrier_data_t * carrier_data, int id) {
329
-	int i;
330
-	LM_DBG("searching in carrier %.*s, id %d\n", carrier_data->name.len, carrier_data->name.s, carrier_data->id);
331
-	for (i=0; i<carrier_data->domain_num; i++) {
332
-		if (carrier_data->domains[i]) {
333
-			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);
334
-			if (carrier_data->domains[i]->id == id) {
335
-				return carrier_data->domains[i];
336
-			}
337
-		}
277
+	if (index < carrier_data->first_empty_domain) {
278
+		/* move other entries one position up */
279
+		memmove(&carrier_data->domains[index+1], &carrier_data->domains[index], sizeof(struct domain_data_t *)*(carrier_data->first_empty_domain-index));
338 280
 	}
339
-	return NULL;
340
-}
341
-
281
+	carrier_data->domains[index] = domain_data;
282
+	carrier_data->first_empty_domain++;
342 283
 
343
-static int fixup_rule_backup(struct route_flags * rf, struct route_rule * rr){
344
-	struct route_rule_p_list * rl;
345
-	if(!rr->status && rr->backup){
346
-		if((rr->backup->rr = find_rule_by_hash(rf, rr->backup->hash_index)) == NULL){
347
-			LM_ERR("didn't find backup route\n");
348
-			return -1;
349
-		}
350
-	}
351
-	rl = rr->backed_up;
352
-	while(rl){
353
-		if((rl->rr = find_rule_by_hash(rf, rl->hash_index)) == NULL){
354
-			LM_ERR("didn't find backed up route\n");
355
-			return -1;
356
-		}
357
-		rl = rl->next;
358
-	}
359 284
 	return 0;
360 285
 }
361 286
 
362 287
 
363 288
 /**
364
- * Does the work for rule_fixup recursively.
365
- * First, it tries to set a pointer the rules with an existing hash index
366
- * at the marching array index. Afterward, remaining rules are populated
367
- * with incrementing hash indices.
289
+ * Returns the domain data for the given id by doing a binary search.
290
+ * @note The domain array must be sorted!
368 291
  *
369
- * @param node the prefix tree node to be fixed up
292
+ * @param carrier_data carrier data to be searched
293
+ * @param domain_id the id of desired domain
370 294
  *
371
- * @return 0 on success, -1 on failure
295
+ * @return a pointer to the desired domain data, NULL if not found.
372 296
  */
373
-static int rule_fixup_recursor(struct dtrie_node_t *node) {
374
-	struct route_rule * rr;
375
-	struct route_flags * rf;
376
-	int i, p_dice, ret = 0;
297
+struct domain_data_t * get_domain_data(struct carrier_data_t * carrier_data, int domain_id) {
298
+	struct domain_data_t **ret;
299
+	struct domain_data_t key;
300
+	struct domain_data_t *pkey = &key;
377 301
 
378
-	for (rf=(struct route_flags *)(node->data); rf!=NULL; rf=rf->next) {
379
-		p_dice = 0;
380
-		if (rf->rule_list) {
381
-			rr = rf->rule_list;
382
-			rf->rule_num = 0;
383
-			while (rr) {
384
-				rf->rule_num++;
385
-				rf->dice_max += rr->prob * DICE_MAX;
386
-				rr = rr->next;
387
-			}
388
-			rr = rf->rule_list;
389
-			while (rr) {
390
-				rr->dice_to = (rr->prob * DICE_MAX) + p_dice;
391
-				p_dice = rr->dice_to;
392
-				rr = rr->next;
393
-			}
394
-			
395
-			if (rf->rule_num != rf->max_targets) {
396
-				LM_ERR("number of rules(%i) differs from max_targets(%i), maybe your config is wrong?\n", rf->rule_num, rf->max_targets);
397
-				return -1;
398
-			}
399
-			if(rf->rules) {
400
-				shm_free(rf->rules);
401
-				rf->rules = NULL;
402
-			}
403
-			if ((rf->rules = shm_malloc(sizeof(struct route_rule *) * rf->rule_num)) == NULL) {
404
-				LM_ERR("out of shared memory\n");
405
-				return -1;
406
-			}
407
-			memset(rf->rules, 0, sizeof(struct route_rule *) * rf->rule_num);
408
-			for (rr = rf->rule_list; rr; rr = rr->next) {
409
-				if (rr->hash_index) {
410
-					if (rr->hash_index > rf->rule_num) {
411
-						LM_ERR("too large hash index %i, max is %i\n", rr->hash_index, rf->rule_num);
412
-						shm_free(rf->rules);
413
-						return -1;
414
-					}
415
-					if (rf->rules[rr->hash_index - 1]) {
416
-						LM_ERR("duplicate hash index %i\n", rr->hash_index);
417
-						shm_free(rf->rules);
418
-						return -1;
419
-					}
420
-					rf->rules[rr->hash_index - 1] = rr;
421
-					LM_INFO("rule with host %.*s hash has hashindex %i.\n", rr->host.len, rr->host.s, rr->hash_index);
422
-				}
423
-			}
424
-			
425
-			rr = rf->rule_list;
426
-			i=0;
427
-			while (rr && i < rf->rule_num) {
428
-				if (!rr->hash_index) {
429
-					if (rf->rules[i]) {
430
-						i++;
431
-					} else {
432
-						rf->rules[i] = rr;
433
-						rr->hash_index = i + 1;
434
-						LM_INFO("hashless rule with host %.*s hash hash_index %i\n", rr->host.len, rr->host.s, i+1);
435
-						rr = rr->next;
436
-					}
437
-				} else {
438
-					rr = rr->next;
439
-				}
440
-			}
441
-			if (rr) {
442
-				LM_ERR("Could not populate rules: rr: %p\n", rr);
443
-				return -1;
444
-			}
445
-			for(i=0; i<rf->rule_num; i++){
446
-				ret += fixup_rule_backup(rf, rf->rules[i]);
447
-			}
448
-		}
449
-	}
450
-
451
-	for (i=0; i<10; i++) {
452
-		if (node->child[i]) {
453
-			ret += rule_fixup_recursor(node->child[i]);
454
-		}
302
+	if (!carrier_data) {
303
+		LM_ERR("NULL pointer in parameter\n");
304
+		return NULL;
455 305
 	}
456
-
457
-	return ret;
306
+	key.id = domain_id;
307
+	ret = bsearch(&pkey, carrier_data->domains, carrier_data->domain_num, sizeof(carrier_data->domains[0]), compare_domain_data);
308
+	if (ret) return *ret;
309
+	return NULL;
458 310
 }
459 311
 
460 312
 
461 313
 /**
462
- * Fixes the route rules by creating an array for accessing
463
- * route rules by hash index directly
464
- *
465
- * @param rd route data to be fixed
314
+ * Compares the IDs of two carrier data structures.
315
+ * A NULL pointer is always greater than any ID.
466 316
  *
467
- * @return 0 on success, -1 on failure
317
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
468 318
  */
469
-int rule_fixup(struct route_data_t * rd) {
470
-	int i,j;
471
-	for (i=0; i<rd->carrier_num; i++) {
472
-		for (j=0; j<rd->carriers[i]->domain_num; j++) {
473
-			if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
474
-				LM_INFO("fixing tree %.*s\n", rd->carriers[i]->domains[j]->name.len, rd->carriers[i]->domains[j]->name.s);
475
-				if (rule_fixup_recursor(rd->carriers[i]->domains[j]->tree) < 0) {
476
-					return -1;
477
-				}
478
-			} else {
479
-				LM_NOTICE("empty tree at [%i][%i]\n", i, j);
480
-			}
319
+int compare_carrier_data(const void *v1, const void *v2) {
320
+  struct carrier_data_t *c1 = *(struct carrier_data_t * const *)v1;
321
+	struct carrier_data_t *c2 = *(struct carrier_data_t * const *)v2;
322
+	if (c1 == NULL) {
323
+		if (c2 == NULL) return 0;
324
+		else return 1;
325
+	}
326
+	else {
327
+		if (c2 == NULL) return -1;
328
+		else {
329
+			if (c1->id < c2->id) return -1;
330
+			else if (c1->id > c2->id) return 1;
331
+			else return 0;
481 332
 		}
482 333
 	}
483
-	return 0;
484 334
 }
... ...
@@ -32,160 +32,73 @@
32 32
 
33 33
 #include <sys/types.h>
34 34
 #include "../../str.h"
35
-#include "../../locking.h"
36
-#include "../../flags.h"
37
-#include "cr_data.h"
38 35
 
39 36
 
40 37
 /**
41 38
  * The struct for a carrier.
42 39
  */
43 40
 struct carrier_data_t {
41
+	int id; /*!< id of the carrier */
42
+	str * name; /*!< name of the carrier. This points to the name in carrier_map to avoid duplication. */
44 43
 	struct domain_data_t ** domains; /*!< array of routing domains */
45 44
 	size_t domain_num; /*!< number of routing domains */
46
-	str name; /*!< name of the carrier */
47
-	int id; /*!< id of the carrier */
48
-	int index; /*!< index of the carrier */
45
+	size_t first_empty_domain; /*!< the index of the first empty entry in domains */
49 46
 };
50 47
 
51 48
 
52 49
 /**
53 50
  * Create a new carrier_data struct in shared memory and set it up.
54 51
  *
55
- * @param carrier_name the name of the carrier
56 52
  * @param carrier_id id of carrier
57
- * @param index the index for that carrier
53
+ * @param carrier_name pointer to the name of the carrier
58 54
  * @param domains number of domains for that carrier
59 55
  *
60 56
  * @return a pointer to the newly allocated carrier data or NULL on
61 57
  * error, in which case it LOGs an error message.
62 58
  */
63
-struct carrier_data_t * create_carrier_data(const str *carrier_name, int carrier_id, int index, int domains);
64
-
65
-
66
-/**
67
- * Adds the given route information to the routing domain identified by
68
- * domain. scan_prefix identifies the number for which the information
69
- * is and the rewrite_* parameters define what to do in case of a match.
70
- * prob gives the probability with which this rule applies if there are
71
- * more than one for a given prefix.
72
- *
73
- * @param rd the route data to which the route shall be added
74
- * @param carrier_id the carrier id of the route to be added
75
- * @param domain the routing domain of the new route
76
- * @param scan_prefix the number prefix
77
- * @param flags user defined flags
78
- * @param mask mask for user defined flags
79
- * @param max_targets the number of targets
80
- * @param prob the weight of the rule
81
- * @param strip the number of digits to be stripped off userpart before prepending prefix
82
- * @param rewrite_hostpart the rewrite_host of the rule
83
- * @param rewrite_local_prefix the rewrite prefix
84
- * @param rewrite_local_suffix the rewrite suffix
85
- * @param status the status of the rule
86
- * @param hash_index the hash index of the rule
87
- * @param backup indicates if the route is backed up by another. only
88
-                 useful if status==0, if set, it is the hash value
89
-                 of another rule
90
-  * @param backed_up an -1-termintated array of hash indices of the route
91
-                    for which this route is backup
92
- * @param comment a comment for the route rule
93
- *
94
- * @return 0 on success, -1 on error in which case it LOGs a message.
95
- */
96
-int add_route(struct route_data_t * rd, int carrier_id,
97
-		const str * domain, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
98
-		double prob, const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix,
99
-		const str * rewrite_local_suffix, int status, int hash_index, int backup, int * backed_up,
100
-		const str * comment);
59
+struct carrier_data_t * create_carrier_data(int carrier_id, str *carrier_name, int domains);
101 60
 
102 61
 
103 62
 /**
104
- * Adds the given failure route information to the failure routing domain identified by
105
- * domain. scan_prefix, host, reply_code and flags identifies the number for which
106
- * the information is and the next_domain parameter defines where to continue routing
107
- * in case of a match.
108
- *
109
- * @param rd the route data to which the route shall be added
110
- * @param carrier_id the carrier id of the route to be added
111
- * @param domain the routing domain of the new route
112
- * @param scan_prefix the number prefix
113
- * @param host the hostname last tried
114
- * @param reply_code the reply code 
115
- * @param flags user defined flags
116
- * @param mask mask for user defined flags
117
- * @param next_domain continue routing with this domain
118
- * @param comment a comment for the failure route rule
63
+ * Destroys the given carrier and frees the used memory.
119 64
  *
120
- * @return 0 on success, -1 on error in which case it LOGs a message.
65
+ * @param carrier_data the structure to be destroyed.
121 66
  */
122
-int add_failure_route(struct route_data_t * rd, int carrier_id, const str * domain,
123
-		const str * scan_prefix, const str * host, const str * reply_code,
124
-		flag_t flags, flag_t mask, const str * next_domain, const str * comment);
67
+void destroy_carrier_data(struct carrier_data_t *carrier_data);
125 68
 
126 69
 
127 70
 /**
128
- * adds a carrier_data struct for given carrier
71
+ * Adds a domain_data struct to the given carrier data structure at the given index.
72
+ * Other etries are moved one position up to make space for the new one.
129 73
  *
130
- * @param rd route data to be searched
131
- * @param carrier the name of desired carrier
132
- * @param carrier_id the id of the carrier
133
- * @param domains number of domains for that carrier
74
+ * @param carrier_data the carrier data struct where domain_data should be inserted
75
+ * @param domain_data the domain data struct to be inserted
76
+ * @param index the index where to insert the domain_data structure in the domain array
134 77
  *
135
- * @return a pointer to the root node of the desired routing tree,
136
- * NULL on failure
137
- */
138
-struct carrier_data_t * add_carrier_data(struct route_data_t * rd, const str * carrier, int carrier_id, int domains);
139
-
140
-
141
-/**
142
- * returns the routing tree for the given domain, if domain's tree
143
- * doesnt exist, it will be created. If the trees are completely
144
- * filled and a not existing domain shall be added, an error is
145
- * returned
146
- *
147
- * @param carrier_id the id of the desired carrier
148
- * @param rd route data to be searched
149
- *
150
- * @return a pointer to the root node of the desired routing tree,
151
- * NULL on failure
152
- */
153
-struct carrier_data_t *get_carrier_data(struct route_data_t * rd, int carrier_id);
154
-
155
-
156
-/**
157
- * Returns the domain data for the given name. If it doesnt exist,
158
- * it will be created. If the domain list is completely
159
- * filled and a not existing domain shall be added, an error is
160
- * returned
161
- *
162
- * @param carrier_data carrier data to be searched
163
- * @param domain the name of desired domain
164
- *
165
- * @return a pointer to the desired domain data, NULL on failure.
78
+ * @return 0 on success, -1 on failure
166 79
  */
167
-struct domain_data_t *get_domain_data_by_name(struct carrier_data_t * carrier_data, const str * domain);
80
+int add_domain_data(struct carrier_data_t * carrier_data, struct domain_data_t * domain_data, int index);
168 81
 
169 82
 
170 83
 /**
171
- * Returns the domain data for the given id.
84
+ * Returns the domain data for the given id by doing a binary search.
85
+ * @note The domain array must be sorted!
172 86
  *
173 87
  * @param carrier_data carrier data to be searched
174
- * @param domain the name of desired domain
88
+ * @param domain_id the id of desired domain
175 89
  *
176 90
  * @return a pointer to the desired domain data, NULL if not found.
177 91
  */
178
-struct domain_data_t *get_domain_data_by_id(struct carrier_data_t * carrier_data, int id);
92
+struct domain_data_t *get_domain_data(struct carrier_data_t * carrier_data, int domain_id);
179 93
 
180 94
 
181 95
 /**
182
- * Fixes the route rules by creating an array for accessing
183
- * route rules by hash index directly
96
+ * Compares the IDs of two carrier data structures.
97
+ * A NULL pointer is always greater than any ID.
184 98
  *
185
- * @param rd route data to be fixed
186
- *
187
- * @return 0 on success, -1 on failure
99
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
188 100
  */
189
-int rule_fixup(struct route_data_t * rd);
101
+int compare_carrier_data(const void *v1, const void *v2);
102
+
190 103
 
191 104
 #endif
... ...
@@ -31,6 +31,7 @@
31 31
 #include <sys/types.h>
32 32
 #include <sys/stat.h>
33 33
 #include <unistd.h>
34
+#include <stdlib.h>
34 35
 #include "../../mem/shm_mem.h"
35 36
 #include "../../mem/mem.h"
36 37
 #include "../../ut.h"
... ...
@@ -180,8 +181,10 @@ errout:
180 180
  */
181 181
 int load_config(struct route_data_t * rd) {
182 182
 	cfg_t * cfg = NULL;
183
-	int n, m, o, i, j, k,l, status, hash_index, max_targets, strip;
183
+	int m, o, i, j, k,l, status, hash_index, max_targets, strip;
184 184
 	cfg_t * d, * p, * t;
185
+	struct carrier_data_t * tmp_carrier_data;
186
+	int domain_id;
185 187
 	str domain, prefix, rewrite_prefix, rewrite_suffix, rewrite_host, comment;
186 188
 	double prob;
187 189
 	int * backed_up = NULL;
... ...
@@ -192,21 +195,68 @@ int load_config(struct route_data_t * rd) {
192 192
 		return -1;
193 193
 	}
194 194
 
195
+	rd->carrier_num = 1;
196
+	rd->first_empty_carrier = 0;
197
+	rd->domain_num = cfg_size(cfg, "domain");
198
+
195 199
 	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *))) == NULL) {
196 200
 		SHM_MEM_ERROR;
197 201
 		return -1;
198 202
 	}
199 203
 	memset(rd->carriers, 0, sizeof(struct carrier_data_t *));
200 204
 
201
-	rd->carrier_num = 1;
202
-	n = cfg_size(cfg, "domain");
203
-	if (add_carrier_data(rd, &default_tree, 1, n) == NULL) {
205
+	/* Create carrier map */
206
+	if ((rd->carrier_map = shm_malloc(sizeof(struct name_map_t))) == NULL) {
207
+		SHM_MEM_ERROR;
208
+		return -1;
209
+	}
210
+	memset(rd->carrier_map, 0, sizeof(struct name_map_t));
211
+	rd->carrier_map[0].id = 1;
212
+	rd->carrier_map[0].name.len = default_tree.len;
213
+	rd->carrier_map[0].name.s = shm_malloc(rd->carrier_map[0].name.len);
214
+	if (rd->carrier_map[0].name.s == NULL) {
215
+		SHM_MEM_ERROR;
216
+		return -1;
217
+	}
218
+	memcpy(rd->carrier_map[0].name.s, default_tree.s, rd->carrier_map[0].name.len);
219
+
220
+	/* Create domain map */
221
+	if ((rd->domain_map = shm_malloc(sizeof(struct name_map_t) * rd->domain_num)) == NULL) {
222
+		SHM_MEM_ERROR;
223
+		return -1;
224
+	}
225
+	memset(rd->domain_map, 0, sizeof(struct name_map_t) * rd->domain_num);
226
+	for (i=0; i<rd->domain_num; i++) {
227
+		d = cfg_getnsec(cfg, "domain", i);
228
+		domain.s = (char *)cfg_title(d);
229
+		if (domain.s==NULL) domain.s="";
230
+		domain.len = strlen(domain.s);
231
+		rd->domain_map[i].id = i+1;
232
+		rd->domain_map[i].name.len = domain.len;
233
+		rd->domain_map[i].name.s = shm_malloc(rd->domain_map[i].name.len);
234
+		if (rd->domain_map[i].name.s == NULL) {
235
+			SHM_MEM_ERROR;
236
+			return -1;
237
+		}
238
+		memcpy(rd->domain_map[i].name.s, domain.s, rd->domain_map[i].name.len);
239
+	}
240
+	/* sort domain map by id for faster access */
241
+	qsort(rd->domain_map, rd->domain_num, sizeof(rd->domain_map[0]), compare_name_map);
242
+
243
+	/* Create and insert carrier data structure */
244
+	tmp_carrier_data = create_carrier_data(1, &rd->carrier_map[0].name, rd->domain_num);
245
+	if (tmp_carrier_data == NULL) {
246
+		LM_ERR("can't create new carrier\n");
247
+		return -1;
248
+	}
249
+	if (add_carrier_data(rd, tmp_carrier_data) < 0) {
204 250
 		LM_ERR("couldn't add carrier data\n");
251
+		destroy_carrier_data(tmp_carrier_data);
205 252
 		return -1;
206 253
 	}
207 254
 
208
-	memset(rd->carriers[0]->domains, 0, sizeof(struct domain_data_t *) * n);
209
-	for (i = 0; i < n; i++) {
255
+	/* add all routes */
256
+	for (i = 0; i < rd->domain_num; i++) {
210 257
 		d = cfg_getnsec(cfg, "domain", i);
211 258
 		domain.s = (char *)cfg_title(d);
212 259
 		if (domain.s==NULL) domain.s="";
... ...
@@ -264,9 +314,18 @@ int load_config(struct route_data_t * rd) {
264 264
 				}
265 265
 				backup = cfg_getint(t, "backup");
266 266
 
267
+				domain_id = map_name2id(rd->domain_map, rd->domain_num, &domain);
268
+				if (domain_id < 0) {
269
+					LM_ERR("cannot find id for domain '%.*s'", domain.len, domain.s);
270
+					if (backed_up) {
271
+						pkg_free(backed_up);
272
+					}
273
+					return -1;
274
+				}
275
+
267 276
 				LM_INFO("adding route for prefix %.*s, to host %.*s, prob %f, backed up: %i, backup: %i\n",
268 277
 				    prefix.len, prefix.s, rewrite_host.len, rewrite_host.s, prob, backed_up_size, backup);
269
-				if (add_route(rd, 1, &domain, &prefix, 0, 0, max_targets, prob, &rewrite_host,
278
+				if (add_route(rd, 1, domain_id, &prefix, 0, 0, max_targets, prob, &rewrite_host,
270 279
 				              strip, &rewrite_prefix, &rewrite_suffix, status,
271 280
 				              hash_index, backup, backed_up, &comment) < 0) {
272 281
 					LM_INFO("Error while adding route\n");
... ...
@@ -386,7 +445,7 @@ int save_config(struct route_data_t * rd) {
386 386
 	i = 0;
387 387
 	if (rd->carrier_num>=1) {
388 388
 		for (j=0; j< rd->carriers[i]->domain_num; j++) {
389
-			fprintf(outfile, "domain %.*s {\n", rd->carriers[i]->domains[j]->name.len, rd->carriers[i]->domains[j]->name.s);
389
+			fprintf(outfile, "domain %.*s {\n", rd->carriers[i]->domains[j]->name->len, rd->carriers[i]->domains[j]->name->s);
390 390
 			if (save_route_data_recursor(rd->carriers[i]->domains[j]->tree, outfile) < 0) {
391 391
 				goto errout;
392 392
 			}
... ...
@@ -27,6 +27,7 @@
27 27
  * - Module; \ref carrierroute
28 28
  */
29 29
 
30
+#include <stdlib.h>
30 31
 #include "../../mem/shm_mem.h"
31 32
 #include "cr_data.h"
32 33
 #include "carrierroute.h"
... ...
@@ -34,6 +35,7 @@
34 34
 #include "cr_db.h"
35 35
 #include "cr_carrier.h"
36 36
 #include "cr_domain.h"
37
+#include "cr_rule.h"
37 38
 
38 39
 
39 40
 /**
... ...
@@ -42,46 +44,19 @@
42 42
 struct route_data_t ** global_data = NULL;
43 43
 
44 44
 
45
-/**
46
- * Destroys a carrier
47
- *
48
- * @param tree route data to be destroyed
49
- */
50
-static void destroy_carrier_data(struct carrier_data_t * carrier_data) {
51
-	int i;
52
-
53
-	if (carrier_data == NULL) {
54
-		return;
55
-	}
56
-	if (carrier_data->domains != NULL) {
57
-		for (i = 0; i < carrier_data->domain_num; ++i) {
58
-			if (carrier_data->domains[i] != NULL) {
59
-				destroy_domain_data(carrier_data->domains[i]);
60
-			}
61
-		}
62
-		shm_free(carrier_data->domains);
63
-	}
64
-	if(carrier_data->name.s){
65
-		shm_free(carrier_data->name.s);
66
-	}
67
-	shm_free(carrier_data);
68
-	return;
69
-}
70
-
71
-
72 45
 static int carrier_data_fixup(struct route_data_t * rd){
73 46
 	int i;
74 47
 	str tmp;
75 48
 	tmp = default_tree;
76
-	rd->default_carrier_index = -1;
49
+	rd->default_carrier_id = -1;
77 50
 	for(i=0; i<rd->carrier_num; i++){
78 51
 		if(rd->carriers[i]){
79
-			if(str_strcmp(&(rd->carriers[i]->name), &tmp) == 0){
80
-				rd->default_carrier_index = i;
52
+			if(str_strcmp(rd->carriers[i]->name, &tmp) == 0){
53
+				rd->default_carrier_id = rd->carriers[i]->id;
81 54
 			}
82 55
 		}
83 56
 	}
84
-	if(rd->default_carrier_index < 0){
57
+	if(rd->default_carrier_id < 0){
85 58
 		LM_ERR("default_carrier not found\n");
86 59
 	}
87 60
 	return 0;
... ...
@@ -98,7 +73,7 @@ int init_route_data(void) {
98 98
 		global_data = (struct route_data_t **)
99 99
 		              shm_malloc(sizeof(struct route_data_t *));
100 100
 		if (global_data == NULL) {
101
-			LM_ERR("Out of shared memory before even doing anything.\n");
101
+			SHM_MEM_ERROR;
102 102
 			return -1;
103 103
 		}
104 104
 	}
... ...
@@ -140,12 +115,49 @@ void clear_route_data(struct route_data_t *data) {
140 140
 		}
141 141
 		shm_free(data->carriers);
142 142
 	}
143
+	if (data->carrier_map) {
144
+		for (i = 0; i < data->carrier_num; ++i) {
145
+			if (data->carrier_map[i].name.s) shm_free(data->carrier_map[i].name.s);
146
+		}
147
+		shm_free(data->carrier_map);
148
+	}
149
+	if (data->domain_map) {
150
+		for (i = 0; i < data->domain_num; ++i) {
151
+			if (data->domain_map[i].name.s) shm_free(data->domain_map[i].name.s);
152
+		}
153
+		shm_free(data->domain_map);
154
+	}
143 155
 	shm_free(data);
144 156
 	return;
145 157
 }
146 158
 
147 159
 
148 160
 /**
161
+ * adds a carrier_data struct for given carrier.
162
+ *
163
+ * @param rd route data to be searched
164
+ * @param carrier_data the carrier data struct to be inserted
165
+ *
166
+ * @return 0 on success, -1 on failure
167
+ */
168
+int add_carrier_data(struct route_data_t * rd, struct carrier_data_t * carrier_data) {
169
+	if (rd->first_empty_carrier >= rd->carrier_num) {
170
+		LM_ERR("carrier array already full");
171
+		return -1;
172
+	}
173
+
174
+	if (rd->carriers[rd->first_empty_carrier] != 0) {
175
+		LM_ERR("invalid pointer in first empty carrier entry");
176
+		return -1;
177
+	}
178
+
179
+	rd->carriers[rd->first_empty_carrier] = carrier_data;
180
+	rd->first_empty_carrier++;
181
+	return 0;
182
+}
183
+
184
+
185
+/**
149 186
  * Loads the routing data into the routing trees and sets the
150 187
  * global_data pointer to the new data. The old_data is removed
151 188
  * when it is not locked anymore.
... ...
@@ -158,7 +170,7 @@ int reload_route_data(void) {
158 158
 	int i;
159 159
 
160 160
 	if ((new_data = shm_malloc(sizeof(struct route_data_t))) == NULL) {
161
-		LM_ERR("out of shared memory\n");
161
+		SHM_MEM_ERROR;
162 162
 		return -1;
163 163
 	}
164 164
 	memset(new_data, 0, sizeof(struct route_data_t));
... ...
@@ -167,32 +179,40 @@ int reload_route_data(void) {
167 167
 	case CARRIERROUTE_MODE_DB:
168 168
 		if (load_route_data_db(new_data) < 0) {
169 169
 			LM_ERR("could not load routing data\n");
170
-			return -1;
170
+			goto errout;
171 171
 		}
172 172
 		break;
173 173
 	case CARRIERROUTE_MODE_FILE:
174 174
 		if (load_config(new_data) < 0) {
175 175
 			LM_ERR("could not load routing data\n");
176
-			return -1;
176
+			goto errout;
177 177
 		}
178 178
 		break;
179 179
 	default:
180 180
 		LM_ERR("invalid mode");
181
-		return -1;
181
+		goto errout;
182 182
 	}
183 183
 	if (new_data == NULL) {
184 184
 		LM_ERR("loading routing data failed (NULL pointer)");
185
-		return -1;
185
+		goto errout;
186
+	}
187
+
188
+	/* sort carriers by id for faster access */
189
+	qsort(new_data->carriers, new_data->carrier_num, sizeof(new_data->carriers[0]), compare_carrier_data);
190
+
191
+	/* sort domains by id for faster access */
192
+	for (i=0; i<new_data->carrier_num; i++) {
193
+		qsort(new_data->carriers[i]->domains, new_data->carriers[i]->domain_num, sizeof(new_data->carriers[i]->domains[0]), compare_domain_data);
186 194
 	}
187 195
 
188 196
 	if (rule_fixup(new_data) < 0) {
189 197
 		LM_ERR("could not fixup rules\n");
190
-		return -1;
198
+		goto errout;
191 199
 	}
192 200
 
193 201
 	if (carrier_data_fixup(new_data) < 0){
194 202
 		LM_ERR("could not fixup trees\n");
195
-		return -1;
203
+		goto errout;
196 204
 	}
197 205
 
198 206
 	new_data->proc_cnt = 0;
... ...
@@ -211,6 +231,10 @@ int reload_route_data(void) {
211 211
 		clear_route_data(old_data);
212 212
 	}
213 213
 	return 0;
214
+
215
+ errout:
216
+	clear_route_data(new_data);
217
+	return -1;
214 218
 }
215 219
 
216 220
 
... ...
@@ -251,3 +275,391 @@ void release_data(struct route_data_t *data) {
251 251
 	--data->proc_cnt;
252 252
 	lock_release(&data->lock);
253 253
 }
254
+
255
+
256
+/**