cr_rule.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cr_rule.c 5299 2008-12-04 18:12:33Z henningw $
00003  *
00004  * Copyright (C) 2007-2008 1&1 Internet AG
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio 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  * Kamailio 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 
00023 /**
00024  * \file cr_rule.c
00025  * \brief Contains the functions to manage routing rule data.
00026  * \ingroup carrierroute
00027  * - Module; \ref carrierroute
00028  */
00029 
00030 #include "../../ut.h"
00031 #include "cr_rule.h"
00032 
00033 
00034 /**
00035  * Adds a route rule to rf. prefix, rewrite_hostpart, rewrite_local_prefix,
00036  * rewrite_local_suffix, and comment must not contain NULL pointers.
00037  *
00038  * @param rf the current route_flags struct
00039  * @param prefix the whole scan prefix
00040  * @param max_targets the number of targets
00041  * @param prob the weight of the rule
00042  * @param rewrite_hostpart the rewrite_host of the rule
00043  * @param strip the strip value of the rule
00044  * @param rewrite_local_prefix the rewrite prefix
00045  * @param rewrite_local_suffix the rewrite suffix
00046  * @param status the status of the rule
00047  * @param hash_index the hash index of the rule
00048  * @param backup indicates if the route is backed up by another. only
00049                  useful if status==0, if set, it is the hash value
00050                  of another rule
00051  * @param backed_up an NULL-termintated array of hash indices of the route
00052                     for which this route is backup
00053  * @param comment a comment for the route rule
00054  *
00055  * @return 0 on success, -1 on failure
00056  *
00057  * @see add_route_to_tree()
00058  */
00059 int add_route_rule(struct route_flags *rf, const str * prefix,
00060       int max_targets, double prob, const str * rewrite_hostpart, int strip,
00061       const str * rewrite_local_prefix, const str * rewrite_local_suffix,
00062       int status, int hash_index, int backup, int * backed_up, 
00063       const str * comment) {
00064    struct route_rule * shm_rr, * prev = NULL, * tmp = NULL;
00065    struct route_rule_p_list * t_rl;
00066    int * t_bu;
00067 
00068    if (max_targets) {
00069       rf->max_targets = max_targets;
00070    } else {
00071       rf->max_targets++;
00072    }
00073 
00074    if ((shm_rr = shm_malloc(sizeof(struct route_rule))) == NULL) {
00075       SHM_MEM_ERROR;
00076       return -1;
00077    }
00078    memset(shm_rr, 0, sizeof(struct route_rule));
00079 
00080    if (shm_str_dup(&shm_rr->host, rewrite_hostpart) != 0) {
00081       goto mem_error;
00082    }
00083 
00084    if (shm_str_dup(&shm_rr->prefix, prefix) != 0) {
00085       goto mem_error;
00086    }
00087 
00088    shm_rr->strip = strip;
00089 
00090    if (shm_str_dup(&shm_rr->local_prefix, rewrite_local_prefix) != 0) {
00091       goto mem_error;
00092    }
00093 
00094    if (shm_str_dup(&shm_rr->local_suffix, rewrite_local_suffix) != 0) {
00095       goto mem_error;
00096    }
00097 
00098    if (shm_str_dup(&shm_rr->comment, comment) != 0) {
00099       goto mem_error;
00100    }
00101 
00102    shm_rr->status = status;
00103    shm_rr->hash_index = hash_index;
00104    shm_rr->orig_prob = prob;
00105    if (shm_rr->status || backup != -1) {
00106       shm_rr->prob = prob;
00107    }  else {
00108        shm_rr->prob = 0;
00109    }
00110    if (backup >= 0) {
00111       if ((shm_rr->backup = shm_malloc(sizeof(struct route_rule_p_list))) == NULL) {
00112          goto mem_error;
00113       }
00114       memset(shm_rr->backup, 0, sizeof(struct route_rule_p_list));
00115       shm_rr->backup->hash_index = backup;
00116    }
00117    shm_rr->backed_up = NULL;
00118    t_bu = backed_up;
00119    if(!backed_up){
00120       LM_INFO("no backed up rules\n");
00121    }
00122    while (t_bu && *t_bu != -1) {
00123       if ((t_rl = shm_malloc(sizeof(struct route_rule_p_list))) == NULL) {
00124          goto mem_error;
00125       }
00126       memset(t_rl, 0, sizeof(struct route_rule_p_list));
00127       t_rl->hash_index = *t_bu;
00128       t_rl->next = shm_rr->backed_up;
00129       shm_rr->backed_up = t_rl;
00130       t_bu++;
00131    }
00132 
00133    /* rules with a probability of zero are always at the beginning of the list */
00134    tmp = rf->rule_list;
00135    while(tmp && tmp->prob == 0){
00136       prev = tmp;
00137       tmp = tmp->next;
00138    }
00139    /* rules with prob > 0 are sorted by hash_index */
00140    while(tmp && (tmp->hash_index < shm_rr->hash_index)){
00141       prev = tmp;
00142       tmp = tmp->next;
00143    }
00144    if(prev){
00145       shm_rr->next = prev->next;
00146       prev->next = shm_rr;
00147    } else {
00148       shm_rr->next = rf->rule_list;
00149       rf->rule_list = shm_rr;
00150    }
00151 
00152    return 0;
00153 
00154 mem_error:
00155    SHM_MEM_ERROR;
00156    destroy_route_rule(shm_rr);
00157    return -1;
00158 }
00159 
00160 
00161 /**
00162  * Destroys route rule rr by freeing all its memory.
00163  *
00164  * @param rr route rule to be destroyed
00165  */
00166 void destroy_route_rule(struct route_rule * rr) {
00167    struct route_rule_p_list * t_rl;
00168    if (rr->host.s) {
00169       shm_free(rr->host.s);
00170    }
00171    if (rr->local_prefix.s) {
00172       shm_free(rr->local_prefix.s);
00173    }
00174    if (rr->local_suffix.s) {
00175       shm_free(rr->local_suffix.s);
00176    }
00177    if (rr->comment.s) {
00178       shm_free(rr->comment.s);
00179    }
00180    if (rr->prefix.s) {
00181       shm_free(rr->prefix.s);
00182    }
00183    if(rr->backup){
00184       shm_free(rr->backup);
00185    }
00186    while(rr->backed_up){
00187       t_rl = rr->backed_up->next;
00188       shm_free(rr->backed_up);
00189       rr->backed_up = t_rl;
00190    }
00191    shm_free(rr);
00192    return;
00193 }
00194 
00195 
00196 /**
00197  * Try to find a matching route_flags struct in rt and return it, add it if not found.
00198  *
00199  * @param rf_head pointer to the head of the route flags list, might be changed during insert.
00200  * @param flags user defined flags
00201  * @param mask mask for user defined flags
00202  *
00203  * @return pointer to the route_flags struct on success, NULL on failure.
00204  *
00205  */
00206 struct route_flags * add_route_flags(struct route_flags **rf_head, const flag_t flags, const flag_t mask)
00207 {
00208    struct route_flags *shm_rf;
00209    struct route_flags *prev_rf, *tmp_rf;
00210    prev_rf = tmp_rf = NULL;
00211 
00212    if (rf_head) {
00213       /* search for matching route_flags struct */
00214       for (tmp_rf=*rf_head; tmp_rf!=NULL; tmp_rf=tmp_rf->next) {
00215          if ((tmp_rf->flags == flags) && (tmp_rf->mask == mask)) return tmp_rf;
00216       }
00217       
00218       /* not found, insert one */
00219       for (tmp_rf=*rf_head; tmp_rf!=NULL; tmp_rf=tmp_rf->next) {
00220          if (tmp_rf->mask < mask) break;
00221          prev_rf=tmp_rf;
00222       }
00223    }
00224 
00225    if ((shm_rf = shm_malloc(sizeof(struct route_flags))) == NULL) {
00226       SHM_MEM_ERROR;
00227       return NULL;
00228    }
00229    memset(shm_rf, 0, sizeof(struct route_flags));
00230 
00231    shm_rf->flags=flags;
00232    shm_rf->mask=mask;
00233    shm_rf->next=tmp_rf;
00234    
00235    if (prev_rf) {
00236       prev_rf->next = shm_rf;
00237    }
00238    else {
00239       if (rf_head) *rf_head=shm_rf;
00240    }
00241 
00242    return shm_rf;
00243 }
00244 
00245 
00246 /**
00247  * Destroys route_flags in shared memory by freing all its memory.
00248  *
00249  * @param rf route_flags struct to be destroyed
00250  */
00251 void destroy_route_flags(struct route_flags *rf) {
00252    struct route_rule *rs, *rs_tmp;
00253 
00254    if (rf->rules) {
00255       shm_free(rf->rules);
00256    }
00257    rs = rf->rule_list;
00258    while (rs != NULL) {
00259       rs_tmp = rs->next;
00260       destroy_route_rule(rs);
00261       rs = rs_tmp;
00262    }
00263    shm_free(rf);
00264 }
00265 
00266 
00267 /**
00268  * Compares the priority of two failure route rules.
00269  *
00270  * @param frr1 first failure rule
00271  * @param frr2 second failure rule
00272  *
00273  * @return 0 if frr1 and frr2 have the same priority, -1 if frr1 has higher priority than frr2, 1 if frr1 has lower priority than frr2.
00274  *
00275  * @see add_failure_route_to_tree()
00276  */
00277 static int failure_rule_prio_cmp(struct failure_route_rule *frr1, struct failure_route_rule *frr2) {
00278    int n1, n2, i;
00279    
00280    /* host has highest priority */
00281    if ((frr1->host.len == 0) && (frr2->host.len > 0)) {
00282       /* host1 is wildcard -> frr1 has lower priority */
00283       return 1;
00284    }
00285    else if ((frr1->host.len > 0) && (frr2->host.len == 0)) {
00286       /* host2 is wildcard -> frr1 has higher priority */
00287       return -1;
00288    }
00289    else {
00290       /* reply_code has second highest priority */
00291       n1=0;
00292       n2=0;
00293       for (i=0; i < frr1->reply_code.len; i++) {
00294          if (frr1->reply_code.s[i]=='.') n1++;
00295       }
00296       for (i=0; i < frr2->reply_code.len; i++) {
00297          if (frr2->reply_code.s[i]=='.') n2++;
00298       }
00299       if (n1 < n2) {
00300          /* reply_code1 has fewer wildcards -> frr1 has higher priority */
00301          return -1;
00302       }
00303       else if (n1 > n2) {
00304          /* reply_code1 has more wildcards -> frr1 has lower priority */
00305          return 1;
00306       }
00307       else {
00308          /* flags have lowest priority */
00309          if (frr1->mask > frr2->mask) {
00310             return -1;
00311          }
00312          else if (frr1->mask < frr2->mask) {
00313             return 1;
00314          }
00315       }
00316    }
00317    
00318    return 0;
00319 }
00320 
00321 
00322 /**
00323  * Adds a failure route rule to rule list. prefix, host, reply_code, and comment
00324  * must not contain NULL pointers.
00325  *
00326  * @param frr_head pointer to the head of the failure route rule list, might be changed during insert
00327  * @param prefix the whole scan prefix
00328  * @param host the hostname last tried
00329  * @param reply_code the reply code 
00330  * @param flags user defined flags
00331  * @param mask mask for user defined flags
00332  * @param next_domain continue routing with this domain
00333  * @param comment a comment for the route rule
00334  *
00335  * @return pointer to the failure_route_rul struct on success, NULL on failure.
00336  *
00337  * @see add_failure_route_to_tree()
00338  */
00339 struct failure_route_rule *add_failure_route_rule(struct failure_route_rule **frr_head,
00340       const str * prefix, const str * host, const str * reply_code,
00341       flag_t flags, flag_t mask, const int next_domain, const str * comment) {
00342    struct failure_route_rule *shm_frr, *frr, *prev;
00343    frr = prev = NULL;
00344    
00345    if ((shm_frr = shm_malloc(sizeof(struct failure_route_rule))) == NULL) {
00346       SHM_MEM_ERROR;
00347       return NULL;
00348    }
00349    memset(shm_frr, 0, sizeof(struct failure_route_rule));
00350    
00351    if (shm_str_dup(&shm_frr->host, host) != 0) {
00352       goto mem_error;
00353    }
00354    
00355    if (shm_str_dup(&shm_frr->reply_code, reply_code) != 0) {
00356       goto mem_error;
00357    }
00358    
00359    shm_frr->flags = flags;
00360    shm_frr->mask = mask;
00361    shm_frr->next_domain = next_domain;
00362    
00363    if (shm_str_dup(&shm_frr->comment, comment) != 0) {
00364       goto mem_error;
00365    }
00366    
00367    /* before inserting into list, check priorities! */
00368    if (frr_head) {
00369       frr=*frr_head;
00370       prev=NULL;
00371       while ((frr != NULL) && (failure_rule_prio_cmp(shm_frr, frr) > 0)) {
00372          prev=frr;
00373          frr=frr->next;
00374       }
00375    }
00376 
00377    shm_frr->next = frr;
00378 
00379    if(prev){
00380       prev->next = shm_frr;
00381    }
00382    else {
00383       if (frr_head) *frr_head=shm_frr;
00384    }
00385 
00386    return shm_frr;
00387    
00388 mem_error:
00389    SHM_MEM_ERROR;
00390    destroy_failure_route_rule(shm_frr);
00391    return NULL;
00392 }
00393 
00394 
00395 /**
00396  * Destroys failure route rule frr by freeing all its memory.
00397  *
00398  * @param frr route rule to be destroyed
00399  */
00400 void destroy_failure_route_rule(struct failure_route_rule * frr) {
00401    if (frr->host.s) {
00402       shm_free(frr->host.s);
00403    }
00404    if (frr->comment.s) {
00405       shm_free(frr->comment.s);
00406    }
00407    if (frr->prefix.s) {
00408       shm_free(frr->prefix.s);
00409    }
00410    if (frr->reply_code.s) {
00411       shm_free(frr->reply_code.s);
00412    }
00413    shm_free(frr);
00414    return;
00415 }
00416 
00417 
00418 struct route_rule * find_rule_by_hash(struct route_flags * rf, int hash){
00419    struct route_rule * rr;
00420    rr = rf->rule_list;
00421    while(rr){
00422       if(rr->hash_index == hash){
00423          return rr;
00424       }
00425       rr = rr->next;
00426    }
00427    return NULL;
00428 }
00429 
00430 
00431 struct route_rule * find_rule_by_host(struct route_flags * rf, str * host){
00432    struct route_rule * rr;
00433    rr = rf->rule_list;
00434    while(rr){
00435       if(str_strcmp(&(rr->host), host) == 0){
00436          return rr;
00437       }
00438       rr = rr->next;
00439    }
00440    return NULL;
00441 }
00442 
00443 
00444 int add_backup_rule(struct route_rule * rule, struct route_rule * backup){
00445    struct route_rule_p_list * tmp = NULL;
00446    if(!backup->status){
00447       LM_ERR("desired backup route is inactive\n");
00448       return -1;
00449    }
00450    if((tmp = shm_malloc(sizeof(struct route_rule_p_list))) == NULL) {
00451       SHM_MEM_ERROR;
00452       return -1;
00453    }
00454    memset(tmp, 0, sizeof(struct route_rule_p_list));
00455    tmp->hash_index = rule->hash_index;
00456    tmp->rr = rule;
00457    tmp->next = backup->backed_up;
00458    backup->backed_up =  tmp;
00459 
00460    tmp = NULL;
00461    if((tmp = shm_malloc(sizeof(struct route_rule_p_list))) == NULL) {
00462       SHM_MEM_ERROR;
00463       return -1;
00464    }
00465    memset(tmp, 0, sizeof(struct route_rule_p_list));
00466    tmp->hash_index = backup->hash_index;
00467    tmp->rr = backup;
00468    rule->backup = tmp;
00469 
00470    if(rule->backed_up){
00471       tmp = rule->backed_up;
00472       while(tmp->next) {
00473          tmp = tmp->next;
00474       }
00475       tmp->next = backup->backed_up;
00476       backup->backed_up = rule->backed_up;
00477       rule->backed_up = NULL;
00478    }
00479    tmp = rule->backup->rr->backed_up;
00480    while(tmp) {
00481       tmp->rr->backup->hash_index = rule->backup->hash_index;
00482       tmp->rr->backup->rr = rule->backup->rr;
00483       tmp = tmp->next;
00484    }
00485    return 0;
00486 }
00487 
00488 
00489 int remove_backed_up(struct route_rule * rule){
00490    struct route_rule_p_list * rl, * prev = NULL;
00491    if(rule->backup) {
00492       if(rule->backup->rr) {
00493          rl = rule->backup->rr->backed_up;
00494          while(rl) {
00495             if(rl->hash_index == rule->hash_index) {
00496                if(prev) {
00497                   prev->next = rl->next;
00498                } else {
00499                   rule->backup->rr->backed_up = rl->next;
00500                }
00501                shm_free(rl);
00502                shm_free(rule->backup);
00503                rule->backup = NULL;
00504                return 0;
00505             }
00506             prev = rl;
00507             rl = rl->next;
00508          }
00509       }
00510       return -1;
00511    }
00512    return 0;
00513 }
00514 
00515 
00516 struct route_rule * find_auto_backup(struct route_flags * rf, struct route_rule * rule){
00517    struct route_rule * rr;
00518    rr = rf->rule_list;
00519    while(rr){
00520       if(!rr->backed_up && (rr->hash_index != rule->hash_index) && rr->status){
00521          return rr;
00522       }
00523       rr = rr->next;
00524    }
00525    return NULL;
00526 }

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6