/** * loads the config data into shared memory (but doesn't really * share it), updates the routing data and writes it to the config * file. Afterwards, the global routing data is reloaded. * * @param opts pointer to the option structure which contains * data to be modified or to be added * * @return 0 on success, -1 on failure */ static int update_route_data(fifo_opt_t * opts) { struct route_data_t * rd; int i,j; int domain_id; str tmp_domain; str tmp_prefix; str tmp_host; str tmp_rewrite_prefix; str tmp_rewrite_suffix; str tmp_comment = str_init(""); if ((rd = shm_malloc(sizeof(struct route_data_t))) == NULL) { SHM_MEM_ERROR; return -1; } memset(rd, 0, sizeof(struct route_data_t)); if (load_config(rd) < 0) { LM_ERR("could not load config"); FIFO_ERR(E_LOADCONF); return -1; } if (rule_fixup(rd) < 0) { LM_ERR("could not fixup rules"); FIFO_ERR(E_RULEFIXUP); return -1; } updated = 0; if (opts->cmd == OPT_ADD) { tmp_domain=opts->domain; tmp_prefix=opts->prefix; tmp_host=opts->host; tmp_rewrite_prefix=opts->rewrite_prefix; tmp_rewrite_suffix=opts->rewrite_suffix; if (tmp_domain.s==NULL) { tmp_domain.s=""; tmp_domain.len=0; } if (tmp_prefix.s==NULL) { tmp_prefix.s=""; tmp_prefix.len=0; } if (tmp_host.s==NULL) { tmp_host.s=""; tmp_host.len=0; } if (tmp_rewrite_prefix.s==NULL) { tmp_rewrite_prefix.s=""; tmp_rewrite_prefix.len=0; } if (tmp_rewrite_suffix.s==NULL) { tmp_rewrite_suffix.s=""; tmp_rewrite_suffix.len=0; } domain_id = map_name2id(rd->domain_map, rd->domain_num, &tmp_domain); if (domain_id < 0) { LM_ERR("cannot find id for domain '%.*s'", tmp_domain.len, tmp_domain.s); goto errout; } if (add_route(rd, 1, domain_id, &tmp_prefix, 0, 0, 0, opts->prob, &tmp_host, opts->strip, &tmp_rewrite_prefix, &tmp_rewrite_suffix, opts->status, opts->hash_index, -1, NULL, &tmp_comment) < 0) { goto errout; } updated = 1; if (rule_fixup(rd) < 0) { LM_ERR("could not fixup rules after route appending"); FIFO_ERR(E_RULEFIXUP); goto errout; } } else { for (i=0; i<rd->carrier_num; i++) { if(rd->carriers[i]){ for (j=0; j<rd->carriers[i]->domain_num; j++) { if (rd->carriers[i]->domains[j] && rd->carriers[i]->domains[j]->tree) { if (update_route_data_recursor(rd->carriers[i]->domains[j]->tree, rd->carriers[i]->domains[j]->name, opts) < 0) { goto errout; } } } } } } if(!updated){ LM_ERR("no match for update found"); FIFO_ERR(E_NOUPDATE); goto errout; } if (save_config(rd) < 0) { LM_ERR("could not save config"); FIFO_ERR(E_SAVECONF); goto errout; } if (reload_route_data() == -1) { LM_ERR("could not reload route data"); FIFO_ERR(E_LOADCONF); goto errout; } clear_route_data(rd); return 0; errout: clear_route_data(rd); return -1; }
/** * Does the work for update_route_data by recursively * traversing the routing tree * * @param node points to the current routing tree node * @param act_domain routing domain which is currently * searched * @param opts points to the fifo command option structure * * @see update_route_data() * * @return 0 on success, -1 on failure */ static int update_route_data_recursor(struct dtrie_node_t *node, str * act_domain, fifo_opt_t * opts) { int i, hash = 0; struct route_rule * rr, * prev = NULL, * tmp, * backup; struct route_flags *rf; rf = (struct route_flags *)(node->data); if (rf && rf->rule_list) { rr = rf->rule_list; while (rr) { if ((!opts->domain.len || (strncmp(opts->domain.s, OPT_STAR, strlen(OPT_STAR)) == 0) || ((opts->domain.len == act_domain->len) && (strncmp(opts->domain.s, act_domain->s, opts->domain.len) == 0))) && ((!opts->prefix.len && !rr->prefix.len) || (strncmp(opts->prefix.s, OPT_STAR, strlen(OPT_STAR)) == 0) || (rr->prefix.len == opts->prefix.len && (strncmp(opts->prefix.s, rr->prefix.s, opts->prefix.len) == 0))) && ((!opts->host.len && !rr->host.s) || (strncmp(opts->host.s, OPT_STAR, strlen(OPT_STAR)) == 0) || ((strncmp(rr->host.s, opts->host.s, opts->host.len) == 0) && (rr->host.len == opts->host.len))) && ((opts->prob < 0) || (opts->prob == rr->prob))) { switch (opts->cmd) { case OPT_REPLACE: LM_INFO("replace host %.*s with %.*s\n", rr->host.len, rr->host.s, opts->new_host.len, opts->new_host.s); if (rr->host.s) { shm_free(rr->host.s); } if (opts->new_host.len) { if ((rr->host.s = shm_malloc(opts->new_host.len + 1)) == NULL) { SHM_MEM_ERROR; FIFO_ERR(E_NOMEM); return -1; } memmove(rr->host.s, opts->new_host.s, opts->new_host.len + 1); rr->host.len = opts->new_host.len; rr->host.s[rr->host.len] = '\0'; } else { rr->host.len = 0; } rr->status = opts->status; prev = rr; rr = rr->next; updated = 1; break; case OPT_DEACTIVATE: if (remove_backed_up(rr) < 0) { LM_ERR("could not reset backup hosts\n"); FIFO_ERR(E_RESET); return -1; } if (opts->new_host.len > 0) { LM_INFO("deactivating host %.*s\n", rr->host.len, rr->host.s); if ( opts->new_host.s && (strcmp(opts->new_host.s, rr->host.s) == 0)){ LM_ERR("Backup host the same as initial host %.*s",rr->host.len, rr->host.s); FIFO_ERR(E_WRONGOPT); return -1; } if (opts->new_host.len == 1 && opts->new_host.s[0] == 'a') { if ((backup = find_auto_backup(rf, rr)) == NULL) { LM_ERR("didn't find auto backup route\n"); FIFO_ERR(E_NOAUTOBACKUP); return -1; } } else { errno = 0; hash = strtol(opts->new_host.s, NULL, 10); if (errno == EINVAL || errno == ERANGE) { if ((backup = find_rule_by_hash(rf, hash)) == NULL) { LM_ERR("didn't find given backup route (hash %i)\n", hash); FIFO_ERR(E_NOHASHBACKUP); return -1; } } else { if ((backup = find_rule_by_host(rf, &opts->new_host)) == NULL) { LM_ERR("didn't find given backup route (host %.*s)\n", opts->new_host.len, opts->new_host.s); FIFO_ERR(E_NOHOSTBACKUP); return -1; } } } if (add_backup_rule(rr, backup) < 0) { LM_ERR("couldn't set backup route\n"); FIFO_ERR(E_ADDBACKUP); return -1; } } else { if(rr->backed_up){ LM_ERR("can't deactivate route without backup route because it is backup route for others\n"); FIFO_ERR(E_DELBACKUP); return -1; } } rr->status = opts->status; prev = rr; rr = rr->next; updated = 1; break; case OPT_ACTIVATE: LM_INFO("activating host %.*s\n", rr->host.len, rr->host.s); if (remove_backed_up(rr) < 0) { LM_ERR("could not reset backup hosts\n"); FIFO_ERR(E_RESET); return -1; } rr->status = opts->status; prev = rr; rr = rr->next; updated = 1; break; case OPT_REMOVE: LM_INFO("removing host %.*s\n", rr->host.len, rr->host.s); if (rr->backed_up){ LM_ERR("cannot remove host %.*s which is backup for other hosts\n", rr->host.len, rr->host.s); FIFO_ERR(E_DELBACKUP); return -1; } if (remove_backed_up(rr) < 0) { LM_ERR("could not reset backup hosts\n"); FIFO_ERR(E_RESET); return -1; } if (prev) { prev->next = rr->next; tmp = rr; rr = prev; destroy_route_rule(tmp); prev = rr; rr = rr->next; } else { rf->rule_list = rr->next; tmp = rr; rr = rf->rule_list; destroy_route_rule(tmp); } rf->rule_num--; rf->max_targets--; updated = 1; break; default: rr = rr->next; break; } } else { prev = rr; rr = rr->next; } } } for (i=0; i<cr_match_mode; i++) { if (node->child[i]) { if (update_route_data_recursor(node->child[i], act_domain, opts) < 0) { return -1; } } } return 0; }
/** * loads the config data into shared memory (but doesn't really * share it), updates the routing data and writes it to the config * file. Afterwards, the global routing data is reloaded. * * @param opts pointer to the option structure which contains * data to be modified or to be added * * @return 0 on success, -1 on failure */ static int update_route_data(fifo_opt_t * opts) { struct rewrite_data * rd; int i,j; str tmp_domain; str tmp_prefix; str tmp_host; str tmp_rewrite_prefix; str tmp_rewrite_suffix; str tmp_comment = str_init(""); if ((rd = shm_malloc(sizeof(struct rewrite_data))) == NULL) { LM_ERR("out of shared memory\n"); return -1; } memset(rd, 0, sizeof(struct rewrite_data)); if (load_config(rd) < 0) { LM_ERR("could not load config\n"); FIFO_ERR(E_LOADCONF); return -1; } if (rule_fixup(rd) < 0) { LM_ERR("could not fixup rules\n"); FIFO_ERR(E_RULEFIXUP); return -1; } updated = 0; if (opts->cmd == OPT_ADD) { tmp_domain=opts->domain; tmp_prefix=opts->prefix; tmp_host=opts->host; tmp_rewrite_prefix=opts->rewrite_prefix; tmp_rewrite_suffix=opts->rewrite_suffix; if (tmp_domain.s==NULL) { tmp_domain.s=""; tmp_domain.len=0; } if (tmp_prefix.s==NULL) { tmp_prefix.s=""; tmp_prefix.len=0; } if (tmp_host.s==NULL) { tmp_host.s=""; tmp_host.len=0; } if (tmp_rewrite_prefix.s==NULL) { tmp_rewrite_prefix.s=""; tmp_rewrite_prefix.len=0; } if (tmp_rewrite_suffix.s==NULL) { tmp_rewrite_suffix.s=""; tmp_rewrite_suffix.len=0; } if (add_route(rd, 1, &tmp_domain, &tmp_prefix, 0, 0, 0, opts->prob, &tmp_host, opts->strip, &tmp_rewrite_prefix, &tmp_rewrite_suffix, opts->status, opts->hash_index, -1, NULL, &tmp_comment) < 0) { goto errout; } updated = 1; if (rule_fixup(rd) < 0) { LM_ERR("could not fixup rules after route appending\n"); FIFO_ERR(E_RULEFIXUP); return -1; } } else { for (i=0; i<rd->tree_num; i++) { if(rd->carriers[i]){ for (j=0; j<rd->carriers[i]->tree_num; j++) { if (rd->carriers[i]->trees[j] && rd->carriers[i]->trees[j]->tree) { if (update_route_data_recursor(rd->carriers[i]->trees[j]->tree, &rd->carriers[i]->trees[j]->name, opts) < 0) { goto errout; } } } } } } if(!updated){ LM_ERR("no match for update found\n"); FIFO_ERR(E_NOUPDATE); goto errout; } if (save_config(rd) < 0) { LM_ERR("could not save config\n"); FIFO_ERR(E_SAVECONF); goto errout; } if (prepare_route_tree() == -1) { LM_ERR("could not prepare the route tree\n"); FIFO_ERR(E_LOADCONF); goto errout; } destroy_rewrite_data(rd); return 0; errout: destroy_rewrite_data(rd); return -1; }