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