cr_data.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007-2008 1&1 Internet AG
00005  *
00006  * This file is part of SIP-router, a free SIP server.
00007  *
00008  * SIP-router is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * SIP-router is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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         /* sort carriers by id for faster access */
00201         qsort(new_data->carriers, new_data->carrier_num, sizeof(new_data->carriers[0]), compare_carrier_data);
00202 
00203         /* sort domains by id for faster access */
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; /* not found, must be inserted at the beginning of array */
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; /* not found, must be inserted at the end of array */
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         /* left == right here! */
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                 /* found domain id */
00395                 domain_data = carrier_data->domains[i];
00396         }
00397         else {
00398                 /* did not find domain id - insert new entry! */
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                 /* keep the array sorted! */
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 }