cr_fifo.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cr_fifo.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_fifo.c
00025  * \brief Functions for modifying routing data via fifo commands.
00026  * \ingroup carrierroute
00027  * - Module; \ref carrierroute
00028  */
00029 
00030 #include <ctype.h>
00031 #include <stdlib.h>
00032 
00033 #include "../../mem/mem.h"
00034 #include "../../mem/shm_mem.h"
00035 #include "../../str.h"
00036 #include "../../ut.h"
00037 
00038 #include "cr_fifo.h"
00039 #include "carrierroute.h"
00040 #include "cr_config.h"
00041 #include "cr_carrier.h"
00042 #include "cr_domain.h"
00043 #include "cr_rule.h"
00044 
00045 
00046 /**
00047  * Defines the option set for the different fifo commands
00048  * Every line is for a command,
00049  * The first field defines the required options, the second field defines the
00050  * optional options and the third field defines the invalid options.
00051  */
00052 static unsigned int opt_settings[5][3] = {{O_PREFIX|O_DOMAIN|O_HOST|O_PROB, O_R_PREFIX|O_R_SUFFIX|O_H_INDEX, O_NEW_TARGET},
00053         {O_HOST|O_DOMAIN|O_PREFIX, O_PROB, O_R_PREFIX|O_R_SUFFIX|O_NEW_TARGET|O_H_INDEX},
00054         {O_HOST|O_NEW_TARGET, O_PREFIX|O_DOMAIN|O_PROB, O_R_PREFIX|O_R_SUFFIX|O_H_INDEX},
00055         {O_HOST|O_DOMAIN|O_PREFIX, O_PROB|O_NEW_TARGET, O_R_PREFIX|O_R_SUFFIX|O_H_INDEX},
00056         {O_HOST|O_DOMAIN|O_PREFIX, O_PROB, O_R_PREFIX|O_R_SUFFIX|O_NEW_TARGET|O_H_INDEX}};
00057 
00058 int fifo_err;
00059 
00060 static int updated;
00061 
00062 static int dump_tree_recursor (struct mi_node* msg, struct dtrie_node_t *node, char *prefix);
00063 
00064 static struct mi_root* print_replace_help(void);
00065 
00066 static int get_fifo_opts(str * buf, fifo_opt_t * opts, unsigned int opt_set[]);
00067 
00068 static int update_route_data(fifo_opt_t * opts);
00069 
00070 static int update_route_data_recursor(struct dtrie_node_t *node, str * act_domain, fifo_opt_t * opts);
00071 
00072 static struct mi_root* print_fifo_err(void);
00073 
00074 
00075 static int str_toklen(str * str, const char * delims)
00076 {
00077    int len;
00078    
00079    if ((str==NULL) || (str->s==NULL)) {
00080       /* No more tokens */
00081       return -1;
00082    }
00083    
00084    len=0;
00085    while (len<str->len) {
00086       if (strchr(delims,str->s[len])!=NULL) {
00087          return len;
00088       }
00089       len++;
00090    }
00091    
00092    return len;
00093 }
00094 
00095 
00096 /**
00097  * reloads the routing data
00098  *
00099  * @param cmd_tree the MI command tree
00100  * @param param the parameter
00101  *
00102  * @return code 200 on success, code 500 on failure
00103  */
00104 struct mi_root* reload_fifo (struct mi_root* cmd_tree, void *param) {
00105    struct mi_root * tmp = NULL;
00106 
00107    if (reload_route_data () == -1) {
00108       tmp = init_mi_tree(500, "failed to re-built tree, see log", 33);
00109    }
00110    else {
00111       tmp = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00112    }
00113    return tmp;
00114 }
00115 
00116 
00117 /**
00118  * prints the routing data
00119  *
00120  * @param cmd_tree the MI command tree
00121  * @param param the parameter
00122  *
00123  * @return code 200 on success, code 400 or 500 on failure
00124  */
00125 struct mi_root* dump_fifo (struct mi_root* cmd_tree, void *param) {
00126    struct route_data_t * rd;
00127    str *tmp_str;
00128    str empty_str = str_init("<empty>");
00129 
00130    if((rd = get_data ()) == NULL) {
00131       LM_ERR("error during retrieve data\n");
00132       return init_mi_tree(500, "error during command processing", 31);
00133    }
00134    
00135    struct mi_root* rpl_tree;
00136    struct mi_node* node = NULL;
00137    rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00138    if(rpl_tree == NULL)
00139       return 0;
00140    node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "Printing routing information:");
00141    if(node == NULL)
00142       goto error;
00143 
00144    LM_DBG("start processing of data\n");
00145    int i, j;
00146    for (i = 0; i < rd->carrier_num; i++) {
00147       if (rd->carriers[i]) {
00148          tmp_str = (rd->carriers[i] ? rd->carriers[i]->name : &empty_str);
00149          node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "Printing tree for carrier '%.*s' (%i)\n", tmp_str->len, tmp_str->s, rd->carriers[i] ? rd->carriers[i]->id : 0);
00150          if(node == NULL)
00151             goto error;
00152          for (j=0; j<rd->carriers[i]->domain_num; j++) {
00153             if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
00154                tmp_str = (rd->carriers[i]->domains[j] ? rd->carriers[i]->domains[j]->name : &empty_str);
00155                node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "Printing tree for domain '%.*s' (%i)\n", tmp_str->len, tmp_str->s, rd->carriers[i]->domains[j]->id);
00156                if(node == NULL)
00157                   goto error;
00158                dump_tree_recursor (&rpl_tree->node, rd->carriers[i]->domains[j]->tree, "");
00159             }
00160          }
00161       }
00162    }
00163    release_data (rd);
00164    return rpl_tree;
00165    return 0;
00166 
00167 error:
00168    release_data (rd);
00169    free_mi_tree(rpl_tree);
00170    return 0;
00171 }
00172 
00173 
00174 /**
00175  * replaces the host specified by parameters in the
00176  * fifo command, can be used only in file mode
00177  * expect one mi node that contains the command
00178  *
00179  * @param cmd_tree the MI command tree
00180  * @param param the parameter
00181  *
00182  * @return code 200 on success, code 400 or 500 on failure
00183  */
00184 struct mi_root* replace_host (struct mi_root* cmd_tree, void *param) {
00185    struct mi_node *node = NULL;
00186 
00187    int ret;
00188    fifo_opt_t options;
00189 
00190    if(mode != CARRIERROUTE_MODE_FILE) {
00191       return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00192    }
00193    
00194    node = cmd_tree->node.kids;
00195    if (node==NULL || node->next!=NULL)
00196       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00197 
00198    
00199    /* look for command */
00200    if (node->value.s==NULL)
00201       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00202 
00203    if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_REPLACE])) <  0) {
00204       return print_fifo_err();
00205    }
00206 
00207    options.status = 1;
00208    options.cmd = OPT_REPLACE;
00209 
00210    if(update_route_data(&options) < 0) {
00211       return init_mi_tree(500, "failed to update route data, see log", 37);
00212    }
00213 
00214    return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00215 }
00216 
00217 
00218 /**
00219  * deactivates the host given in the command line options,
00220  * can be used only in file mode
00221  * expect one mi node that contains the command
00222  *
00223  * @param cmd_tree the MI command tree
00224  * @param param the parameter
00225  *
00226  * @return code 200 on success, code 400 or 500 on failure
00227  */
00228 struct mi_root* deactivate_host (struct mi_root* cmd_tree, void *param) {
00229    struct mi_node *node = NULL;
00230 
00231    int ret;
00232    fifo_opt_t options;
00233 
00234    if(mode != CARRIERROUTE_MODE_FILE) {
00235       return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00236    }
00237 
00238    node = cmd_tree->node.kids;
00239    if (node==NULL || node->next!=NULL)
00240       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00241 
00242    
00243    /* look for command */
00244    if (node->value.s==NULL)
00245       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00246 
00247    if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_DEACTIVATE])) <  0) {
00248       return print_fifo_err();
00249    }
00250 
00251    options.status = 0;
00252    options.cmd = OPT_DEACTIVATE;
00253 
00254    if(update_route_data(&options) < 0) {
00255       return init_mi_tree(500, "failed to update route data, see log", 37);
00256    }
00257 
00258    return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00259 }
00260 
00261 
00262 /**
00263  * activates the host given in the command line options,
00264  * can be used only in file mode
00265  * expect one mi node that contains the command
00266  *
00267  * @param cmd_tree the MI command tree
00268  * @param param the parameter
00269  *
00270  * @return code 200 on success, code 400 or 500 on failure
00271  */
00272 struct mi_root* activate_host (struct mi_root* cmd_tree, void *param) {
00273    struct mi_node *node = NULL;
00274 
00275    int ret;
00276    fifo_opt_t options;
00277 
00278    if(mode != CARRIERROUTE_MODE_FILE) {
00279       return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00280    }
00281 
00282    node = cmd_tree->node.kids;
00283    if (node==NULL || node->next!=NULL)
00284       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00285 
00286    
00287    /* look for command */
00288    if (node->value.s==NULL)
00289       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00290 
00291    if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_ACTIVATE])) <  0) {
00292       return print_fifo_err();
00293    }
00294 
00295    options.status = 1;
00296    options.cmd = OPT_ACTIVATE;
00297 
00298    if(update_route_data(&options) < 0) {
00299       return init_mi_tree(500, "failed to update route data, see log", 37);
00300    }
00301 
00302    return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00303 }
00304 
00305 
00306 /**
00307  * adds the host specified by the command line args,
00308  * can be used only in file mode
00309  * expect one mi node that contains the command
00310  *
00311  * @param cmd_tree the MI command tree
00312  * @param param the parameter
00313  *
00314  * @return code 200 on success, code 400 or 500 on failure
00315  */
00316 struct mi_root* add_host (struct mi_root* cmd_tree, void *param) {
00317    struct mi_node *node = NULL;
00318 
00319    int ret;
00320    fifo_opt_t options;
00321 
00322    if(mode != CARRIERROUTE_MODE_FILE) {
00323       return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00324    }
00325 
00326    node = cmd_tree->node.kids;
00327    if (node==NULL || node->next!=NULL || node->value.s==NULL) {
00328       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00329    }
00330 
00331    if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_ADD])) <  0) {
00332       return print_fifo_err();
00333    }
00334 
00335    options.status = 1;
00336    options.cmd = OPT_ADD;
00337 
00338    if(update_route_data(&options) < 0) {
00339       return init_mi_tree(500, "failed to update route data, see log", 37);
00340    }
00341 
00342    return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00343 }
00344 
00345 
00346 /**
00347  * deletes the host specified by the command line args,
00348  * can be used only in file mode
00349  * expect one mi node that contains the command
00350  *
00351  * @param cmd_tree the MI command tree
00352  * @param param the parameter
00353  *
00354  * @return code 200 on success, code 400 or 500 on failure
00355  */
00356 struct mi_root* delete_host (struct mi_root* cmd_tree, void * param) {
00357    struct mi_node *node = NULL;
00358 
00359    int ret;
00360    fifo_opt_t options;
00361 
00362    if(mode != CARRIERROUTE_MODE_FILE) {
00363       return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00364    }
00365 
00366    node = cmd_tree->node.kids;
00367    if (node==NULL || node->next!=NULL)
00368       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00369 
00370    
00371    /* look for command */
00372    if (node->value.s==NULL)
00373       return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00374 
00375    if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_REMOVE])) <  0) {
00376       return print_fifo_err();
00377    }
00378 
00379    options.cmd = OPT_REMOVE;
00380 
00381    if(update_route_data(&options) < 0) {
00382       return init_mi_tree(500, "failed to update route data, see log", 37);
00383    }
00384 
00385    return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00386 }
00387 
00388 
00389 /**
00390  * does the work for dump_fifo, traverses the routing tree
00391  * and prints route rules if present.
00392  *
00393  * @param msg MI node that is used to append the informations
00394  * @param node pointer to the routing tree node
00395  * @param prefix carries the current scan prefix
00396  *
00397  * @return mi node containing the route rules
00398  */
00399 static int dump_tree_recursor (struct mi_node* msg, struct dtrie_node_t *node, char *prefix) {
00400    char s[256];
00401    char *p;
00402    int i;
00403    struct route_flags *rf;
00404    struct route_rule *rr;
00405    struct route_rule_p_list * rl;
00406    double prob;
00407 
00408    strcpy (s, prefix);
00409    p = s + strlen (s);
00410    p[1] = '\0';
00411    for (i = 0; i < cr_match_mode; ++i) {
00412       if (node->child[i] != NULL) {
00413          *p = i + '0';
00414          dump_tree_recursor (msg->next, node->child[i], s);
00415       }
00416    }
00417    *p = '\0';
00418    for (rf = (struct route_flags *)(node->data); rf != NULL; rf = rf->next) {
00419       for (rr = rf->rule_list; rr != NULL; rr = rr->next) {
00420          if(rf->dice_max){
00421             prob = (double)(rr->prob * DICE_MAX)/(double)rf->dice_max;
00422          } else {
00423             prob = rr->prob;
00424          }
00425          addf_mi_node_child(msg->next, 0, 0, 0, "%10s: %0.3f %%, '%.*s': %s, '%i', '%.*s', '%.*s', '%.*s'\n",
00426                                      strlen(prefix) > 0 ? prefix : "NULL", prob * 100, rr->host.len, rr->host.s,
00427                                      (rr->status ? "ON" : "OFF"), rr->strip,
00428                                      rr->local_prefix.len, rr->local_prefix.s,
00429                                      rr->local_suffix.len, rr->local_suffix.s,
00430                                      rr->comment.len, rr->comment.s);
00431          if(!rr->status && rr->backup && rr->backup->rr){
00432             addf_mi_node_child(msg->next, 0, 0, 0, "            Rule is backed up by: %.*s\n", rr->backup->rr->host.len, rr->backup->rr->host.s);
00433          }
00434          if(rr->backed_up){
00435             rl = rr->backed_up;
00436             i=0;
00437             while(rl){
00438                if(rl->rr){
00439                   addf_mi_node_child(msg->next, 0, 0, 0, "            Rule is backup for: %.*s", rl->rr->host.len, rl->rr->host.s);
00440                }
00441                rl = rl->next;
00442                i++;
00443             }
00444          }
00445       }
00446    }
00447    return 0;
00448 }
00449 
00450 
00451 /**
00452  * parses the command line argument for options
00453  *
00454  * @param buf the command line argument
00455  * @param opts fifo options
00456  * @param opt_set set of the options
00457  *
00458  * @return 0 on success, -1 on failure
00459  *
00460  * @see dump_fifo()
00461  */
00462 static int get_fifo_opts(str * buf, fifo_opt_t * opts, unsigned int opt_set[]) {
00463    int opt_argc = 0;
00464    str opt_argv[20];
00465    int i, op = -1;
00466    unsigned int used_opts = 0;
00467    int toklen;
00468 
00469    memset(opt_argv, 0, sizeof(opt_argv));
00470    memset(opts, 0, sizeof(fifo_opt_t));
00471    opts->prob = -1;
00472 
00473    while((toklen = str_toklen(buf, " \t\r\n")) >=0 && opt_argc < 20) {
00474       buf->s[toklen] = '\0'; /* insert zero termination, since strtod might be used later on it */
00475       opt_argv[opt_argc].len = toklen;
00476       opt_argv[opt_argc].s = buf->s;
00477       buf->s += toklen + 1;
00478       buf->len -= toklen + 1;
00479       LM_DBG("found arg[%i]: %.*s\n", opt_argc, opt_argv[opt_argc].len, opt_argv[opt_argc].s);
00480       opt_argc++;
00481    }
00482    for (i=0; i<opt_argc; i++) {
00483       LM_DBG("token %.*s", opt_argv[i].len, opt_argv[i].s);
00484       if (opt_argv[i].len >= 1) {
00485          switch(*opt_argv[i].s) {
00486                case '-': switch(opt_argv[i].s[1]) {
00487                      case OPT_DOMAIN_CHR:
00488                      op = OPT_DOMAIN;
00489                      used_opts |= O_DOMAIN;
00490                      break;
00491                      case OPT_PREFIX_CHR:
00492                      op = OPT_PREFIX;
00493                      used_opts |= O_PREFIX;
00494                      break;
00495                      case OPT_HOST_CHR:
00496                      op = OPT_HOST;
00497                      used_opts |= O_HOST;
00498                      break;
00499                      case OPT_NEW_TARGET_CHR:
00500                      op = OPT_NEW_TARGET;
00501                      used_opts |= O_NEW_TARGET;
00502                      break;
00503                      case OPT_PROB_CHR:
00504                      op = OPT_PROB;
00505                      used_opts |= O_PROB;
00506                      break;
00507                      case OPT_R_PREFIX_CHR:
00508                      op = OPT_R_PREFIX;
00509                      used_opts |= O_R_PREFIX;
00510                      break;
00511                      case OPT_R_SUFFIX_CHR:
00512                      op = OPT_R_SUFFIX;
00513                      used_opts |= O_R_SUFFIX;
00514                      break;
00515                      case OPT_HASH_INDEX_CHR:
00516                      op = OPT_HASH_INDEX;
00517                      used_opts |= O_H_INDEX;
00518                      break;
00519                      case OPT_HELP_CHR:
00520                      FIFO_ERR(E_HELP);
00521                      return -1;
00522                      default: {
00523                         FIFO_ERR(E_WRONGOPT);
00524                         LM_DBG("Unknown option: %.*s\n", opt_argv[i].len, opt_argv[i].s);
00525                         return -1;
00526                      }
00527                }
00528                break;
00529                default: switch(op) {
00530                      case OPT_DOMAIN:
00531                      opts->domain = opt_argv[i];
00532                      op = -1;
00533                      break;
00534                      case OPT_PREFIX:
00535                      if (str_strcasecmp(&opt_argv[i], &CR_EMPTY_PREFIX) == 0) {
00536                         opts->prefix.s = NULL;
00537                         opts->prefix.len = 0;
00538                      } else {
00539                         opts->prefix = opt_argv[i];
00540                      }
00541                      op = -1;
00542                      break;
00543                      case OPT_HOST:
00544                      opts->host = opt_argv[i];
00545                      op = -1;
00546                      break;
00547                      case OPT_NEW_TARGET:
00548                      opts->new_host = opt_argv[i];
00549                      op = -1;
00550                      break;
00551                      case OPT_PROB:
00552                      opts->prob = strtod(opt_argv[i].s, NULL); /* we can use str.s since we zero terminated it earlier */
00553                      op = -1;
00554                      break;
00555                      case OPT_R_PREFIX:
00556                      opts->rewrite_prefix = opt_argv[i];
00557                      op = -1;
00558                      break;
00559                      case OPT_STRIP:
00560                      str2sint(&opt_argv[i], &opts->strip);
00561                      op = -1;
00562                      break;
00563                      case OPT_R_SUFFIX:
00564                      opts->rewrite_suffix = opt_argv[i];
00565                      op = -1;
00566                      break;
00567                      case OPT_HASH_INDEX:
00568                      str2sint(&opt_argv[i], &opts->hash_index);
00569                      op = -1;
00570                      break;
00571                      default: {
00572                         LM_DBG("No option given\n");
00573                         FIFO_ERR(E_NOOPT);
00574                         return -1;
00575                      }
00576                }
00577                break;
00578          }
00579       }
00580    }
00581    if((used_opts & opt_set[OPT_INVALID]) != 0) {
00582       LM_DBG("invalid option\n");
00583       FIFO_ERR(E_INVALIDOPT);
00584       return -1;
00585    }
00586    if((used_opts & opt_set[OPT_MANDATORY]) != opt_set[OPT_MANDATORY]) {
00587       LM_DBG("option missing\n");
00588       FIFO_ERR(E_MISSOPT);
00589       return -1;
00590    }
00591    return 0;
00592 }
00593 
00594 
00595 /**
00596  * loads the config data into shared memory (but doesn't really
00597  * share it), updates the routing data and writes it to the config
00598  * file. Afterwards, the global routing data is reloaded.
00599  *
00600  * @param opts pointer to the option structure which contains
00601  * data to be modified or to be added
00602  *
00603  * @return 0 on success, -1 on failure
00604  */
00605 static int update_route_data(fifo_opt_t * opts) {
00606    struct route_data_t * rd;
00607    int i,j;
00608    int domain_id;
00609    str tmp_domain;
00610    str tmp_prefix;
00611    str tmp_host;
00612    str tmp_rewrite_prefix;
00613    str tmp_rewrite_suffix;
00614    str tmp_comment = str_init("");
00615 
00616    if ((rd = shm_malloc(sizeof(struct route_data_t))) == NULL) {
00617       SHM_MEM_ERROR;
00618       return -1;
00619    }
00620    memset(rd, 0, sizeof(struct route_data_t));
00621    if (load_config(rd) < 0) {
00622       LM_ERR("could not load config");
00623       FIFO_ERR(E_LOADCONF);
00624       return -1;
00625    }
00626 
00627    if (rule_fixup(rd) < 0) {
00628       LM_ERR("could not fixup rules");
00629       FIFO_ERR(E_RULEFIXUP);
00630       return -1;
00631    }
00632    updated = 0;
00633 
00634    if (opts->cmd == OPT_ADD) {
00635       tmp_domain=opts->domain;
00636       tmp_prefix=opts->prefix;
00637       tmp_host=opts->host;
00638       tmp_rewrite_prefix=opts->rewrite_prefix;
00639       tmp_rewrite_suffix=opts->rewrite_suffix;
00640       if (tmp_domain.s==NULL) {
00641          tmp_domain.s="";
00642          tmp_domain.len=0;
00643       }
00644       if (tmp_prefix.s==NULL) {
00645          tmp_prefix.s="";
00646          tmp_prefix.len=0;
00647       }
00648       if (tmp_host.s==NULL) {
00649          tmp_host.s="";
00650          tmp_host.len=0;
00651       }
00652       if (tmp_rewrite_prefix.s==NULL) {
00653          tmp_rewrite_prefix.s="";
00654          tmp_rewrite_prefix.len=0;
00655       }
00656       if (tmp_rewrite_suffix.s==NULL) {
00657          tmp_rewrite_suffix.s="";
00658          tmp_rewrite_suffix.len=0;
00659       }
00660 
00661       domain_id = map_name2id(rd->domain_map, rd->domain_num, &tmp_domain);
00662       if (domain_id < 0) {
00663          LM_ERR("cannot find id for domain '%.*s'", tmp_domain.len, tmp_domain.s);
00664          goto errout;
00665       }
00666 
00667       if (add_route(rd, 1, domain_id, &tmp_prefix, 0, 0, 0, opts->prob,
00668                     &tmp_host, opts->strip, &tmp_rewrite_prefix, &tmp_rewrite_suffix,
00669                     opts->status, opts->hash_index, -1, NULL, &tmp_comment) < 0) {
00670          goto errout;
00671       }
00672       updated = 1;
00673       if (rule_fixup(rd) < 0) {
00674          LM_ERR("could not fixup rules after route appending");
00675          FIFO_ERR(E_RULEFIXUP);
00676          goto errout;
00677       }
00678    } else {
00679       for (i=0; i<rd->carrier_num; i++) {
00680          if(rd->carriers[i]){
00681             for (j=0; j<rd->carriers[i]->domain_num; j++) {
00682                if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
00683                   if (update_route_data_recursor(rd->carriers[i]->domains[j]->tree, rd->carriers[i]->domains[j]->name, opts) < 0) {
00684                      goto errout;
00685                   }
00686                }
00687             }
00688          }
00689       }
00690    }
00691 
00692    if(!updated){
00693       LM_ERR("no match for update found");
00694       FIFO_ERR(E_NOUPDATE);
00695       goto errout;
00696    }
00697 
00698    if (save_config(rd) < 0) {
00699       LM_ERR("could not save config");
00700       FIFO_ERR(E_SAVECONF);
00701       goto errout;
00702    }
00703 
00704    if (reload_route_data() == -1) {
00705       LM_ERR("could not reload route data");
00706       FIFO_ERR(E_LOADCONF);
00707       goto errout;
00708    }
00709 
00710    clear_route_data(rd);
00711    return 0;
00712 errout:
00713    clear_route_data(rd);
00714    return -1;
00715 }
00716 
00717 
00718 /**
00719  * Does the work for update_route_data by recursively
00720  * traversing the routing tree
00721  *
00722  * @param node points to the current routing tree node
00723  * @param act_domain routing domain which is currently
00724  * searched
00725  * @param opts points to the fifo command option structure
00726  *
00727  * @see update_route_data()
00728  *
00729  * @return 0 on success, -1 on failure
00730  */
00731 static int update_route_data_recursor(struct dtrie_node_t *node, str * act_domain, fifo_opt_t * opts) {
00732    int i, hash = 0;
00733    struct route_rule * rr, * prev = NULL, * tmp, * backup;
00734    struct route_flags *rf;
00735 
00736    rf = (struct route_flags *)(node->data);
00737    if (rf && rf->rule_list) {
00738       rr = rf->rule_list;
00739       while (rr) {
00740          if ((!opts->domain.len || (strncmp(opts->domain.s, OPT_STAR, strlen(OPT_STAR)) == 0)
00741                  || ((opts->domain.len == act_domain->len) && (strncmp(opts->domain.s, act_domain->s, opts->domain.len) == 0)))
00742                  && ((!opts->prefix.len && !rr->prefix.len) || (strncmp(opts->prefix.s, OPT_STAR, strlen(OPT_STAR)) == 0)
00743                      || (rr->prefix.len == opts->prefix.len && (strncmp(opts->prefix.s, rr->prefix.s, opts->prefix.len) == 0)))
00744                  && ((!opts->host.len && !rr->host.s) || (strncmp(opts->host.s, OPT_STAR, strlen(OPT_STAR)) == 0)
00745                      || ((strncmp(rr->host.s, opts->host.s, opts->host.len) == 0) && (rr->host.len == opts->host.len)))
00746                  && ((opts->prob < 0) || (opts->prob == rr->prob))) {
00747             switch (opts->cmd) {
00748                case OPT_REPLACE:
00749                   LM_INFO("replace host %.*s with %.*s\n", rr->host.len, rr->host.s, opts->new_host.len, opts->new_host.s);
00750                   if (rr->host.s) {
00751                      shm_free(rr->host.s);
00752                   }
00753                   if (opts->new_host.len) {
00754                      if ((rr->host.s = shm_malloc(opts->new_host.len + 1)) == NULL) {
00755                         SHM_MEM_ERROR;
00756                         FIFO_ERR(E_NOMEM);
00757                         return -1;
00758                      }
00759                      memmove(rr->host.s, opts->new_host.s, opts->new_host.len + 1);
00760                      rr->host.len = opts->new_host.len;
00761                      rr->host.s[rr->host.len] = '\0';
00762                   } else {
00763                      rr->host.len = 0;
00764                   }
00765                   rr->status = opts->status;
00766                   prev = rr;
00767                   rr = rr->next;
00768                   updated = 1;
00769                   break;
00770                case OPT_DEACTIVATE:
00771                   if (remove_backed_up(rr) < 0) {
00772                      LM_ERR("could not reset backup hosts\n");
00773                      FIFO_ERR(E_RESET);
00774                      return -1;
00775                   }
00776                   if (opts->new_host.len > 0) {
00777                      LM_INFO("deactivating host %.*s\n", rr->host.len, rr->host.s);
00778                      if (opts->new_host.len == 1 && opts->new_host.s[0] == 'a') {
00779                         if ((backup = find_auto_backup(rf, rr)) == NULL) {
00780                            LM_ERR("didn't find auto backup route\n");
00781                            FIFO_ERR(E_NOAUTOBACKUP);
00782                            return -1;
00783                         }
00784                      } else {
00785                         errno = 0;
00786                         hash = strtol(opts->new_host.s, NULL, 10);
00787                         if (errno == EINVAL || errno == ERANGE) {
00788                            if ((backup = find_rule_by_hash(rf, hash)) == NULL) {
00789                               LM_ERR("didn't find given backup route (hash %i)\n", hash);
00790                               FIFO_ERR(E_NOHASHBACKUP);
00791                               return -1;
00792                            }
00793                         } else {
00794                            if ((backup = find_rule_by_host(rf, &opts->new_host)) == NULL) {
00795                               LM_ERR("didn't find given backup route (host %.*s)\n", opts->new_host.len, opts->new_host.s);
00796                               FIFO_ERR(E_NOHOSTBACKUP);
00797                               return -1;
00798                            }
00799                         }
00800                      }
00801                      if (add_backup_rule(rr, backup) < 0) {
00802                         LM_ERR("couldn't set backup route\n");
00803                         FIFO_ERR(E_ADDBACKUP);
00804                         return -1;
00805                      }
00806                   } else {
00807                      if(rr->backed_up){
00808                         LM_ERR("can't deactivate route without backup route because it is backup route for others\n");
00809                         FIFO_ERR(E_DELBACKUP);
00810                         return -1;
00811                      }
00812                   }
00813                   rr->status = opts->status;
00814                   prev = rr;
00815                   rr = rr->next;
00816                   updated = 1;
00817                   break;
00818                case OPT_ACTIVATE:
00819                   LM_INFO("activating host %.*s\n", rr->host.len, rr->host.s);
00820                   if (remove_backed_up(rr) < 0) {
00821                      LM_ERR("could not reset backup hosts\n");
00822                      FIFO_ERR(E_RESET);
00823                      return -1;
00824                   }
00825                   rr->status = opts->status;
00826                   prev = rr;
00827                   rr = rr->next;
00828                   updated = 1;
00829                   break;
00830                case OPT_REMOVE:
00831                   LM_INFO("removing host %.*s\n", rr->host.len, rr->host.s);
00832                   if (rr->backed_up){
00833                      LM_ERR("cannot remove host %.*s which is backup for other hosts\n", rr->host.len, rr->host.s);
00834                      FIFO_ERR(E_DELBACKUP);
00835                      return -1;
00836                   }
00837                   if (remove_backed_up(rr) < 0) {
00838                      LM_ERR("could not reset backup hosts\n");
00839                      FIFO_ERR(E_RESET);
00840                      return -1;
00841                   }
00842                   if (prev) {
00843                      prev->next = rr->next;
00844                      tmp = rr;
00845                      rr = prev;
00846                      destroy_route_rule(tmp);
00847                      prev = rr;
00848                      rr = rr->next;
00849                   } else {
00850                      rf->rule_list = rr->next;
00851                      tmp = rr;
00852                      rr = rf->rule_list;
00853                      destroy_route_rule(tmp);
00854                   }
00855                   rf->rule_num--;
00856                   rf->max_targets--;
00857                   updated = 1;
00858                   break;
00859                default:
00860                   rr = rr->next;
00861                   break;
00862             }
00863          } else {
00864             prev = rr;
00865             rr = rr->next;
00866          }
00867       }
00868    }
00869    for (i=0; i<cr_match_mode; i++) {
00870       if (node->child[i]) {
00871          if (update_route_data_recursor(node->child[i], act_domain, opts) < 0) {
00872             return -1;
00873          }
00874       }
00875    }
00876    return 0;
00877 }
00878 
00879 
00880 /**
00881  * prints a short help text for fifo command usage
00882  */
00883 static struct mi_root* print_replace_help(void) {
00884        struct mi_root* rpl_tree;
00885        struct mi_node* node;
00886 
00887        rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00888        if(rpl_tree == NULL)
00889                return 0;
00890 
00891        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "carrierroute options usage:");
00892        if(node == NULL)
00893                goto error;
00894        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c searched/new remote host\n", OPT_HOST_CHR);
00895        if(node == NULL)
00896                goto error;
00897        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c replacement/backup host", OPT_NEW_TARGET_CHR);
00898        if(node == NULL)
00899                goto error;
00900        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: searched/new domain", OPT_DOMAIN_CHR);
00901        if(node == NULL)
00902                goto error;
00903        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: searched/new prefix", OPT_PREFIX_CHR);
00904        if(node == NULL)
00905                goto error;
00906        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: searched/new weight (0..1)", OPT_PROB_CHR);
00907        if(node == NULL)
00908                goto error;
00909        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: new rewrite prefix", OPT_R_PREFIX_CHR);
00910        if(node == NULL)
00911                goto error;
00912        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: new rewrite suffix", OPT_R_SUFFIX_CHR);
00913        if(node == NULL)
00914                goto error;
00915        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: new hash index", OPT_HASH_INDEX_CHR);
00916        if(node == NULL)
00917                goto error;
00918        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: prints this help", OPT_HELP_CHR);
00919        if(node == NULL)
00920                goto error;
00921 
00922        return rpl_tree;
00923 
00924 error:
00925        free_mi_tree(rpl_tree);
00926        return 0;
00927 }
00928 
00929 
00930 /**
00931  * interpret the fifo errors, creates a mi tree
00932  * @todo this is currently not evaluated for errors during update_route_data
00933  */
00934 struct mi_root* print_fifo_err(void) {
00935    struct mi_root* rpl_tree;
00936    
00937    switch (fifo_err) {
00938       case E_MISC: 
00939          rpl_tree = init_mi_tree( 400, "An error occured", 17);
00940          if(rpl_tree == NULL)
00941             return 0;
00942          break;
00943       case E_NOOPT:
00944          rpl_tree = init_mi_tree( 400, "No option given", 16);
00945          if(rpl_tree == NULL)
00946             return 0;
00947          break;
00948       case E_WRONGOPT:
00949          rpl_tree = init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00950          if(rpl_tree == NULL)
00951             return 0;
00952          break;
00953       case E_NOMEM:
00954          rpl_tree = init_mi_tree( 500, "Out of memory", 14);
00955          if(rpl_tree == NULL)
00956             return 0;
00957          break;
00958       case E_RESET:
00959          rpl_tree = init_mi_tree( 500, "Could not reset backup routes", 30);
00960          if(rpl_tree == NULL)
00961             return 0;
00962          break;
00963       case E_NOAUTOBACKUP:
00964          rpl_tree = init_mi_tree( 400, "No auto backup route found", 27);
00965          if(rpl_tree == NULL)
00966             return 0;
00967          break;
00968       case E_NOHASHBACKUP:
00969          rpl_tree = init_mi_tree( 400, "No backup route for given hash found", 37);
00970          if(rpl_tree == NULL)
00971             return 0;
00972          break;
00973       case E_NOHOSTBACKUP:
00974          rpl_tree = init_mi_tree( 400, "No backup route for given host found", 37);
00975          if(rpl_tree == NULL)
00976             return 0;
00977          break;
00978       case E_ADDBACKUP:
00979          rpl_tree = init_mi_tree( 500, "Could not set backup route", 27);
00980          if(rpl_tree == NULL)
00981             return 0;
00982          break;
00983       case E_DELBACKUP:
00984          rpl_tree = init_mi_tree( 400, "Could not delete or deactivate route, it is backup for other routes", 68);
00985          if(rpl_tree == NULL)
00986             return 0;
00987          break;
00988       case E_LOADCONF:
00989          rpl_tree = init_mi_tree( 500, "Could not load config from file", 32);
00990          if(rpl_tree == NULL)
00991             return 0;
00992          break;
00993       case E_SAVECONF:
00994          rpl_tree = init_mi_tree( 500, "Could not save config", 22);
00995          if(rpl_tree == NULL)
00996             return 0;
00997          break;
00998       case E_INVALIDOPT:
00999          rpl_tree = init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
01000          if(rpl_tree == NULL)
01001             return 0;
01002          break;
01003       case E_MISSOPT:
01004          rpl_tree = init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01005          if(rpl_tree == NULL)
01006             return 0;
01007          break;
01008       case E_RULEFIXUP:
01009          rpl_tree = init_mi_tree( 500, "Could not fixup rules", 22);
01010          if(rpl_tree == NULL)
01011             return 0;
01012          break;
01013       case E_NOUPDATE:
01014          rpl_tree = init_mi_tree( 500, "No match for update found", 26);
01015          if(rpl_tree == NULL)
01016             return 0;
01017          break;
01018       case E_HELP:
01019          return print_replace_help();
01020          break;
01021       default:
01022          rpl_tree = init_mi_tree( 500, "An error occured", 17);
01023          if(rpl_tree == NULL)
01024             return 0;
01025          break;
01026    }
01027    return rpl_tree;
01028 }

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