00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00030 #include <stdlib.h>
00031 #include "../../mem/shm_mem.h"
00032 #include "cr_data.h"
00033 #include "carrierroute.h"
00034 #include "cr_config.h"
00035 #include "cr_db.h"
00036 #include "cr_carrier.h"
00037 #include "cr_domain.h"
00038 #include "cr_rule.h"
00039
00040
00044 struct route_data_t ** global_data = NULL;
00045
00046
00047 static int carrier_data_fixup(struct route_data_t * rd){
00048 int i;
00049 str tmp;
00050 tmp = default_tree;
00051 rd->default_carrier_id = -1;
00052 for(i=0; i<rd->carrier_num; i++){
00053 if(rd->carriers[i]){
00054 if(str_strcmp(rd->carriers[i]->name, &tmp) == 0){
00055 rd->default_carrier_id = rd->carriers[i]->id;
00056 }
00057 }
00058 }
00059 if(rd->default_carrier_id < 0){
00060 LM_ERR("default_carrier not found\n");
00061 }
00062 return 0;
00063 }
00064
00065
00071 int init_route_data(void) {
00072 if (global_data == NULL) {
00073 global_data = (struct route_data_t **)
00074 shm_malloc(sizeof(struct route_data_t *));
00075 if (global_data == NULL) {
00076 SHM_MEM_ERROR;
00077 return -1;
00078 }
00079 }
00080 *global_data = NULL;
00081 return 0;
00082 }
00083
00084
00088 void destroy_route_data(void){
00089 struct route_data_t * rd = get_data();
00090 clear_route_data(rd);
00091 if(global_data){
00092 *global_data = NULL;
00093 shm_free(global_data);
00094 global_data = NULL;
00095 }
00096 }
00097
00098
00104 void clear_route_data(struct route_data_t *data) {
00105 int i;
00106
00107 if (data == NULL) {
00108 return;
00109 }
00110 if (data->carriers != NULL) {
00111 for (i = 0; i < data->carrier_num; ++i) {
00112 if (data->carriers[i] != NULL) {
00113 destroy_carrier_data(data->carriers[i]);
00114 }
00115 }
00116 shm_free(data->carriers);
00117 }
00118 if (data->carrier_map) {
00119 for (i = 0; i < data->carrier_num; ++i) {
00120 if (data->carrier_map[i].name.s) shm_free(data->carrier_map[i].name.s);
00121 }
00122 shm_free(data->carrier_map);
00123 }
00124 if (data->domain_map) {
00125 for (i = 0; i < data->domain_num; ++i) {
00126 if (data->domain_map[i].name.s) shm_free(data->domain_map[i].name.s);
00127 }
00128 shm_free(data->domain_map);
00129 }
00130 shm_free(data);
00131 return;
00132 }
00133
00134
00143 int add_carrier_data(struct route_data_t * rd, struct carrier_data_t * carrier_data) {
00144 if (rd->first_empty_carrier >= rd->carrier_num) {
00145 LM_ERR("carrier array already full");
00146 return -1;
00147 }
00148
00149 if (rd->carriers[rd->first_empty_carrier] != 0) {
00150 LM_ERR("invalid pointer in first empty carrier entry");
00151 return -1;
00152 }
00153
00154 rd->carriers[rd->first_empty_carrier] = carrier_data;
00155 rd->first_empty_carrier++;
00156 return 0;
00157 }
00158
00159
00167 int reload_route_data(void) {
00168 struct route_data_t * old_data;
00169 struct route_data_t * new_data = NULL;
00170 int i;
00171
00172 if ((new_data = shm_malloc(sizeof(struct route_data_t))) == NULL) {
00173 SHM_MEM_ERROR;
00174 return -1;
00175 }
00176 memset(new_data, 0, sizeof(struct route_data_t));
00177
00178 switch (mode) {
00179 case CARRIERROUTE_MODE_DB:
00180 if (load_route_data_db(new_data) < 0) {
00181 LM_ERR("could not load routing data\n");
00182 goto errout;
00183 }
00184 break;
00185 case CARRIERROUTE_MODE_FILE:
00186 if (load_config(new_data) < 0) {
00187 LM_ERR("could not load routing data\n");
00188 goto errout;
00189 }
00190 break;
00191 default:
00192 LM_ERR("invalid mode");
00193 goto errout;
00194 }
00195 if (new_data == NULL) {
00196 LM_ERR("loading routing data failed (NULL pointer)");
00197 goto errout;
00198 }
00199
00200
00201 qsort(new_data->carriers, new_data->carrier_num, sizeof(new_data->carriers[0]), compare_carrier_data);
00202
00203
00204 for (i=0; i<new_data->carrier_num; i++) {
00205 qsort(new_data->carriers[i]->domains, new_data->carriers[i]->domain_num, sizeof(new_data->carriers[i]->domains[0]), compare_domain_data);
00206 }
00207
00208 if (rule_fixup(new_data) < 0) {
00209 LM_ERR("could not fixup rules\n");
00210 goto errout;
00211 }
00212
00213 if (carrier_data_fixup(new_data) < 0){
00214 LM_ERR("could not fixup trees\n");
00215 goto errout;
00216 }
00217
00218 new_data->proc_cnt = 0;
00219
00220 if (*global_data == NULL) {
00221 *global_data = new_data;
00222 } else {
00223 old_data = *global_data;
00224 *global_data = new_data;
00225 i = 0;
00226 while (old_data->proc_cnt > 0) {
00227 LM_ERR("data is still locked after %i seconds\n", i);
00228 sleep_us(i*1000000);
00229 i++;
00230 }
00231 clear_route_data(old_data);
00232 }
00233 return 0;
00234
00235 errout:
00236 clear_route_data(new_data);
00237 return -1;
00238 }
00239
00240
00248 struct route_data_t * get_data(void) {
00249 struct route_data_t *ret;
00250 if (!global_data || !*global_data) {
00251 return NULL;
00252 }
00253 ret = *global_data;
00254 lock_get(&ret->lock);
00255 ++ret->proc_cnt;
00256 lock_release(&ret->lock);
00257 if (ret == *global_data) {
00258 return ret;
00259 } else {
00260 lock_get(&ret->lock);
00261 --ret->proc_cnt;
00262 lock_release(&ret->lock);
00263 return NULL;
00264 }
00265 }
00266
00267
00273 void release_data(struct route_data_t *data) {
00274 lock_get(&data->lock);
00275 --data->proc_cnt;
00276 lock_release(&data->lock);
00277 }
00278
00279
00289 struct carrier_data_t *get_carrier_data(struct route_data_t * rd, int carrier_id) {
00290 struct carrier_data_t **ret;
00291 struct carrier_data_t key;
00292 struct carrier_data_t *pkey = &key;
00293
00294 if (!rd) {
00295 LM_ERR("NULL pointer in parameter\n");
00296 return NULL;
00297 }
00298 key.id = carrier_id;
00299 ret = bsearch(&pkey, rd->carriers, rd->carrier_num, sizeof(rd->carriers[0]), compare_carrier_data);
00300 if (ret) return *ret;
00301 return NULL;
00302 }
00303
00304
00305 typedef int (*cmpfunc_t)(const void *v1, const void *v2);
00306
00307
00325 static int binary_search(void *base, unsigned int len, int elemsize, void *key, cmpfunc_t cmpfunc, int *index) {
00326 int left, right, mid;
00327
00328 if (index) *index=-1;
00329 if (!base) {
00330 LM_ERR("NULL pointer in parameter\n");
00331 return -1;
00332 }
00333 if (len == 0) {
00334 if (index) *index=0;
00335 return 0;
00336 }
00337
00338 left=0;
00339 right=len-1;
00340 if (cmpfunc(base+elemsize*left, key) > 0) {
00341 LM_DBG("not found (out of left bound)\n");
00342 if (index) *index=0;
00343 return 0;
00344 }
00345 if (cmpfunc(base+elemsize*right, key) < 0) {
00346 LM_DBG("not found (out of right bound)\n");
00347 if (index) *index=len;
00348 return 0;
00349 }
00350
00351 while (left < right) {
00352 mid = left + ((right - left) / 2);
00353 if (cmpfunc(base+elemsize*mid, key) < 0) left = mid + 1;
00354 else right = mid;
00355 }
00356
00357
00358 if (index) *index=left;
00359 if (cmpfunc(base+elemsize*left, key) == 0) return 1;
00360 else return 0;
00361 }
00362
00363
00374 static struct domain_data_t * get_domain_data_or_add(struct route_data_t * rd, struct carrier_data_t * carrier_data, int domain_id) {
00375 struct domain_data_t key;
00376 struct domain_data_t *pkey = &key;
00377 struct domain_data_t *domain_data = NULL;
00378 str *domain_name;
00379 int i;
00380 int res;
00381
00382 if ((!rd) || (!carrier_data)) {
00383 LM_ERR("NULL pointer in parameter\n");
00384 return NULL;
00385 }
00386
00387 key.id = domain_id;
00388 res = binary_search(carrier_data->domains, carrier_data->first_empty_domain, sizeof(struct domain_data_t *), &pkey, compare_domain_data, &i);
00389 if (res<0) {
00390 LM_ERR("error while searching for domain_id %d\n", domain_id);
00391 return NULL;
00392 }
00393 else if (res>0) {
00394
00395 domain_data = carrier_data->domains[i];
00396 }
00397 else {
00398
00399 if ((domain_name = map_id2name(rd->domain_map, rd->domain_num, domain_id)) == NULL) {
00400 LM_ERR("could not find domain name for id %d\n", domain_id);
00401 return NULL;
00402 }
00403 if ((domain_data = create_domain_data(domain_id, domain_name)) == NULL) {
00404 LM_ERR("could not create new domain data\n");
00405 return NULL;
00406 }
00407
00408
00409 if (add_domain_data(carrier_data, domain_data, i) < 0) {
00410 LM_ERR("could not add domain data\n");
00411 destroy_domain_data(domain_data);
00412 return NULL;
00413 }
00414 LM_INFO("added domain %d '%.*s' to carrier %d '%.*s'", domain_id, domain_name->len, domain_name->s, carrier_data->id, carrier_data->name->len, carrier_data->name->s);
00415 }
00416
00417 return domain_data;
00418 }
00419
00420
00451 int add_route(struct route_data_t * rd, int carrier_id,
00452 int domain_id, const str * scan_prefix, flag_t flags, flag_t mask, int max_targets,
00453 double prob, const str * rewrite_hostpart, int strip,
00454 const str * rewrite_local_prefix, const str * rewrite_local_suffix,
00455 int status, int hash_index, int backup, int * backed_up, const str * comment) {
00456 struct carrier_data_t * carrier_data = NULL;
00457 struct domain_data_t * domain_data = NULL;
00458 LM_INFO("adding prefix %.*s, prob %f\n", scan_prefix->len, scan_prefix->s, prob);
00459
00460 if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
00461 LM_ERR("could not retrieve carrier data for carrier id %d\n", carrier_id);
00462 return -1;
00463 }
00464
00465 if ((domain_data = get_domain_data_or_add(rd, carrier_data, domain_id)) == NULL) {
00466 LM_ERR("could not retrieve domain data\n");
00467 return -1;
00468 }
00469
00470 LM_INFO("found carrier and domain, now adding route\n");
00471 return add_route_to_tree(domain_data->tree, scan_prefix, flags, mask, scan_prefix, max_targets, prob, rewrite_hostpart,
00472 strip, rewrite_local_prefix, rewrite_local_suffix, status,
00473 hash_index, backup, backed_up, comment);
00474 }
00475
00476
00496 int add_failure_route(struct route_data_t * rd, int carrier_id, int domain_id,
00497 const str * scan_prefix, const str * host, const str * reply_code,
00498 flag_t flags, flag_t mask, int next_domain_id, const str * comment) {
00499 struct carrier_data_t * carrier_data = NULL;
00500 struct domain_data_t * domain_data = NULL;
00501 LM_INFO("adding prefix %.*s, reply code %.*s\n", scan_prefix->len, scan_prefix->s, reply_code->len, reply_code->s);
00502
00503 if (reply_code->len!=3) {
00504 LM_ERR("invalid reply_code '%.*s'!\n", reply_code->len, reply_code->s);
00505 return -1;
00506 }
00507
00508 if ((carrier_data = get_carrier_data(rd, carrier_id)) == NULL) {
00509 LM_ERR("could not retrieve carrier data\n");
00510 return -1;
00511 }
00512
00513 if ((domain_data = get_domain_data_or_add(rd, carrier_data, domain_id)) == NULL) {
00514 LM_ERR("could not retrieve domain data\n");
00515 return -1;
00516 }
00517
00518 LM_INFO("found carrier and domain, now adding failure route\n");
00519 return add_failure_route_to_tree(domain_data->failure_tree, scan_prefix, scan_prefix, host, reply_code,
00520 flags, mask, next_domain_id, comment);
00521 }
00522
00523
00524 static int fixup_rule_backup(struct route_flags * rf, struct route_rule * rr){
00525 struct route_rule_p_list * rl;
00526 if(!rr->status && rr->backup){
00527 if((rr->backup->rr = find_rule_by_hash(rf, rr->backup->hash_index)) == NULL){
00528 LM_ERR("didn't find backup route\n");
00529 return -1;
00530 }
00531 }
00532 rl = rr->backed_up;
00533 while(rl){
00534 if((rl->rr = find_rule_by_hash(rf, rl->hash_index)) == NULL){
00535 LM_ERR("didn't find backed up route\n");
00536 return -1;
00537 }
00538 rl = rl->next;
00539 }
00540 return 0;
00541 }
00542
00543
00554 static int rule_fixup_recursor(struct dtrie_node_t *node) {
00555 struct route_rule * rr;
00556 struct route_flags * rf;
00557 int i, p_dice, ret = 0;
00558
00559 for (rf=(struct route_flags *)(node->data); rf!=NULL; rf=rf->next) {
00560 p_dice = 0;
00561 if (rf->rule_list) {
00562 rr = rf->rule_list;
00563 rf->rule_num = 0;
00564 while (rr) {
00565 rf->rule_num++;
00566 rf->dice_max += rr->prob * DICE_MAX;
00567 rr = rr->next;
00568 }
00569 rr = rf->rule_list;
00570 while (rr) {
00571 rr->dice_to = (rr->prob * DICE_MAX) + p_dice;
00572 p_dice = rr->dice_to;
00573 rr = rr->next;
00574 }
00575
00576 if (rf->rule_num != rf->max_targets) {
00577 LM_ERR("number of rules(%i) differs from max_targets(%i), maybe your config is wrong?\n", rf->rule_num, rf->max_targets);
00578 return -1;
00579 }
00580 if(rf->rules) {
00581 shm_free(rf->rules);
00582 rf->rules = NULL;
00583 }
00584 if ((rf->rules = shm_malloc(sizeof(struct route_rule *) * rf->rule_num)) == NULL) {
00585 SHM_MEM_ERROR;
00586 return -1;
00587 }
00588 memset(rf->rules, 0, sizeof(struct route_rule *) * rf->rule_num);
00589 for (rr = rf->rule_list; rr; rr = rr->next) {
00590 if (rr->hash_index) {
00591 if (rr->hash_index > rf->rule_num) {
00592 LM_ERR("too large hash index %i, max is %i\n", rr->hash_index, rf->rule_num);
00593 shm_free(rf->rules);
00594 return -1;
00595 }
00596 if (rf->rules[rr->hash_index - 1]) {
00597 LM_ERR("duplicate hash index %i\n", rr->hash_index);
00598 shm_free(rf->rules);
00599 return -1;
00600 }
00601 rf->rules[rr->hash_index - 1] = rr;
00602 LM_INFO("rule with host %.*s hash has hashindex %i.\n", rr->host.len, rr->host.s, rr->hash_index);
00603 }
00604 }
00605
00606 rr = rf->rule_list;
00607 i=0;
00608 while (rr && i < rf->rule_num) {
00609 if (!rr->hash_index) {
00610 if (rf->rules[i]) {
00611 i++;
00612 } else {
00613 rf->rules[i] = rr;
00614 rr->hash_index = i + 1;
00615 LM_INFO("hashless rule with host %.*s hash, hash_index %i\n", rr->host.len, rr->host.s, i+1);
00616 rr = rr->next;
00617 }
00618 } else {
00619 rr = rr->next;
00620 }
00621 }
00622 if (rr) {
00623 LM_ERR("Could not populate rules: rr: %p\n", rr);
00624 return -1;
00625 }
00626 for(i=0; i<rf->rule_num; i++){
00627 ret += fixup_rule_backup(rf, rf->rules[i]);
00628 }
00629 }
00630 }
00631
00632 for (i=0; i<cr_match_mode; i++) {
00633 if (node->child[i]) {
00634 ret += rule_fixup_recursor(node->child[i]);
00635 }
00636 }
00637
00638 return ret;
00639 }
00640
00641
00650 int rule_fixup(struct route_data_t * rd) {
00651 int i,j;
00652 for (i=0; i<rd->carrier_num; i++) {
00653 for (j=0; j<rd->carriers[i]->domain_num; j++) {
00654 if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
00655 LM_INFO("fixing tree %.*s\n", rd->carriers[i]->domains[j]->name->len, rd->carriers[i]->domains[j]->name->s);
00656 if (rule_fixup_recursor(rd->carriers[i]->domains[j]->tree) < 0) {
00657 return -1;
00658 }
00659 } else {
00660 LM_NOTICE("empty tree at [%i][%i]\n", i, j);
00661 }
00662 }
00663 }
00664 return 0;
00665 }