cr_rule.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 "../../ut.h"
00031 #include "cr_rule.h"
00032 
00033 
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 
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 
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 
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 
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 
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 
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 }