/** * Destroys route_tree_item in shared memory by freing all its memory. * * @param route_tree_item route tree node to be destroyed */ static void destroy_route_tree_item(struct route_tree_item *route_tree_item) { int i; struct route_rule *rs; struct route_rule *rs_tmp; if (!route_tree_item) { LM_ERR("NULL pointer in parameter\n"); } for (i = 0; i < 10; ++i) { if (route_tree_item->nodes[i] != NULL) { destroy_route_tree_item(route_tree_item->nodes[i]); } } if (route_tree_item->rules) { shm_free(route_tree_item->rules); } rs = route_tree_item->rule_list; while (rs != NULL) { rs_tmp = rs->next; destroy_route_rule(rs); rs = rs_tmp; } shm_free(route_tree_item); return; }
/** * Destroys route_flags in shared memory by freing all its memory. * * @param rf route_flags struct to be destroyed */ static void destroy_route_flags(struct route_flags *rf) { struct route_rule *rs; struct route_rule *rs_tmp; if (rf->rules) { shm_free(rf->rules); } rs = rf->rule_list; while (rs != NULL) { rs_tmp = rs->next; destroy_route_rule(rs); rs = rs_tmp; } shm_free(rf); }
/** * 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; }
/** * Adds a route rule to rf. prefix, rewrite_hostpart, rewrite_local_prefix, * rewrite_local_suffix, and comment must not contain NULL pointers. * * @param rf the current route_flags struct * @param prefix the whole scan prefix * @param max_targets the number of targets * @param prob the weight of the rule * @param rewrite_hostpart the rewrite_host of the rule * @param strip the strip value of the rule * @param rewrite_local_prefix the rewrite prefix * @param rewrite_local_suffix the rewrite suffix * @param status the status of the rule * @param hash_index the hash index of the rule * @param backup indicates if the route is backed up by another. only useful if status==0, if set, it is the hash value of another rule * @param backed_up an NULL-termintated array of hash indices of the route for which this route is backup * @param comment a comment for the route rule * * @return 0 on success, -1 on failure * * @see add_route_to_tree() */ int add_route_rule(struct route_flags *rf, const str * prefix, int max_targets, double prob, const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix, const str * rewrite_local_suffix, int status, int hash_index, int backup, int * backed_up, const str * comment) { struct route_rule * shm_rr, * prev = NULL, * tmp = NULL; struct route_rule_p_list * t_rl; int * t_bu; if (max_targets) { rf->max_targets = max_targets; } else { rf->max_targets++; } if ((shm_rr = shm_malloc(sizeof(struct route_rule))) == NULL) { LM_ERR("out of shared memory\n"); return -1; } memset(shm_rr, 0, sizeof(struct route_rule)); if (shm_str_dup(&shm_rr->host, rewrite_hostpart) != 0) { goto mem_error; } if (shm_str_dup(&shm_rr->prefix, prefix) != 0) { goto mem_error; } shm_rr->strip = strip; if (shm_str_dup(&shm_rr->local_prefix, rewrite_local_prefix) != 0) { goto mem_error; } if (shm_str_dup(&shm_rr->local_suffix, rewrite_local_suffix) != 0) { goto mem_error; } if (shm_str_dup(&shm_rr->comment, comment) != 0) { goto mem_error; } shm_rr->status = status; shm_rr->hash_index = hash_index; shm_rr->orig_prob = prob; if (shm_rr->status || backup != -1) { shm_rr->prob = prob; } else { shm_rr->prob = 0; } if (backup >= 0) { if ((shm_rr->backup = shm_malloc(sizeof(struct route_rule_p_list))) == NULL) { goto mem_error; } memset(shm_rr->backup, 0, sizeof(struct route_rule_p_list)); shm_rr->backup->hash_index = backup; } shm_rr->backed_up = NULL; t_bu = backed_up; if(!backed_up){ LM_INFO("no backed up rules\n"); } while (t_bu && *t_bu != -1) { if ((t_rl = shm_malloc(sizeof(struct route_rule_p_list))) == NULL) { goto mem_error; } memset(t_rl, 0, sizeof(struct route_rule_p_list)); t_rl->hash_index = *t_bu; t_rl->next = shm_rr->backed_up; shm_rr->backed_up = t_rl; t_bu++; } /* rules with a probability of zero are always at the beginning of the list */ tmp = rf->rule_list; while(tmp && tmp->prob == 0){ prev = tmp; tmp = tmp->next; } /* rules with prob > 0 are sorted by hash_index */ while(tmp && (tmp->hash_index < shm_rr->hash_index)){ prev = tmp; tmp = tmp->next; } if(prev){ shm_rr->next = prev->next; prev->next = shm_rr; } else { shm_rr->next = rf->rule_list; rf->rule_list = shm_rr; } return 0; mem_error: LM_ERR("out of shared memory\n"); destroy_route_rule(shm_rr); return -1; }