cr_fifo.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 <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 
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 
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 
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                 goto error2;
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                                         if (dump_tree_recursor (&rpl_tree->node, rd->carriers[i]->domains[j]->tree, "") < 0) 
00159                                                 goto error;
00160                                 }
00161                         }
00162                 }
00163         }
00164         release_data (rd);
00165         return rpl_tree;
00166 
00167 error:
00168         free_mi_tree(rpl_tree);
00169 error2:
00170         release_data (rd);
00171         return 0;
00172 }
00173 
00174 
00185 struct mi_root* replace_host (struct mi_root* cmd_tree, void *param) {
00186         struct mi_node *node = NULL;
00187 
00188         int ret;
00189         fifo_opt_t options;
00190 
00191         if(mode != CARRIERROUTE_MODE_FILE) {
00192                 return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00193         }
00194         
00195         node = cmd_tree->node.kids;
00196         if (node==NULL || node->next!=NULL)
00197                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00198 
00199         
00200         /* look for command */
00201         if (node->value.s==NULL)
00202                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00203 
00204         if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_REPLACE])) <  0) {
00205                 return print_fifo_err();
00206         }
00207 
00208         options.status = 1;
00209         options.cmd = OPT_REPLACE;
00210 
00211         if(update_route_data(&options) < 0) {
00212                 return init_mi_tree(500, "failed to update route data, see log", 37);
00213         }
00214 
00215         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00216 }
00217 
00218 
00229 struct mi_root* deactivate_host (struct mi_root* cmd_tree, void *param) {
00230         struct mi_node *node = NULL;
00231 
00232         int ret;
00233         fifo_opt_t options;
00234 
00235         if(mode != CARRIERROUTE_MODE_FILE) {
00236                 return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00237         }
00238 
00239         node = cmd_tree->node.kids;
00240         if (node==NULL || node->next!=NULL)
00241                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00242 
00243         
00244         /* look for command */
00245         if (node->value.s==NULL)
00246                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00247 
00248         if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_DEACTIVATE])) <  0) {
00249                 return print_fifo_err();
00250         }
00251 
00252         options.status = 0;
00253         options.cmd = OPT_DEACTIVATE;
00254 
00255         if(update_route_data(&options) < 0) {
00256                 return init_mi_tree(500, "failed to update route data, see log", 37);
00257         }
00258 
00259         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00260 }
00261 
00262 
00273 struct mi_root* activate_host (struct mi_root* cmd_tree, void *param) {
00274         struct mi_node *node = NULL;
00275 
00276         int ret;
00277         fifo_opt_t options;
00278 
00279         if(mode != CARRIERROUTE_MODE_FILE) {
00280                 return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00281         }
00282 
00283         node = cmd_tree->node.kids;
00284         if (node==NULL || node->next!=NULL)
00285                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00286 
00287         
00288         /* look for command */
00289         if (node->value.s==NULL)
00290                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00291 
00292         if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_ACTIVATE])) <  0) {
00293                 return print_fifo_err();
00294         }
00295 
00296         options.status = 1;
00297         options.cmd = OPT_ACTIVATE;
00298 
00299         if(update_route_data(&options) < 0) {
00300                 return init_mi_tree(500, "failed to update route data, see log", 37);
00301         }
00302 
00303         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00304 }
00305 
00306 
00317 struct mi_root* add_host (struct mi_root* cmd_tree, void *param) {
00318         struct mi_node *node = NULL;
00319 
00320         int ret;
00321         fifo_opt_t options;
00322 
00323         if(mode != CARRIERROUTE_MODE_FILE) {
00324                 return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00325         }
00326 
00327         node = cmd_tree->node.kids;
00328         if (node==NULL || node->next!=NULL || node->value.s==NULL) {
00329                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00330         }
00331 
00332         if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_ADD])) <  0) {
00333                 return print_fifo_err();
00334         }
00335 
00336         options.status = 1;
00337         options.cmd = OPT_ADD;
00338 
00339         if(update_route_data(&options) < 0) {
00340                 return init_mi_tree(500, "failed to update route data, see log", 37);
00341         }
00342 
00343         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00344 }
00345 
00346 
00357 struct mi_root* delete_host (struct mi_root* cmd_tree, void * param) {
00358         struct mi_node *node = NULL;
00359 
00360         int ret;
00361         fifo_opt_t options;
00362 
00363         if(mode != CARRIERROUTE_MODE_FILE) {
00364                 return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70);
00365         }
00366 
00367         node = cmd_tree->node.kids;
00368         if (node==NULL || node->next!=NULL)
00369                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00370 
00371         
00372         /* look for command */
00373         if (node->value.s==NULL)
00374                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00375 
00376         if((ret = get_fifo_opts(&node->value, &options, opt_settings[OPT_REMOVE])) <  0) {
00377                 return print_fifo_err();
00378         }
00379 
00380         options.cmd = OPT_REMOVE;
00381 
00382         if(update_route_data(&options) < 0) {
00383                 return init_mi_tree(500, "failed to update route data, see log", 37);
00384         }
00385 
00386         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00387 }
00388 
00389 
00400 static int dump_tree_recursor (struct mi_node* msg, struct dtrie_node_t *node, char *prefix) {
00401         char s[256];
00402         char *p;
00403         int i;
00404         struct route_flags *rf;
00405         struct route_rule *rr;
00406         struct route_rule_p_list * rl;
00407         double prob;
00408         struct mi_node* tmp_node = NULL;
00409 
00410         strcpy (s, prefix);
00411         p = s + strlen (s);
00412         p[1] = '\0';
00413         for (i = 0; i < cr_match_mode; ++i) {
00414                 if (node->child[i] != NULL) {
00415                         *p = i + '0';
00416                         /* if there is a problem in processing the child nodes .. return an error */
00417                         if(dump_tree_recursor (msg->next, node->child[i], s) < 0)
00418                                 return -1;
00419                 }
00420         }
00421         *p = '\0';
00422         for (rf = (struct route_flags *)(node->data); rf != NULL; rf = rf->next) {
00423                 for (rr = rf->rule_list; rr != NULL; rr = rr->next) {
00424                         if(rf->dice_max){
00425                                 prob = (double)(rr->prob * DICE_MAX)/(double)rf->dice_max;
00426                         } else {
00427                                 prob = rr->prob;
00428                         }
00429                         tmp_node = addf_mi_node_child(msg->next, 0, 0, 0, "%10s: %0.3f %%, '%.*s': %s, '%i', '%.*s', '%.*s', '%.*s'\n",
00430                                                                                                  strlen(prefix) > 0 ? prefix : "NULL", prob * 100, rr->host.len, rr->host.s,
00431                                                                                                  (rr->status ? "ON" : "OFF"), rr->strip,
00432                                                                                                  rr->local_prefix.len, rr->local_prefix.s,
00433                                                                                                  rr->local_suffix.len, rr->local_suffix.s,
00434                                                                                                  rr->comment.len, rr->comment.s);
00435                         if(!tmp_node) return -1;
00436                         if(!rr->status && rr->backup && rr->backup->rr){
00437                                 tmp_node = 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);
00438                                 if(!tmp_node) return -1;
00439                         }
00440                         if(rr->backed_up){
00441                                 rl = rr->backed_up;
00442                                 i=0;
00443                                 while(rl){
00444                                         if(rl->rr){
00445                                                 tmp_node = addf_mi_node_child(msg->next, 0, 0, 0, "            Rule is backup for: %.*s", rl->rr->host.len, rl->rr->host.s);
00446                                                 if(!tmp_node) return -1;
00447                                         }
00448                                         rl = rl->next;
00449                                         i++;
00450                                 }
00451                         }
00452                 }
00453         }
00454         return 0;
00455 }
00456 
00457 
00469 static int get_fifo_opts(str * buf, fifo_opt_t * opts, unsigned int opt_set[]) {
00470         int opt_argc = 0;
00471         str opt_argv[20];
00472         int i, op = -1;
00473         unsigned int used_opts = 0;
00474         int toklen;
00475 
00476         memset(opt_argv, 0, sizeof(opt_argv));
00477         memset(opts, 0, sizeof(fifo_opt_t));
00478         opts->prob = -1;
00479 
00480         while((toklen = str_toklen(buf, " \t\r\n")) >=0 && opt_argc < 20) {
00481                 buf->s[toklen] = '\0'; /* insert zero termination, since strtod might be used later on it */
00482                 opt_argv[opt_argc].len = toklen;
00483                 opt_argv[opt_argc].s = buf->s;
00484                 buf->s += toklen + 1;
00485                 buf->len -= toklen + 1;
00486                 LM_DBG("found arg[%i]: %.*s\n", opt_argc, opt_argv[opt_argc].len, opt_argv[opt_argc].s);
00487                 opt_argc++;
00488         }
00489         for (i=0; i<opt_argc; i++) {
00490                 LM_DBG("token %.*s", opt_argv[i].len, opt_argv[i].s);
00491                 if (opt_argv[i].len >= 1) {
00492                         switch(*opt_argv[i].s) {
00493                                         case '-': switch(opt_argv[i].s[1]) {
00494                                                         case OPT_DOMAIN_CHR:
00495                                                         op = OPT_DOMAIN;
00496                                                         used_opts |= O_DOMAIN;
00497                                                         break;
00498                                                         case OPT_PREFIX_CHR:
00499                                                         op = OPT_PREFIX;
00500                                                         used_opts |= O_PREFIX;
00501                                                         break;
00502                                                         case OPT_HOST_CHR:
00503                                                         op = OPT_HOST;
00504                                                         used_opts |= O_HOST;
00505                                                         break;
00506                                                         case OPT_NEW_TARGET_CHR:
00507                                                         op = OPT_NEW_TARGET;
00508                                                         used_opts |= O_NEW_TARGET;
00509                                                         break;
00510                                                         case OPT_PROB_CHR:
00511                                                         op = OPT_PROB;
00512                                                         used_opts |= O_PROB;
00513                                                         break;
00514                                                         case OPT_R_PREFIX_CHR:
00515                                                         op = OPT_R_PREFIX;
00516                                                         used_opts |= O_R_PREFIX;
00517                                                         break;
00518                                                         case OPT_R_SUFFIX_CHR:
00519                                                         op = OPT_R_SUFFIX;
00520                                                         used_opts |= O_R_SUFFIX;
00521                                                         break;
00522                                                         case OPT_HASH_INDEX_CHR:
00523                                                         op = OPT_HASH_INDEX;
00524                                                         used_opts |= O_H_INDEX;
00525                                                         break;
00526                                                         case OPT_HELP_CHR:
00527                                                         FIFO_ERR(E_HELP);
00528                                                         return -1;
00529                                                         default: {
00530                                                                 FIFO_ERR(E_WRONGOPT);
00531                                                                 LM_DBG("Unknown option: %.*s\n", opt_argv[i].len, opt_argv[i].s);
00532                                                                 return -1;
00533                                                         }
00534                                         }
00535                                         break;
00536                                         default: switch(op) {
00537                                                         case OPT_DOMAIN:
00538                                                         opts->domain = opt_argv[i];
00539                                                         op = -1;
00540                                                         break;
00541                                                         case OPT_PREFIX:
00542                                                         if (str_strcasecmp(&opt_argv[i], &CR_EMPTY_PREFIX) == 0) {
00543                                                                 opts->prefix.s = NULL;
00544                                                                 opts->prefix.len = 0;
00545                                                         } else {
00546                                                                 opts->prefix = opt_argv[i];
00547                                                         }
00548                                                         op = -1;
00549                                                         break;
00550                                                         case OPT_HOST:
00551                                                         opts->host = opt_argv[i];
00552                                                         op = -1;
00553                                                         break;
00554                                                         case OPT_NEW_TARGET:
00555                                                         opts->new_host = opt_argv[i];
00556                                                         op = -1;
00557                                                         break;
00558                                                         case OPT_PROB:
00559                                                         opts->prob = strtod(opt_argv[i].s, NULL); /* we can use str.s since we zero terminated it earlier */
00560                                                         op = -1;
00561                                                         break;
00562                                                         case OPT_R_PREFIX:
00563                                                         opts->rewrite_prefix = opt_argv[i];
00564                                                         op = -1;
00565                                                         break;
00566                                                         case OPT_STRIP:
00567                                                         str2sint(&opt_argv[i], &opts->strip);
00568                                                         op = -1;
00569                                                         break;
00570                                                         case OPT_R_SUFFIX:
00571                                                         opts->rewrite_suffix = opt_argv[i];
00572                                                         op = -1;
00573                                                         break;
00574                                                         case OPT_HASH_INDEX:
00575                                                         str2sint(&opt_argv[i], &opts->hash_index);
00576                                                         op = -1;
00577                                                         break;
00578                                                         default: {
00579                                                                 LM_DBG("No option given\n");
00580                                                                 FIFO_ERR(E_NOOPT);
00581                                                                 return -1;
00582                                                         }
00583                                         }
00584                                         break;
00585                         }
00586                 }
00587         }
00588         if((used_opts & opt_set[OPT_INVALID]) != 0) {
00589                 LM_DBG("invalid option\n");
00590                 FIFO_ERR(E_INVALIDOPT);
00591                 return -1;
00592         }
00593         if((used_opts & opt_set[OPT_MANDATORY]) != opt_set[OPT_MANDATORY]) {
00594                 LM_DBG("option missing\n");
00595                 FIFO_ERR(E_MISSOPT);
00596                 return -1;
00597         }
00598         return 0;
00599 }
00600 
00601 
00612 static int update_route_data(fifo_opt_t * opts) {
00613         struct route_data_t * rd;
00614         int i,j;
00615         int domain_id;
00616         str tmp_domain;
00617         str tmp_prefix;
00618         str tmp_host;
00619         str tmp_rewrite_prefix;
00620         str tmp_rewrite_suffix;
00621         str tmp_comment = str_init("");
00622 
00623         if ((rd = shm_malloc(sizeof(struct route_data_t))) == NULL) {
00624                 SHM_MEM_ERROR;
00625                 return -1;
00626         }
00627         memset(rd, 0, sizeof(struct route_data_t));
00628         if (load_config(rd) < 0) {
00629                 LM_ERR("could not load config");
00630                 FIFO_ERR(E_LOADCONF);
00631                 return -1;
00632         }
00633 
00634         if (rule_fixup(rd) < 0) {
00635                 LM_ERR("could not fixup rules");
00636                 FIFO_ERR(E_RULEFIXUP);
00637                 return -1;
00638         }
00639         updated = 0;
00640 
00641         if (opts->cmd == OPT_ADD) {
00642                 tmp_domain=opts->domain;
00643                 tmp_prefix=opts->prefix;
00644                 tmp_host=opts->host;
00645                 tmp_rewrite_prefix=opts->rewrite_prefix;
00646                 tmp_rewrite_suffix=opts->rewrite_suffix;
00647                 if (tmp_domain.s==NULL) {
00648                         tmp_domain.s="";
00649                         tmp_domain.len=0;
00650                 }
00651                 if (tmp_prefix.s==NULL) {
00652                         tmp_prefix.s="";
00653                         tmp_prefix.len=0;
00654                 }
00655                 if (tmp_host.s==NULL) {
00656                         tmp_host.s="";
00657                         tmp_host.len=0;
00658                 }
00659                 if (tmp_rewrite_prefix.s==NULL) {
00660                         tmp_rewrite_prefix.s="";
00661                         tmp_rewrite_prefix.len=0;
00662                 }
00663                 if (tmp_rewrite_suffix.s==NULL) {
00664                         tmp_rewrite_suffix.s="";
00665                         tmp_rewrite_suffix.len=0;
00666                 }
00667 
00668                 domain_id = map_name2id(rd->domain_map, rd->domain_num, &tmp_domain);
00669                 if (domain_id < 0) {
00670                         LM_ERR("cannot find id for domain '%.*s'", tmp_domain.len, tmp_domain.s);
00671                         goto errout;
00672                 }
00673 
00674                 if (add_route(rd, 1, domain_id, &tmp_prefix, 0, 0, 0, opts->prob,
00675                               &tmp_host, opts->strip, &tmp_rewrite_prefix, &tmp_rewrite_suffix,
00676                               opts->status, opts->hash_index, -1, NULL, &tmp_comment) < 0) {
00677                         goto errout;
00678                 }
00679                 updated = 1;
00680                 if (rule_fixup(rd) < 0) {
00681                         LM_ERR("could not fixup rules after route appending");
00682                         FIFO_ERR(E_RULEFIXUP);
00683                         goto errout;
00684                 }
00685         } else {
00686                 for (i=0; i<rd->carrier_num; i++) {
00687                         if(rd->carriers[i]){
00688                                 for (j=0; j<rd->carriers[i]->domain_num; j++) {
00689                                         if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) {
00690                                                 if (update_route_data_recursor(rd->carriers[i]->domains[j]->tree, rd->carriers[i]->domains[j]->name, opts) < 0) {
00691                                                         goto errout;
00692                                                 }
00693                                         }
00694                                 }
00695                         }
00696                 }
00697         }
00698 
00699         if(!updated){
00700                 LM_ERR("no match for update found");
00701                 FIFO_ERR(E_NOUPDATE);
00702                 goto errout;
00703         }
00704 
00705         if (save_config(rd) < 0) {
00706                 LM_ERR("could not save config");
00707                 FIFO_ERR(E_SAVECONF);
00708                 goto errout;
00709         }
00710 
00711         if (reload_route_data() == -1) {
00712                 LM_ERR("could not reload route data");
00713                 FIFO_ERR(E_LOADCONF);
00714                 goto errout;
00715         }
00716 
00717         clear_route_data(rd);
00718         return 0;
00719 errout:
00720         clear_route_data(rd);
00721         return -1;
00722 }
00723 
00724 
00738 static int update_route_data_recursor(struct dtrie_node_t *node, str * act_domain, fifo_opt_t * opts) {
00739         int i, hash = 0;
00740         struct route_rule * rr, * prev = NULL, * tmp, * backup;
00741         struct route_flags *rf;
00742 
00743         rf = (struct route_flags *)(node->data);
00744         if (rf && rf->rule_list) {
00745                 rr = rf->rule_list;
00746                 while (rr) {
00747                         if ((!opts->domain.len || (strncmp(opts->domain.s, OPT_STAR, strlen(OPT_STAR)) == 0)
00748                                 || ((opts->domain.len == act_domain->len) && (strncmp(opts->domain.s, act_domain->s, opts->domain.len) == 0)))
00749                                 && ((!opts->prefix.len && !rr->prefix.len) || (strncmp(opts->prefix.s, OPT_STAR, strlen(OPT_STAR)) == 0)
00750                                     || (rr->prefix.len == opts->prefix.len && (strncmp(opts->prefix.s, rr->prefix.s, opts->prefix.len) == 0)))
00751                                 && ((!opts->host.len && !rr->host.s) || (strncmp(opts->host.s, OPT_STAR, strlen(OPT_STAR)) == 0)
00752                                     || ((strncmp(rr->host.s, opts->host.s, opts->host.len) == 0) && (rr->host.len == opts->host.len)))
00753                                 && ((opts->prob < 0) || (opts->prob == rr->prob))) {
00754                                 switch (opts->cmd) {
00755                                         case OPT_REPLACE:
00756                                                 LM_INFO("replace host %.*s with %.*s\n", rr->host.len, rr->host.s, opts->new_host.len, opts->new_host.s);
00757                                                 if (rr->host.s) {
00758                                                         shm_free(rr->host.s);
00759                                                 }
00760                                                 if (opts->new_host.len) {
00761                                                         if ((rr->host.s = shm_malloc(opts->new_host.len + 1)) == NULL) {
00762                                                                 SHM_MEM_ERROR;
00763                                                                 FIFO_ERR(E_NOMEM);
00764                                                                 return -1;
00765                                                         }
00766                                                         memmove(rr->host.s, opts->new_host.s, opts->new_host.len + 1);
00767                                                         rr->host.len = opts->new_host.len;
00768                                                         rr->host.s[rr->host.len] = '\0';
00769                                                 } else {
00770                                                         rr->host.len = 0;
00771                                                 }
00772                                                 rr->status = opts->status;
00773                                                 prev = rr;
00774                                                 rr = rr->next;
00775                                                 updated = 1;
00776                                                 break;
00777                                         case OPT_DEACTIVATE:
00778                                                 if (remove_backed_up(rr) < 0) {
00779                                                         LM_ERR("could not reset backup hosts\n");
00780                                                         FIFO_ERR(E_RESET);
00781                                                         return -1;
00782                                                 }
00783                                                 if (opts->new_host.len > 0) {
00784                                                         LM_INFO("deactivating host %.*s\n", rr->host.len, rr->host.s);
00785                                                         if ( opts->new_host.s && (strcmp(opts->new_host.s, rr->host.s) == 0)){
00786                                                                 LM_ERR("Backup host the same as initial host %.*s",rr->host.len, rr->host.s);
00787                                                                 FIFO_ERR(E_WRONGOPT);
00788                                                                 return -1;
00789                                                         }
00790                                                         if (opts->new_host.len == 1 && opts->new_host.s[0] == 'a') {
00791                                                                 if ((backup = find_auto_backup(rf, rr)) == NULL) {
00792                                                                         LM_ERR("didn't find auto backup route\n");
00793                                                                         FIFO_ERR(E_NOAUTOBACKUP);
00794                                                                         return -1;
00795                                                                 }
00796                                                         } else {
00797                                                                 errno = 0;
00798                                                                 hash = strtol(opts->new_host.s, NULL, 10);
00799                                                                 if (errno == EINVAL || errno == ERANGE) {
00800                                                                         if ((backup = find_rule_by_hash(rf, hash)) == NULL) {
00801                                                                                 LM_ERR("didn't find given backup route (hash %i)\n", hash);
00802                                                                                 FIFO_ERR(E_NOHASHBACKUP);
00803                                                                                 return -1;
00804                                                                         }
00805                                                                 } else {
00806                                                                         if ((backup = find_rule_by_host(rf, &opts->new_host)) == NULL) {
00807                                                                                 LM_ERR("didn't find given backup route (host %.*s)\n", opts->new_host.len, opts->new_host.s);
00808                                                                                 FIFO_ERR(E_NOHOSTBACKUP);
00809                                                                                 return -1;
00810                                                                         }
00811                                                                 }
00812                                                         }
00813                                                         if (add_backup_rule(rr, backup) < 0) {
00814                                                                 LM_ERR("couldn't set backup route\n");
00815                                                                 FIFO_ERR(E_ADDBACKUP);
00816                                                                 return -1;
00817                                                         }
00818                                                 } else {
00819                                                         if(rr->backed_up){
00820                                                                 LM_ERR("can't deactivate route without backup route because it is backup route for others\n");
00821                                                                 FIFO_ERR(E_DELBACKUP);
00822                                                                 return -1;
00823                                                         }
00824                                                 }
00825                                                 rr->status = opts->status;
00826                                                 prev = rr;
00827                                                 rr = rr->next;
00828                                                 updated = 1;
00829                                                 break;
00830                                         case OPT_ACTIVATE:
00831                                                 LM_INFO("activating host %.*s\n", rr->host.len, rr->host.s);
00832                                                 if (remove_backed_up(rr) < 0) {
00833                                                         LM_ERR("could not reset backup hosts\n");
00834                                                         FIFO_ERR(E_RESET);
00835                                                         return -1;
00836                                                 }
00837                                                 rr->status = opts->status;
00838                                                 prev = rr;
00839                                                 rr = rr->next;
00840                                                 updated = 1;
00841                                                 break;
00842                                         case OPT_REMOVE:
00843                                                 LM_INFO("removing host %.*s\n", rr->host.len, rr->host.s);
00844                                                 if (rr->backed_up){
00845                                                         LM_ERR("cannot remove host %.*s which is backup for other hosts\n", rr->host.len, rr->host.s);
00846                                                         FIFO_ERR(E_DELBACKUP);
00847                                                         return -1;
00848                                                 }
00849                                                 if (remove_backed_up(rr) < 0) {
00850                                                         LM_ERR("could not reset backup hosts\n");
00851                                                         FIFO_ERR(E_RESET);
00852                                                         return -1;
00853                                                 }
00854                                                 if (prev) {
00855                                                         prev->next = rr->next;
00856                                                         tmp = rr;
00857                                                         rr = prev;
00858                                                         destroy_route_rule(tmp);
00859                                                         prev = rr;
00860                                                         rr = rr->next;
00861                                                 } else {
00862                                                         rf->rule_list = rr->next;
00863                                                         tmp = rr;
00864                                                         rr = rf->rule_list;
00865                                                         destroy_route_rule(tmp);
00866                                                 }
00867                                                 rf->rule_num--;
00868                                                 rf->max_targets--;
00869                                                 updated = 1;
00870                                                 break;
00871                                         default:
00872                                                 rr = rr->next;
00873                                                 break;
00874                                 }
00875                         } else {
00876                                 prev = rr;
00877                                 rr = rr->next;
00878                         }
00879                 }
00880         }
00881         for (i=0; i<cr_match_mode; i++) {
00882                 if (node->child[i]) {
00883                         if (update_route_data_recursor(node->child[i], act_domain, opts) < 0) {
00884                                 return -1;
00885                         }
00886                 }
00887         }
00888         return 0;
00889 }
00890 
00891 
00895 static struct mi_root* print_replace_help(void) {
00896        struct mi_root* rpl_tree;
00897        struct mi_node* node;
00898 
00899        rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN );
00900        if(rpl_tree == NULL)
00901                return 0;
00902 
00903        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "carrierroute options usage:");
00904        if(node == NULL)
00905                goto error;
00906        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c searched/new remote host\n", OPT_HOST_CHR);
00907        if(node == NULL)
00908                goto error;
00909        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c replacement/backup host", OPT_NEW_TARGET_CHR);
00910        if(node == NULL)
00911                goto error;
00912        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: searched/new domain", OPT_DOMAIN_CHR);
00913        if(node == NULL)
00914                goto error;
00915        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: searched/new prefix", OPT_PREFIX_CHR);
00916        if(node == NULL)
00917                goto error;
00918        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: searched/new weight (0..1)", OPT_PROB_CHR);
00919        if(node == NULL)
00920                goto error;
00921        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: new rewrite prefix", OPT_R_PREFIX_CHR);
00922        if(node == NULL)
00923                goto error;
00924        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: new rewrite suffix", OPT_R_SUFFIX_CHR);
00925        if(node == NULL)
00926                goto error;
00927        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: new hash index", OPT_HASH_INDEX_CHR);
00928        if(node == NULL)
00929                goto error;
00930        node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "\t-%c: prints this help", OPT_HELP_CHR);
00931        if(node == NULL)
00932                goto error;
00933 
00934        return rpl_tree;
00935 
00936 error:
00937        free_mi_tree(rpl_tree);
00938        return 0;
00939 }
00940 
00941 
00946 struct mi_root* print_fifo_err(void) {
00947         struct mi_root* rpl_tree;
00948         
00949         switch (fifo_err) {
00950                 case E_MISC: 
00951                         rpl_tree = init_mi_tree( 400, "An error occured", 17);
00952                         if(rpl_tree == NULL)
00953                                 return 0;
00954                         break;
00955                 case E_NOOPT:
00956                         rpl_tree = init_mi_tree( 400, "No option given", 16);
00957                         if(rpl_tree == NULL)
00958                                 return 0;
00959                         break;
00960                 case E_WRONGOPT:
00961                         rpl_tree = init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00962                         if(rpl_tree == NULL)
00963                                 return 0;
00964                         break;
00965                 case E_NOMEM:
00966                         rpl_tree = init_mi_tree( 500, "Out of memory", 14);
00967                         if(rpl_tree == NULL)
00968                                 return 0;
00969                         break;
00970                 case E_RESET:
00971                         rpl_tree = init_mi_tree( 500, "Could not reset backup routes", 30);
00972                         if(rpl_tree == NULL)
00973                                 return 0;
00974                         break;
00975                 case E_NOAUTOBACKUP:
00976                         rpl_tree = init_mi_tree( 400, "No auto backup route found", 27);
00977                         if(rpl_tree == NULL)
00978                                 return 0;
00979                         break;
00980                 case E_NOHASHBACKUP:
00981                         rpl_tree = init_mi_tree( 400, "No backup route for given hash found", 37);
00982                         if(rpl_tree == NULL)
00983                                 return 0;
00984                         break;
00985                 case E_NOHOSTBACKUP:
00986                         rpl_tree = init_mi_tree( 400, "No backup route for given host found", 37);
00987                         if(rpl_tree == NULL)
00988                                 return 0;
00989                         break;
00990                 case E_ADDBACKUP:
00991                         rpl_tree = init_mi_tree( 500, "Could not set backup route", 27);
00992                         if(rpl_tree == NULL)
00993                                 return 0;
00994                         break;
00995                 case E_DELBACKUP:
00996                         rpl_tree = init_mi_tree( 400, "Could not delete or deactivate route, it is backup for other routes", 68);
00997                         if(rpl_tree == NULL)
00998                                 return 0;
00999                         break;
01000                 case E_LOADCONF:
01001                         rpl_tree = init_mi_tree( 500, "Could not load config from file", 32);
01002                         if(rpl_tree == NULL)
01003                                 return 0;
01004                         break;
01005                 case E_SAVECONF:
01006                         rpl_tree = init_mi_tree( 500, "Could not save config", 22);
01007                         if(rpl_tree == NULL)
01008                                 return 0;
01009                         break;
01010                 case E_INVALIDOPT:
01011                         rpl_tree = init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
01012                         if(rpl_tree == NULL)
01013                                 return 0;
01014                         break;
01015                 case E_MISSOPT:
01016                         rpl_tree = init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
01017                         if(rpl_tree == NULL)
01018                                 return 0;
01019                         break;
01020                 case E_RULEFIXUP:
01021                         rpl_tree = init_mi_tree( 500, "Could not fixup rules", 22);
01022                         if(rpl_tree == NULL)
01023                                 return 0;
01024                         break;
01025                 case E_NOUPDATE:
01026                         rpl_tree = init_mi_tree( 500, "No match for update found", 26);
01027                         if(rpl_tree == NULL)
01028                                 return 0;
01029                         break;
01030                 case E_HELP:
01031                         return print_replace_help();
01032                         break;
01033                 default:
01034                         rpl_tree = init_mi_tree( 500, "An error occured", 17);
01035                         if(rpl_tree == NULL)
01036                                 return 0;
01037                         break;
01038         }
01039         return rpl_tree;
01040 }