cr_config.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cr_config.c 5227 2008-11-19 13:16:15Z 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_config.c
00025  * \brief Functions for load and save routing data from a config file.
00026  * \ingroup carrierroute
00027  * - Module; \ref carrierroute
00028  */
00029 
00030 #include <confuse.h>
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <unistd.h>
00034 #include <stdlib.h>
00035 #include "../../mem/shm_mem.h"
00036 #include "../../mem/mem.h"
00037 #include "../../ut.h"
00038 #include "cr_config.h"
00039 #include "carrierroute.h"
00040 #include "cr_rule.h"
00041 #include "cr_domain.h"
00042 #include "cr_carrier.h"
00043 
00044 
00045 /**
00046  * reports errors during config file parsing using LOG macro
00047  *
00048  * @param cfg points to the current config data structure
00049  * @param fmt a format string
00050  * @param ap format arguments
00051  */
00052 static void conf_error(cfg_t *cfg, const char * fmt, va_list ap) {
00053    // FIXME this don't seems to work reliable, produces strange error messages
00054    LM_GEN1(L_ERR, (char *) fmt, ap);
00055 }
00056 
00057 
00058 /**
00059  * Parses the config file
00060  *
00061  * @return a pointer to the configuration data structure, NULL on failure
00062  */
00063 static cfg_t * parse_config(void) {
00064    cfg_t * cfg = NULL;
00065 
00066    cfg_opt_t target_opts[] = {
00067                                  CFG_STR("comment", 0, CFGF_NONE),
00068                                  CFG_INT("strip", 0, CFGF_NONE),
00069                                  CFG_STR("rewrite_prefix", 0, CFGF_NONE),
00070                                  CFG_FLOAT("prob", 0, CFGF_NONE),
00071                                  CFG_INT("hash_index", 0, CFGF_NONE),
00072                                  CFG_STR("rewrite_suffix", 0, CFGF_NONE),
00073                                  CFG_INT("status", 1, CFGF_NONE),
00074                                  CFG_INT_LIST("backed_up", NULL, CFGF_NONE),
00075                                  CFG_INT("backup", -1, CFGF_NONE),
00076                                  CFG_END()
00077                              };
00078 
00079    cfg_opt_t prefix_opts[] = {
00080                                  CFG_SEC("target", target_opts, CFGF_MULTI | CFGF_TITLE),
00081                                  CFG_INT("max_targets", -1, CFGF_NONE),
00082                                  CFG_END()
00083                              };
00084 
00085    cfg_opt_t domain_opts[] = {
00086                                  CFG_SEC("prefix", prefix_opts, CFGF_MULTI | CFGF_TITLE),
00087                                  CFG_END()
00088                              };
00089 
00090    cfg_opt_t opts[] = {
00091                           CFG_SEC("domain", domain_opts, CFGF_MULTI | CFGF_TITLE),
00092                           CFG_END()
00093                       };
00094 
00095    cfg = cfg_init(opts, CFGF_NONE);
00096 
00097    cfg_set_error_function(cfg, conf_error);
00098 
00099    switch (cfg_parse(cfg, config_file)) {
00100       case CFG_FILE_ERROR: LM_ERR("file not found: %s\n", config_file);
00101          return NULL;
00102       case CFG_PARSE_ERROR: LM_ERR("error while parsing %s in line %i, section %s\n",
00103                                    cfg->filename, cfg->line, cfg->name);
00104          return NULL;
00105       case CFG_SUCCESS: break;
00106    }
00107    return cfg;
00108 }
00109 
00110 
00111 static int backup_config(void) {
00112    FILE * from, * to;
00113    char * backup_file, ch;
00114    LM_INFO("start configuration backup\n");
00115    if((backup_file = pkg_malloc(strlen(config_file) + strlen (".bak") + 1)) == NULL){
00116       PKG_MEM_ERROR;
00117       return -1;
00118    }
00119    if(!strcpy(backup_file, config_file)){
00120       LM_ERR("can't copy filename\n");
00121       goto errout;
00122    }
00123    if(!strcat(backup_file, ".bak")){
00124       LM_ERR("can't attach suffix\n");
00125       goto errout;
00126    }
00127    /* open source file */
00128    if ((from = fopen(config_file, "rb"))==NULL) {
00129       LM_ERR("Cannot open source file.\n");
00130       goto errout;
00131    }
00132 
00133    /* open destination file */
00134    if ((to = fopen(backup_file, "wb"))==NULL) {
00135       LM_ERR("Cannot open destination file.\n");
00136       fclose(from);
00137       goto errout;
00138    }
00139 
00140    /* copy the file */
00141    while (!feof(from)) {
00142       ch = fgetc(from);
00143       if (ferror(from)) {
00144          LM_ERR("Error reading source file.\n");
00145          goto errout;
00146       }
00147       if (!feof(from)) fputc(ch, to);
00148       if (ferror(to)) {
00149          LM_ERR("Error writing destination file.\n");
00150          goto errout;
00151       }
00152    }
00153 
00154    if (fclose(from)==EOF) {
00155       LM_ERR("Error closing source file.\n");
00156       goto errout;
00157    }
00158 
00159    if (fclose(to)==EOF) {
00160       LM_ERR("Error closing destination file.\n");
00161       goto errout;
00162    }
00163    LM_NOTICE("backup written to %s\n", backup_file);
00164    pkg_free(backup_file);
00165    return 0;
00166 errout:
00167    pkg_free(backup_file);
00168    return -1;
00169 }
00170 
00171 
00172 /**
00173  * Loads the routing data from the config file given in global
00174  * variable config_data and stores it in routing tree rd.
00175  *
00176  * @param rd Pointer to the route data tree where the routing data
00177  * shall be loaded into
00178  *
00179  * @return 0 means ok, -1 means an error occured
00180  *
00181  */
00182 int load_config(struct route_data_t * rd) {
00183    cfg_t * cfg = NULL;
00184    int m, o, i, j, k,l, status, hash_index, max_targets, strip;
00185    cfg_t * d, * p, * t;
00186    struct carrier_data_t * tmp_carrier_data;
00187    int domain_id;
00188    str domain, prefix, rewrite_prefix, rewrite_suffix, rewrite_host, comment;
00189    double prob;
00190    int * backed_up = NULL;
00191    int backed_up_size, backup;
00192    backed_up_size = backup = 0;
00193 
00194    if ((cfg = parse_config()) == NULL) {
00195       return -1;
00196    }
00197 
00198    rd->carrier_num = 1;
00199    rd->first_empty_carrier = 0;
00200    rd->domain_num = cfg_size(cfg, "domain");
00201 
00202    if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *))) == NULL) {
00203       SHM_MEM_ERROR;
00204       return -1;
00205    }
00206    memset(rd->carriers, 0, sizeof(struct carrier_data_t *));
00207 
00208    /* Create carrier map */
00209    if ((rd->carrier_map = shm_malloc(sizeof(struct name_map_t))) == NULL) {
00210       SHM_MEM_ERROR;
00211       return -1;
00212    }
00213    memset(rd->carrier_map, 0, sizeof(struct name_map_t));
00214    rd->carrier_map[0].id = 1;
00215    rd->carrier_map[0].name.len = default_tree.len;
00216    rd->carrier_map[0].name.s = shm_malloc(rd->carrier_map[0].name.len);
00217    if (rd->carrier_map[0].name.s == NULL) {
00218       SHM_MEM_ERROR;
00219       return -1;
00220    }
00221    memcpy(rd->carrier_map[0].name.s, default_tree.s, rd->carrier_map[0].name.len);
00222 
00223    /* Create domain map */
00224    if ((rd->domain_map = shm_malloc(sizeof(struct name_map_t) * rd->domain_num)) == NULL) {
00225       SHM_MEM_ERROR;
00226       return -1;
00227    }
00228    memset(rd->domain_map, 0, sizeof(struct name_map_t) * rd->domain_num);
00229    for (i=0; i<rd->domain_num; i++) {
00230       d = cfg_getnsec(cfg, "domain", i);
00231       domain.s = (char *)cfg_title(d);
00232       if (domain.s==NULL) domain.s="";
00233       domain.len = strlen(domain.s);
00234       rd->domain_map[i].id = i+1;
00235       rd->domain_map[i].name.len = domain.len;
00236       rd->domain_map[i].name.s = shm_malloc(rd->domain_map[i].name.len);
00237       if (rd->domain_map[i].name.s == NULL) {
00238          SHM_MEM_ERROR;
00239          return -1;
00240       }
00241       memcpy(rd->domain_map[i].name.s, domain.s, rd->domain_map[i].name.len);
00242    }
00243    /* sort domain map by id for faster access */
00244    qsort(rd->domain_map, rd->domain_num, sizeof(rd->domain_map[0]), compare_name_map);
00245 
00246    /* Create and insert carrier data structure */
00247    tmp_carrier_data = create_carrier_data(1, &rd->carrier_map[0].name, rd->domain_num);
00248    if (tmp_carrier_data == NULL) {
00249       LM_ERR("can't create new carrier\n");
00250       return -1;
00251    }
00252    if (add_carrier_data(rd, tmp_carrier_data) < 0) {
00253       LM_ERR("couldn't add carrier data\n");
00254       destroy_carrier_data(tmp_carrier_data);
00255       return -1;
00256    }
00257 
00258    /* add all routes */
00259    for (i = 0; i < rd->domain_num; i++) {
00260       d = cfg_getnsec(cfg, "domain", i);
00261       domain.s = (char *)cfg_title(d);
00262       if (domain.s==NULL) domain.s="";
00263       domain.len = strlen(domain.s);
00264       m = cfg_size(d, "prefix");
00265 
00266       LM_INFO("loading domain %.*s\n", domain.len, domain.s);
00267       for (j = 0; j < m; j++) {
00268          p = cfg_getnsec(d, "prefix", j);
00269          prefix.s = (char *)cfg_title(p);
00270          if (prefix.s==NULL) prefix.s="";
00271          prefix.len = strlen(prefix.s);
00272          if (str_strcasecmp(&prefix, &CR_EMPTY_PREFIX) == 0) {
00273             prefix.s = "";
00274             prefix.len = 0;
00275          }
00276 
00277          LM_INFO("loading prefix %.*s\n", prefix.len, prefix.s);
00278          max_targets = cfg_getint(p, "max_targets");
00279          o = cfg_size(p, "target");
00280          for (k = 0; k < o; k++) {
00281             t = cfg_getnsec(p, "target", k);
00282             rewrite_host.s = (char *)cfg_title(t);
00283             if (rewrite_host.s==NULL) rewrite_host.s="";
00284             rewrite_host.len = strlen(rewrite_host.s);
00285             if (str_strcasecmp(&rewrite_host, &CR_EMPTY_PREFIX) == 0) {
00286                rewrite_host.s = "";
00287                rewrite_host.len = 0;
00288             }
00289 
00290             LM_INFO("loading target %.*s\n", rewrite_host.len, rewrite_host.s);
00291             prob = cfg_getfloat(t, "prob");
00292             strip = cfg_getint(t, "strip");
00293             rewrite_prefix.s = (char *)cfg_getstr(t, "rewrite_prefix");
00294             if (rewrite_prefix.s==NULL) rewrite_prefix.s="";
00295             rewrite_prefix.len = strlen(rewrite_prefix.s);
00296             rewrite_suffix.s = (char *)cfg_getstr(t, "rewrite_suffix");
00297             if (rewrite_suffix.s==NULL) rewrite_suffix.s="";
00298             rewrite_suffix.len = strlen(rewrite_suffix.s);
00299             hash_index = cfg_getint(t, "hash_index");
00300             comment.s = (char *)cfg_getstr(t, "comment");
00301             if (comment.s==NULL) comment.s="";
00302             comment.len = strlen(comment.s);
00303             status = cfg_getint(t, "status");
00304 
00305             if ((backed_up_size = cfg_size(t, "backed_up")) > 0) {
00306                if ((backed_up = pkg_malloc(sizeof(int) * (backed_up_size + 1))) == NULL) {
00307                   PKG_MEM_ERROR;
00308                   return -1;
00309                }
00310                for (l = 0; l < backed_up_size; l++) {
00311                   backed_up[l] = cfg_getnint(t, "backed_up", l);
00312                }
00313                backed_up[backed_up_size] = -1;
00314             }
00315             backup = cfg_getint(t, "backup");
00316 
00317             domain_id = map_name2id(rd->domain_map, rd->domain_num, &domain);
00318             if (domain_id < 0) {
00319                LM_ERR("cannot find id for domain '%.*s'", domain.len, domain.s);
00320                if (backed_up) {
00321                   pkg_free(backed_up);
00322                }
00323                return -1;
00324             }
00325 
00326             LM_INFO("adding route for prefix %.*s, to host %.*s, prob %f, backed up: %i, backup: %i\n",
00327                 prefix.len, prefix.s, rewrite_host.len, rewrite_host.s, prob, backed_up_size, backup);
00328             if (add_route(rd, 1, domain_id, &prefix, 0, 0, max_targets, prob, &rewrite_host,
00329                           strip, &rewrite_prefix, &rewrite_suffix, status,
00330                           hash_index, backup, backed_up, &comment) < 0) {
00331                LM_INFO("Error while adding route\n");
00332                if (backed_up) {
00333                   pkg_free(backed_up);
00334                }
00335                return -1;
00336             }
00337             if (backed_up) {
00338                pkg_free(backed_up);
00339             }
00340             backed_up = NULL;
00341          }
00342       }
00343 
00344    }
00345    cfg_free(cfg);
00346    return 0;
00347 }
00348 
00349 
00350 /**
00351  * Does the work for save_config, traverses the routing data tree
00352  * and writes each rule to file.
00353  *
00354  * @param node the current prefix tree node
00355  * @param outfile the filehandle to which the config data is written
00356  *
00357  * @return 0 on success, -1 on failure
00358  */
00359 static int save_route_data_recursor(struct dtrie_node_t * node, FILE * outfile) {
00360    int i;
00361    struct route_flags *rf;
00362    struct route_rule * rr;
00363    struct route_rule_p_list * rl;
00364    str *tmp_str;
00365    str null_str = str_init("NULL");
00366 
00367    /* no support for flag lists in route config */
00368    rf = (struct route_flags *)(node->data);
00369    if (rf && rf->rule_list) {
00370       rr = rf->rule_list;
00371       tmp_str = (rr->prefix.len ? &rr->prefix : &null_str);
00372       fprintf(outfile, "\tprefix %.*s {\n", tmp_str->len, tmp_str->s);
00373       fprintf(outfile, "\t\tmax_targets = %i\n\n", rf->max_targets);
00374       while (rr) {
00375          tmp_str = (rr->host.len ? &rr->host : &null_str);
00376          fprintf(outfile, "\t\ttarget %.*s {\n", tmp_str->len, tmp_str->s);
00377          fprintf(outfile, "\t\t\tprob = %f\n", rr->orig_prob);
00378          fprintf(outfile, "\t\t\thash_index = %i\n", rr->hash_index);
00379          fprintf(outfile, "\t\t\tstatus = %i\n", rr->status);
00380          if (rr->strip > 0) {
00381             fprintf(outfile, "\t\t\tstrip = \"%i\"\n", rr->strip);
00382          }
00383          if (rr->local_prefix.len) {
00384             fprintf(outfile, "\t\t\trewrite_prefix = \"%.*s\"\n", rr->local_prefix.len, rr->local_prefix.s);
00385          }
00386          if (rr->local_suffix.len) {
00387             fprintf(outfile, "\t\t\trewrite_suffix: \"%.*s\"\n", rr->local_suffix.len, rr->local_suffix.s);
00388          }
00389          if (rr->backup) {
00390             fprintf(outfile, "\t\t\tbackup = %i\n", rr->backup->hash_index);
00391          }
00392          if (rr->backed_up) {
00393             rl = rr->backed_up;
00394             fprintf(outfile, "\t\t\tbacked_up = {");
00395             i=0;
00396             while (rl) {
00397                if (i>0) {
00398                   fprintf(outfile, ", ");
00399                }
00400                fprintf(outfile, "%i", rl->hash_index);
00401                rl = rl->next;
00402                i++;
00403             }
00404             fprintf(outfile, "}\n");
00405          }
00406          if (rr->comment.len) {
00407             fprintf(outfile, "\t\t\tcomment = \"%.*s\"\n", rr->comment.len, rr->comment.s);
00408          }
00409          fprintf(outfile, "\t\t}\n");
00410          rr = rr->next;
00411       }
00412       fprintf(outfile, "\t}\n");
00413    }
00414    for (i = 0; i < cr_match_mode; i++) {
00415       if (node->child[i]) {
00416          if (save_route_data_recursor(node->child[i], outfile) < 0) {
00417             return -1;
00418          }
00419       }
00420    }
00421    return 0;
00422 }
00423 
00424 
00425 /**
00426  * Stores the routing data rd in config_file
00427  *
00428  * @param rd Pointer to the routing tree which shall be saved to file
00429  *
00430  * @return 0 means ok, -1 means an error occured
00431  */
00432 int save_config(struct route_data_t * rd) {
00433    FILE * outfile;
00434    int i,j;
00435 
00436    if(backup_config() < 0){
00437       return -1;
00438    }
00439 
00440    if ((outfile = fopen(config_file, "w")) == NULL) {
00441       LM_ERR("Could not open config file %s\n", config_file);
00442       return -1;
00443    }
00444 
00445    i = 0;
00446    if (rd->carrier_num>=1) {
00447       for (j=0; j< rd->carriers[i]->domain_num; j++) {
00448          fprintf(outfile, "domain %.*s {\n", rd->carriers[i]->domains[j]->name->len, rd->carriers[i]->domains[j]->name->s);
00449          if (save_route_data_recursor(rd->carriers[i]->domains[j]->tree, outfile) < 0) {
00450             goto errout;
00451          }
00452          fprintf(outfile, "}\n\n");
00453       }
00454    }
00455    fclose(outfile);
00456    return 0;
00457 errout:
00458    fclose(outfile);
00459    LM_ERR("Cannot save config file %s\n", config_file);
00460    return -1;
00461 }

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