00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
00041
00042
00043
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
00066
00067
00068
00069
00070
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
00085
00086
00087
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
00099
00100
00101
00102
00103
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
00135
00136
00137
00138
00139
00140
00141
00142
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
00160
00161
00162
00163
00164
00165
00166
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
00241
00242
00243
00244
00245
00246
00247
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
00268
00269
00270
00271
00272
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
00280
00281
00282
00283
00284
00285
00286
00287
00288
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
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
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
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
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
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
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
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
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
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
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
00642
00643
00644
00645
00646
00647
00648
00649
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 }