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 130
    1.21. Example database content - more complex
128 131
           carrierfailureroute table
129 132
 
130
-   1.22. Example database content - route_tree table
133
+   1.22. Example database content - carrier_name table
131 134
    1.23. Necessary extensions for the user table
132 135
    2.1. Set db_url parameter
133 136
    2.2. Set carrierroute_table parameter
... ...
@@ -154,9 +157,12 @@ Henning Westerholt
154 157
    2.23. Set carrierfailureroute_mask_col parameter
155 158
    2.24. Set carrierfailureroute_next_domain_col parameter
156 159
    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
160
+   2.26. Set carrier_name_table parameter
161
+   2.27. Set carrier_name_id_col parameter
162
+   2.28. Set carrier_name_carrier_col parameter
163
+   2.29. Set domain_name_table parameter
164
+   2.30. Set domain_name_id_col parameter
165
+   2.31. Set domain_name_domain_col parameter
160 166
 
161 167
 Chapter 1. Admin Guide
162 168
 
... ...
@@ -183,10 +189,13 @@ Chapter 1. Admin Guide
183 189
 
184 190
    This modules scales up to more than a few million users, and is
185 191
    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.
192
+   entries. We recieved reports of some setups that used more than
193
+   a million routing table entries. It also supports a large
194
+   number of carriers and domains which can be efficiently looked
195
+   up in most of the cases (see below for more informations). In
196
+   load balancing scenarios the usage of the config file mode is
197
+   recommended, to avoid the additional complexity that the
198
+   database driven routing creates.
190 199
 
191 200
    Routing tables can be reloaded and edited (in config file mode)
192 201
    with the MI interface, the config file is updated according the
... ...
@@ -201,6 +210,17 @@ Chapter 1. Admin Guide
201 210
    sections. For user based routing or LCR you should use the
202 211
    database mode.
203 212
 
213
+   In database mode, this module supports names and IDs for the
214
+   carriers and domains. When using IDs for the routing functions,
215
+   efficient binary search is used to find the needed data
216
+   structures. If you are using constant strings as parameter,
217
+   these will be converted to IDs during the fixup procedure.
218
+   However, if you are using AVPs as parameter and they contain
219
+   strings, this cannot be converted to IDs during the fixup
220
+   procedure. In that case linear search is performed to find the
221
+   needed data structures. So from a performance point of view it
222
+   is better to pass only IDs in AVPs to the routing functions.
223
+
204 224
    Basically this module could be used as an replacement for the
205 225
    lcr and the dispatcher module, if you have certain performance,
206 226
    flexibility and/or integration requirements that these modules
... ...
@@ -800,8 +820,8 @@ domain register {
800 820
 | 9  |       2 |      0 | 49          |     0 |  0.5 | de-2.carrier2 |
801 821
 | 10 |       2 |      0 |             |     0 |    1 | gw.carrier2   |
802 822
 | 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    |
823
+| 12 |       3 |      8 | 49          |     0 |    1 | de-gw.default |
824
+| 13 |       3 |      8 |             |     0 |    1 | gw.default    |
805 825
 +----+---------+--------+-------------+-------+------+---------------+
806 826
 ...
807 827
 
... ...
@@ -854,7 +874,7 @@ domain register {
854 874
 |  1 |      99 |           | 408        |    16 |   16 |             |
855 875
 |  2 |      99 | gw1       | 404        |     0 |    0 | 100         |
856 876
 |  3 |      99 | gw2       | 50.        |     0 |    0 | 100         |
857
-|  4 |      99 |           | 404        |  2048 | 2112 | asterisk-1  |
877
+|  4 |      99 |           | 404        |  2048 | 2112 | 101         |
858 878
 +----+---------+-----------+------------+-------+------+-------------+
859 879
 ...
860 880
 
... ...
@@ -872,7 +892,7 @@ domain register {
872 892
    holds domain entries for this routing rules. Not all table
873 893
    colums are show here for brevity.
874 894
 
875
-   Example 1.22. Example database content - route_tree table
895
+   Example 1.22. Example database content - carrier_name table
876 896
 ...
877 897
 +----+----------+
878 898
 | id | carrier  |
... ...
@@ -926,7 +946,7 @@ modparam("carrierroute", "carrierroute_table", "carrierroute")
926 946
 
927 947
 2.3. carrierroute_id_col (string)
928 948
 
929
-   unique ID
949
+   Name of the column contains the unique identifier of a route.
930 950
 
931 951
    Example 2.3. Set carrierroute_id_col parameter
932 952
 ...
... ...
@@ -944,8 +964,10 @@ modparam("carrierroute", "carrierroute_carrier_col", "carrier")
944 964
 
945 965
 2.5. carrierroute_domain_col (string)
946 966
 
947
-   This column contains the route domain. Additional domains could
948
-   be used for example as fallback.
967
+   This column contains the routing domain id. You can define
968
+   several routing domains to have different routing rules. Maybe
969
+   you use domain 0 for normal routing and domain 1 if domain 0
970
+   failed.
949 971
 
950 972
    Example 2.5. Set carrierroute_domain_col parameter
951 973
 ...
... ...
@@ -954,8 +976,12 @@ modparam("carrierroute", "carrierroute_domain_col", "domain")
954 976
 
955 977
 2.6. carrierroute_scan_prefix_col (string)
956 978
 
957
-   This column contains the scan prefix, which define the matching
958
-   portion of a phone number.
979
+   Name of column contains the scan prefixes. Scan prefixes define
980
+   the matching portion of a phone number, e.g. when we have the
981
+   scan prefixes 49721 and 49, the called number is 49721913740,
982
+   it matches 49721, because the longest match is taken. If no
983
+   prefix matches, the number is not routed. To prevent this, an
984
+   empty prefix value of could be added.
959 985
 
960 986
    Example 2.6. Set carrierroute_scan_prefix_col parameter
961 987
 ...
... ...
@@ -983,9 +1009,18 @@ modparam("carrierroute", "carrierroute_mask_col", "mask")
983 1009
 
984 1010
 2.9. carrierroute_prob_col (string)
985 1011
 
986
-   Name of column containing the probability. The probability
987
-   value is used to distribute the traffic between several
988
-   gateways.
1012
+   Name of column contains the probability. The probability value
1013
+   is used to distribute the traffic between several gateways.
1014
+   Let's say 70 % of the traffic shall be routed to gateway A, the
1015
+   other 30 % shall be routed to gateway B, we define a rule for
1016
+   gateway A with a prob value of 0.7 and a rule for gateway B
1017
+   with a prob value of 0.3. If all probabilities for a given
1018
+   prefix, tree and domain don't add to 100%, the prefix values
1019
+   will be adjusted according the given prob values. E.g. if three
1020
+   hosts with prob values of 0.5, 0.5 and 0.4 are defined, the
1021
+   resulting probabilities are 35.714, 35.714 and 28.571%. But its
1022
+   better to choose meaningful values in the first place because
1023
+   of clarity.
989 1024
 
990 1025
    Example 2.9. Set carrierroute_prob_col parameter
991 1026
 ...
... ...
@@ -994,9 +1029,8 @@ modparam("carrierroute", "carrierroute_prob_col", "prob")
994 1029
 
995 1030
 2.10. carrierroute_strip_col (string)
996 1031
 
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.
1032
+   Name of the column contains the number of digits to be stripped
1033
+   of the userpart of an URI before prepending rewrite_prefix.
1000 1034
 
1001 1035
    Example 2.10. Set carrierroute_strip_col parameter
1002 1036
 ...
... ...
@@ -1005,8 +1039,10 @@ modparam("carrierroute", "carrierroute_strip_col", "strip")
1005 1039
 
1006 1040
 2.11. carrierroute_rewrite_host_col (string)
1007 1041
 
1008
-   Name of column containing rewrite prefixes. Here you can define
1009
-   a rewrite prefix for the localpart of the SIP URI.
1042
+   Name of column contains the rewrite prefixes. Here you can
1043
+   define a rewrite prefix for the localpart of the SIP URI. An
1044
+   empty field represents a blacklist entry, anything else is put
1045
+   as domain part into the Request URI of the SIP message.
1010 1046
 
1011 1047
    Example 2.11. Set carrierroute_rewrite_host_col parameter
1012 1048
 ...
... ...
@@ -1016,7 +1052,8 @@ modparam("carrierroute", "carrierroute_rewrite_host_col", "rewrite_host"
1016 1052
 
1017 1053
 2.12. carrierroute_rewrite_prefix_col (string)
1018 1054
 
1019
-   Rewrite prefix for the localpart of the SIP URI.
1055
+   Name of column contains the rewrite prefixes. Here you can
1056
+   define a rewrite prefix for the localpart of the SIP URI.
1020 1057
 
1021 1058
    Example 2.12. Set carrierroute_rewrite_prefix_col parameter
1022 1059
 ...
... ...
@@ -1026,7 +1063,8 @@ fix")
1026 1063
 
1027 1064
 2.13. carrierroute_rewrite_suffix_col (string)
1028 1065
 
1029
-   Rewrite suffix for the localpart of the SIP URI.
1066
+   Name of column contains the rewrite suffixes. Here you can
1067
+   define a rewrite suffix for the localpart of the SIP URI.
1030 1068
 
1031 1069
    Example 2.13. Set carrierroute_rewrite_suffix_col parameter
1032 1070
 ...
... ...
@@ -1037,7 +1075,8 @@ fix")
1037 1075
 2.14. carrierroute_description_col (string)
1038 1076
 
1039 1077
    A comment for the route entry, useful for larger routing
1040
-   tables.
1078
+   tables. The comment is also displayed by the fifo cmd
1079
+   "cr_dump_routes".
1041 1080
 
1042 1081
    Example 2.14. Set carrierroute_description_col parameter
1043 1082
 ...
... ...
@@ -1059,7 +1098,7 @@ te")
1059 1098
 
1060 1099
 2.16. carrierfailureroute_id_col (string)
1061 1100
 
1062
-   unique ID
1101
+   This column contains the unique identifier of a failure route.
1063 1102
 
1064 1103
    Example 2.16. Set carrierfailureroute_id_col parameter
1065 1104
 ...
... ...
@@ -1077,8 +1116,10 @@ modparam("carrierroute", "carrierfailureroute_carrier_col", "carrier")
1077 1116
 
1078 1117
 2.18. carrierfailureroute_domain_col (string)
1079 1118
 
1080
-   This column contains the route domain. Additional domains could
1081
-   be used for example as fallback.
1119
+   This column contains the routing domain id. You can define
1120
+   several routing domains to have different routing rules. Maybe
1121
+   you use domain 0 for normal routing and domain 1 if domain 0
1122
+   failed.
1082 1123
 
1083 1124
    Example 2.18. Set carrierfailureroute_domain_col parameter
1084 1125
 ...
... ...
@@ -1087,8 +1128,12 @@ modparam("carrierroute", "carrierfailureroute_domain_col", "domain")
1087 1128
 
1088 1129
 2.19. carrierfailureroute_scan_prefix_col (string)
1089 1130
 
1090
-   This column contains the scan prefix, which define the matching
1091
-   portion of a phone number.
1131
+   Name of column contains the the scan prefixes. Scan prexies
1132
+   define the matching portion of a phone number, e.g. we have the
1133
+   scan prefixes 49721 and 49, the called number is 49721913740,
1134
+   it matches 49721, because the longest match is taken. If no
1135
+   prefix matches, the number is not failure routed. To prevent
1136
+   this, an empty prefix value of could be added.
1092 1137
 
1093 1138
    Example 2.19. Set carrierfailureroute_scan_prefix_col parameter
1094 1139
 ...
... ...
@@ -1098,8 +1143,8 @@ efix")
1098 1143
 
1099 1144
 2.20. carrierfailureroute_host_name_col (string)
1100 1145
 
1101
-   This column contains the routing destination used for rule
1102
-   matching.
1146
+   Name of the column containing the host name of the last routing
1147
+   destination, using for rules matching.
1103 1148
 
1104 1149
    Example 2.20. Set carrierfailureroute_host_name_col parameter
1105 1150
 ...
... ...
@@ -1138,8 +1183,8 @@ modparam("carrierroute", "carrierfailureroute_mask_col", "mask")
1138 1183
 
1139 1184
 2.24. carrierfailureroute_next_domain_col (string)
1140 1185
 
1141
-   This column contains the route domain that should be used for
1142
-   the next routing attempt.
1186
+   This column contains the route domain id that should be used
1187
+   for the next routing attempt.
1143 1188
 
1144 1189
    Example 2.24. Set carrierfailureroute_next_domain_col parameter
1145 1190
 ...
... ...
@@ -1158,31 +1203,62 @@ modparam("carrierroute", "carrierfailureroute_description_col", "descrip
1158 1203
 tion")
1159 1204
 ...
1160 1205
 
1161
-2.26. route_tree_table (String)
1206
+2.26. carrier_name_table (String)
1162 1207
 
1163
-   Name of the route_tree table for the carrierroute module.
1208
+   Name of the carrier_name table for the carrierroute module.
1164 1209
 
1165
-   Default value is "route_tree".
1210
+   Default value is "carrier_name".
1166 1211
 
1167
-   Example 2.26. Set route_tree_table parameter
1212
+   Example 2.26. Set carrier_name_table parameter
1168 1213
 ...
1169
-modparam("carrierroute", "route_tree_table", "route_tree")
1214
+modparam("carrierroute", "carrier_name_table", "carrier_name")
1170 1215
 ...
1171 1216
 
1172
-2.27. route_tree_id_col (string)
1217
+2.27. carrier_name_id_col (string)
1173 1218
 
1174
-   unique ID
1219
+   Name of the column containing the unique identifier of a
1220
+   carrier.
1175 1221
 
1176
-   Example 2.27. Set route_tree_id_col parameter
1222
+   Example 2.27. Set carrier_name_id_col parameter
1177 1223
 ...
1178
-modparam("carrierroute", "route_tree_id_col", "id")
1224
+modparam("carrierroute", "carrier_name_id_col", "id")
1179 1225
 ...
1180 1226
 
1181
-2.28. route_tree_carrier_col (string)
1227
+2.28. carrier_name_carrier_col (string)
1182 1228
 
1183 1229
    This column contains the carrier name.
1184 1230
 
1185
-   Example 2.28. Set route_tree_carrier_col parameter
1231
+   Example 2.28. Set carrier_name_carrier_col parameter
1232
+...
1233
+modparam("carrierroute", "carrier_name_carrier_col", "carrier")
1234
+...
1235
+
1236
+2.29. domain_name_table (String)
1237
+
1238
+   Name of the domain_name table for the carrierroute module.
1239
+
1240
+   Default value is "domain_name".
1241
+
1242
+   Example 2.29. Set domain_name_table parameter
1243
+...
1244
+modparam("carrierroute", "domain_name_table", "domain_name")
1245
+...
1246
+
1247
+2.30. domain_name_id_col (string)
1248
+
1249
+   Name of the column containing the unique identifier of a
1250
+   domain.
1251
+
1252
+   Example 2.30. Set domain_name_id_col parameter
1253
+...
1254
+modparam("carrierroute", "domain_name_id_col", "id")
1255
+...
1256
+
1257
+2.31. domain_name_domain_col (string)
1258
+
1259
+   This column contains the domain name.
1260
+
1261
+   Example 2.31. Set domain_name_domain_col parameter
1186 1262
 ...
1187
-modparam("carrierroute", "route_tree_carrier_col", "carrier")
1263
+modparam("carrierroute", "domain_name_domain_col", "domain")
1188 1264
 ...
... ...
@@ -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 236
 		carrierroute_db_close();
235 237
 	}
236 238
 	destroy_route_data();
237
-	destroy_domain_map();
238
-	destroy_carrier_map();
239 239
 }
... ...
@@ -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 68
 
233 69
 
234 70
 /**
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
71
+ * Destroys the given carrier and frees the used memory.
239 72
  *
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
73
+ * @param carrier_data the structure to be destroyed.
245 74
  */
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) {
75
+void destroy_carrier_data(struct carrier_data_t *carrier_data) {
262 76
 	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;
77
+	if (carrier_data) {
78
+		if (carrier_data->domains != NULL) {
79
+			for (i=0; i<carrier_data->domain_num; i++) {
80
+				destroy_domain_data(carrier_data->domains[i]);
81
+			}
82
+			shm_free(carrier_data->domains);
270 83
 		}
84
+		shm_free(carrier_data);
271 85
 	}
272
-	return -1;
273 86
 }
274 87
 
275 88
 
276 89
 /**
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
90
+ * Adds a domain_data struct to the given carrier data structure at the given index.
91
+ * Other etries are moved one position up to make space for the new one.
281 92
  *
282
- * @param carrier_data carrier data to be searched
283
- * @param domain the name of desired domain
93
+ * @param carrier_data the carrier data struct where domain_data should be inserted
94
+ * @param domain_data the domain data struct to be inserted
95
+ * @param index the index where to insert the domain_data structure in the domain array
284 96
  *
285
- * @return a pointer to the desired domain data, NULL on failure.
97
+ * @return 0 on success, -1 on failure
286 98
  */
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;
99
+int add_domain_data(struct carrier_data_t * carrier_data, struct domain_data_t * domain_data, int index) {
100
+	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);
101
+ 	LM_DBG("domain position %d (domain_num=%d, first_empty_domain=%d)", index, carrier_data->domain_num, carrier_data->first_empty_domain);
102
+
103
+	if ((index < 0) || (index > carrier_data->first_empty_domain)) {
104
+		LM_ERR("got invalid index during binary search\n");
105
+		return -1;
309 106
 	}
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;
107
+		
108
+	if (carrier_data->first_empty_domain >= carrier_data->domain_num) {
109
+		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);
110
+		return -1;
314 111
 	}
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 112
 
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
-		}
113
+	if (index < carrier_data->first_empty_domain) {
114
+		/* move other entries one position up */
115
+		memmove(&carrier_data->domains[index+1], &carrier_data->domains[index], sizeof(struct domain_data_t *)*(carrier_data->first_empty_domain-index));
338 116
 	}
339
-	return NULL;
340
-}
341
-
117
+	carrier_data->domains[index] = domain_data;
118
+	carrier_data->first_empty_domain++;
342 119
 
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 120
 	return 0;
360 121
 }
361 122
 
362 123
 
363 124
 /**
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.
125
+ * Returns the domain data for the given id by doing a binary search.
126
+ * @note The domain array must be sorted!
368 127
  *
369
- * @param node the prefix tree node to be fixed up
128
+ * @param carrier_data carrier data to be searched
129
+ * @param domain_id the id of desired domain
370 130
  *
371
- * @return 0 on success, -1 on failure
131
+ * @return a pointer to the desired domain data, NULL if not found.
372 132
  */
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;
133
+struct domain_data_t * get_domain_data(struct carrier_data_t * carrier_data, int domain_id) {
134
+	struct domain_data_t **ret;
135
+	struct domain_data_t key;
136
+	struct domain_data_t *pkey = &key;
377 137
 
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
-		}
138
+	if (!carrier_data) {
139
+		LM_ERR("NULL pointer in parameter\n");
140
+		return NULL;
455 141
 	}
456
-
457
-	return ret;
142
+	key.id = domain_id;
143
+	ret = bsearch(&pkey, carrier_data->domains, carrier_data->domain_num, sizeof(carrier_data->domains[0]), compare_domain_data);
144
+	if (ret) return *ret;
145
+	return NULL;
458 146
 }
459 147
 
460 148
 
461 149
 /**
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
150
+ * Compares the IDs of two carrier data structures.
151
+ * A NULL pointer is always greater than any ID.
466 152
  *
467
- * @return 0 on success, -1 on failure
153
+ * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
468 154
  */
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
-			}
155
+int compare_carrier_data(const void *v1, const void *v2) {
156
+  struct carrier_data_t *c1 = *(struct carrier_data_t * const *)v1;
157
+	struct carrier_data_t *c2 = *(struct carrier_data_t * const *)v2;
158
+	if (c1 == NULL) {
159
+		if (c2 == NULL) return 0;
160
+		else return 1;
161
+	}
162
+	else {
163
+		if (c2 == NULL) return -1;
164
+		else {
165
+			if (c1->id < c2->id) return -1;
166
+			else if (c1->id > c2->id) return 1;
167
+			else return 0;
481 168
 		}
482 169
 	}
483
-	return 0;
484 170
 }
... ...
@@ -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 181
  */
181 182
 int load_config(struct route_data_t * rd) {
182 183
 	cfg_t * cfg = NULL;
183
-	int n, m, o, i, j, k,l, status, hash_index, max_targets, strip;
184
+	int m, o, i, j, k,l, status, hash_index, max_targets, strip;
184 185
 	cfg_t * d, * p, * t;
186
+	struct carrier_data_t * tmp_carrier_data;
187
+	int domain_id;
185 188
 	str domain, prefix, rewrite_prefix, rewrite_suffix, rewrite_host, comment;
186 189
 	double prob;
187 190
 	int * backed_up = NULL;
... ...
@@ -192,21 +195,68 @@ int load_config(struct route_data_t * rd) {
192 195
 		return -1;
193 196
 	}
194 197
 
198
+	rd->carrier_num = 1;
199
+	rd->first_empty_carrier = 0;
200
+	rd->domain_num = cfg_size(cfg, "domain");
201
+
195 202
 	if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *))) == NULL) {
196 203
 		SHM_MEM_ERROR;
197 204
 		return -1;
198 205
 	}
199 206
 	memset(rd->carriers, 0, sizeof(struct carrier_data_t *));
200 207
 
201
-	rd->carrier_num = 1;
202
-	n = cfg_size(cfg, "domain");
203
-	if (add_carrier_data(rd, &default_tree, 1, n) == NULL) {
208
+	/* Create carrier map */
209
+	if ((rd->carrier_map = shm_malloc(sizeof(struct name_map_t))) == NULL) {
210
+		SHM_MEM_ERROR;
211
+		return -1;
212
+	}
213
+	memset(rd->carrier_map, 0, sizeof(struct name_map_t));
214
+	rd->carrier_map[0].id = 1;
215
+	rd->carrier_map[0].name.len = default_tree.len;
216
+	rd->carrier_map[0].name.s = shm_malloc(rd->carrier_map[0].name.len);
217
+	if (rd->carrier_map[0].name.s == NULL) {
218
+		SHM_MEM_ERROR;
219
+		return -1;
220
+	}
221
+	memcpy(rd->carrier_map[0].name.s, default_tree.s, rd->carrier_map[0].name.len);
222
+
223
+	/* Create domain map */
224
+	if ((rd->domain_map = shm_malloc(sizeof(struct name_map_t) * rd->domain_num)) == NULL) {
225
+		SHM_MEM_ERROR;
226
+		return -1;
227
+	}
228
+	memset(rd->domain_map, 0, sizeof(struct name_map_t) * rd->domain_num);
229
+	for (i=0; i<rd->domain_num; i++) {
230
+		d = cfg_getnsec(cfg, "domain", i);
231
+		domain.s = (char *)cfg_title(d);
232
+		if (domain.s==NULL) domain.s="";
233
+		domain.len = strlen(domain.s);
234
+		rd->domain_map[i].id = i+1;
235
+		rd->domain_map[i].name.len = domain.len;
236
+		rd->domain_map[i].name.s = shm_malloc(rd->domain_map[i].name.len);
237
+		if (rd->domain_map[i].name.s == NULL) {
238
+			SHM_MEM_ERROR;
239
+			return -1;
240
+		}
241
+		memcpy(rd->domain_map[i].name.s, domain.s, rd->domain_map[i].name.len);
242
+	}
243
+	/* sort domain map by id for faster access */
244
+	qsort(rd->domain_map, rd->domain_num, sizeof(rd->domain_map[0]), compare_name_map);
245
+
246
+	/* Create and insert carrier data structure */
247
+	tmp_carrier_data = create_carrier_data(1, &rd->carrier_map[0].name, rd->domain_num);
248
+	if (tmp_carrier_data == NULL) {
249
+		LM_ERR("can't create new carrier\n");
250
+		return -1;
251
+	}
252
+	if (add_carrier_data(rd, tmp_carrier_data) < 0) {
204 253
 		LM_ERR("couldn't add carrier data\n");
254
+		destroy_carrier_data(tmp_carrier_data);
205 255
 		return -1;
206 256
 	}
207 257
 
208
-	memset(rd->carriers[0]->domains, 0, sizeof(struct domain_data_t *) * n);
209
-	for (i = 0; i < n; i++) {
258
+	/* add all routes */
259
+	for (i = 0; i < rd->domain_num; i++) {
210 260
 		d = cfg_getnsec(cfg, "domain", i);
211 261
 		domain.s = (char *)cfg_title(d);
212 262
 		if (domain.s==NULL) domain.s="";
... ...
@@ -264,9 +314,18 @@ int load_config(struct route_data_t * rd) {
264 314
 				}
265 315
 				backup = cfg_getint(t, "backup");
266 316
 
317
+				domain_id = map_name2id(rd->domain_map, rd->domain_num, &domain);
318
+				if (domain_id < 0) {
319
+					LM_ERR("cannot find id for domain '%.*s'", domain.len, domain.s);
320
+					if (backed_up) {
321
+						pkg_free(backed_up);
322
+					}
323
+					return -1;
324
+				}
325
+
267 326
 				LM_INFO("adding route for prefix %.*s, to host %.*s, prob %f, backed up: %i, backup: %i\n",
268 327
 				    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,
328
+				if (add_route(rd, 1, domain_id, &prefix, 0, 0, max_targets, prob, &rewrite_host,
270 329
 				              strip, &rewrite_prefix, &rewrite_suffix, status,
271 330
 				              hash_index, backup, backed_up, &comment) < 0) {
272 331
 					LM_INFO("Error while adding route\n");
... ...
@@ -386,7 +445,7 @@ int save_config(struct route_data_t * rd) {
386 445
 	i = 0;
387 446
 	if (rd->carrier_num>=1) {
388 447
 		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);
448
+			fprintf(outfile, "domain %.*s {\n", rd->carriers[i]->domains[j]->name->len, rd->carriers[i]->domains[j]->name->s);
390 449
 			if (save_route_data_recursor(rd->carriers[i]->domains[j]->tree, outfile) < 0) {
391 450
 				goto errout;
392 451
 			}
... ...
@@ -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 35
 #include "cr_db.h"
35 36
 #include "cr_carrier.h"
36 37
 #include "cr_domain.h"
38
+#include "cr_rule.h"
37 39
 
38 40
 
39 41
 /**
... ...
@@ -42,46 +44,19 @@
42 44
 struct route_data_t ** global_data = NULL;
43 45
 
44 46
 
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 47
 static int carrier_data_fixup(struct route_data_t * rd){
73 48
 	int i;
74 49
 	str tmp;
75 50
 	tmp = default_tree;
76
-	rd->default_carrier_index = -1;
51
+	rd->default_carrier_id = -1;
77 52
 	for(i=0; i<rd->carrier_num; i++){
78 53
 		if(rd->carriers[i]){
79
-			if(str_strcmp(&(rd->carriers[i]->name), &tmp) == 0){
80
-				rd->default_carrier_index = i;
54
+			if(str_strcmp(rd->carriers[i]->name, &tmp) == 0){
55
+				rd->default_carrier_id = rd->carriers[i]->id;
81 56
 			}
82 57
 		}
83 58
 	}
84
-	if(rd->default_carrier_index < 0){
59
+	if(rd->default_carrier_id < 0){
85 60
 		LM_ERR("default_carrier not found\n");
86 61
 	}
87 62
 	return 0;
... ...
@@ -98,7 +73,7 @@ int init_route_data(void) {
98 73
 		global_data = (struct route_data_t **)
99 74
 		              shm_malloc(sizeof(struct route_data_t *));
100 75
 		if (global_data == NULL) {
101
-			LM_ERR("Out of shared memory before even doing anything.\n");
76
+			SHM_MEM_ERROR;
102 77
 			return -1;
103 78
 		}
104 79
 	}
... ...
@@ -140,11 +115,48 @@ void clear_route_data(struct route_data_t *data) {
140 115
 		}
141 116
 		shm_free(data->carriers);
142 117
 	}
118
+	if (data->carrier_map) {
119
+		for (i = 0; i < data->carrier_num; ++i) {
120
+			if (data->carrier_map[i].name.s) shm_free(data->carrier_map[i].name.s);
121
+		}
122
+		shm_free(data->carrier_map);
123
+	}
124
+	if (data->domain_map) {
125
+		for (i = 0; i < data->domain_num; ++i) {
126
+			if (data->domain_map[i].name.s) shm_free(data->domain_map[i].name.s);
127
+		}
128
+		shm_free(data->domain_map);
129
+	}
143 130
 	shm_free(data);
144 131
 	return;
145 132
 }
146 133
 
147 134
 
135
+/**
136
+ * adds a carrier_data struct for given carrier.
137
+ *
138
+ * @param rd route data to be searched
139
+ * @param carrier_data the carrier data struct to be inserted
140
+ *
141
+ * @return 0 on success, -1 on failure
142
+ */
143
+int add_carrier_data(struct route_data_t * rd, struct carrier_data_t * carrier_data) {
144
+	if (rd->first_empty_carrier >= rd->carrier_num) {
145
+		LM_ERR("carrier array already full");
146
+		return -1;
147
+	}
148
+
149
+	if (rd->carriers[rd->first_empty_carrier] != 0) {
150
+		LM_ERR("invalid pointer in first empty carrier entry");
151
+		return -1;
152
+	}
153
+
154
+	rd->carriers[rd->first_empty_carrier] = carrier_data;
155
+	rd->first_empty_carrier++;
156
+	return 0;
157
+}
158
+
159
+
148 160
 /**
149 161
  * Loads the routing data into the routing trees and sets the
150 162
  * global_data pointer to the new data. The old_data is removed
... ...
@@ -158,7 +170,7 @@ int reload_route_data(void) {
158 170
 	int i;
159 171
 
160 172
 	if ((new_data = shm_malloc(sizeof(struct route_data_t))) == NULL) {
161
-		LM_ERR("out of shared memory\n");
173
+		SHM_MEM_ERROR;
162 174
 		return -1;
163 175
 	}
164 176
 	memset(new_data, 0, sizeof(struct route_data_t));
... ...
@@ -167,32 +179,40 @@ int reload_route_data(void) {
167 179
 	case CARRIERROUTE_MODE_DB:
168 180
 		if (load_route_data_db(new_data) < 0) {
169 181
 			LM_ERR("could not load routing data\n");
170
-			return -1;
182
+			goto errout;
171 183
 		}
172 184
 		break;
173 185
 	case CARRIERROUTE_MODE_FILE:
174 186
 		if (load_config(new_data) < 0) {
175 187
 			LM_ERR("could not load routing data\n");
176
-			return -1;
188
+			goto errout;
177 189
 		}
178 190
 		break;
179 191
 	default:
180 192
 		LM_ERR("invalid mode");
181
-		return -1;
193
+		goto errout;
182 194
 	}
183 195
 	if (new_data == NULL) {
184 196
 		LM_ERR("loading routing data failed (NULL pointer)");
185
-		return -1;
197
+		goto errout;
198
+	}
199
+
200
+	/* sort carriers by id for faster access */
201
+	qsort(new_data->carriers, new_data->carrier_num, sizeof(new_data->carriers[0]), compare_carrier_data);
202
+
203
+	/* sort domains by id for faster access */
204
+	for (i=0; i<new_data->carrier_num; i++) {
205
+		qsort(new_data->carriers[i]->domains, new_data->carriers[i]->domain_num, sizeof(new_data->carriers[i]->domains[0]), compare_domain_data);
186 206
 	}
187 207
 
188 208
 	if (rule_fixup(new_data) < 0) {
189 209
 		LM_ERR("could not fixup rules\n");
190
-		return -1;
210
+		goto errout;
191 211
 	}
192 212
 
193 213
 	if (carrier_data_fixup(new_data) < 0){
194 214
 		LM_ERR("could not fixup trees\n");
195
-		return -1;
215
+		goto errout;
196 216
 	}
197 217
 
198 218
 	new_data->proc_cnt = 0;
... ...
@@ -211,6 +231,10 @@ int reload_route_data(void) {
211 231
 		clear_route_data(old_data);
212 232
 	}
213 233
 	return 0;
234
+
235
+ errout:
236
+	clear_route_data(new_data);
237
+	return -1;
214 238
 }
215 239
 
216 240
 
... ...
@@ -251,3 +275,391 @@ void release_data(struct route_data_t *data) {
251 275
 	--data->proc_cnt;
252 276
 	lock_release(&data->lock);
253 277
 }
278
+
279
+
280
+/**
281
+ * Returns the carrier data for the given id by doing a binary search.