/** * writes the uri dest using the rule list of route_tree * * @param route_tree the current routing tree node * @param dest the returned new destination URI * @param msg the sip message * @param user the localpart of the uri to be rewritten * @param hash_source the SIP header used for hashing * @param alg the algorithm used for hashing * * @return 0 on success, -1 on failure */ static int rewrite_on_rule(struct route_tree_item * route_tree, str * dest, struct sip_msg * msg, str * user, enum hash_source hash_source, enum hash_algorithm alg) { struct route_rule * rr; int prob; assert(route_tree != NULL); assert(route_tree->rule_list != NULL); switch (alg) { case alg_prime: if ((prob = prime_hash_func(msg, hash_source, route_tree->max_targets)) < 0) { return -1; } if ((rr = get_rule_by_hash(route_tree, prob)) == NULL) { LM_CRIT("no route found\n"); return -1; } break; case alg_crc32: if(route_tree->dice_max == 0){ return -1; } if ((prob = hash_func(msg, hash_source, route_tree->dice_max)) < 0) { return -1; } /* This auto-magically takes the last rule if anything is broken. * Sometimes the hash result is zero. If the first rule is off * (has a probablility of zero) then it has also a dice_to of * zero and the message could not be routed at all if we use * '<' here. Thus the '<=' is necessary. */ for (rr = route_tree->rule_list; rr->next != NULL && rr->dice_to <= prob; rr = rr->next) {} if (!rr->status) { if (!rr->backup) { LM_ERR("all routes are off\n"); return -1; } else { if (!rr->backup->rr) { LM_ERR("all routes are off\n"); return -1; } rr = rr->backup->rr; } } break; default: return -1; } return actually_rewrite(rr, dest, msg, user); }
/** * writes the uri dest using the flags and rule list of rf_head * * @param rf_head the head of the route flags list * @param flags user defined flags * @param dest the returned new destination URI * @param msg the sip message * @param user the localpart of the uri to be rewritten * @param hash_source the SIP header used for hashing * @param alg the algorithm used for hashing * @param descavp the name of the AVP where the description is stored * * @return 0 on success, -1 on failure, 1 on empty rule list */ static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest, struct sip_msg * msg, const str * user, const enum hash_source hash_source, const enum hash_algorithm alg, gparam_t *descavp) { struct route_flags * rf; struct route_rule * rr; int prob; assert(rf_head != NULL); LM_DBG("searching for matching routing rules"); for (rf = rf_head; rf != NULL; rf = rf->next) { /* LM_DBG("actual flags %i, searched flags %i, mask %i and match %i", rf->flags, flags, rf->mask, flags&rf->mask); */ if ((flags&rf->mask) == rf->flags) break; } if (rf==NULL) { LM_INFO("did not find a match for flags %d\n", flags); return -1; } if (rf->rule_list == NULL) { LM_INFO("empty rule list\n"); return 1; } switch (alg) { case alg_crc32: { static avp_value_t used_dests[MAX_DESTINATIONS]; static int no_dests = 0; avp_value_t cr_new_uri; if(rf->dice_max == 0) { LM_ERR("invalid dice_max value\n"); return -1; } if ((prob = hash_func(msg, hash_source, rf->dice_max)) < 0) { LM_ERR("could not hash message with CRC32"); return -1; } /* This auto-magically takes the last rule if anything is broken. * Sometimes the hash result is zero. If the first rule is off * (has a probablility of zero) then it has also a dice_to of * zero and the message could not be routed at all if we use * '<' here. Thus the '<=' is necessary. * * cr_uri_already_used is a function that checks that the selected * rule has not been previously used as a failed destinatin */ for (rr = rf->rule_list; rr->next!= NULL && rr->dice_to <= prob ; rr = rr->next) {} //LM_DBG("CR: candidate hashed destination is: <%.*s>\n", rr->host.len, rr->host.s); if (cr_avoid_failed_dests) { if (is_route_type(FAILURE_ROUTE) && (mode == CARRIERROUTE_MODE_DB) ){ build_used_uris_list(used_dests, &no_dests); if (cr_uri_already_used(rr->host, used_dests, no_dests) ) { //LM_DBG("CR: selecting new destination !!! \n"); for (rr = rf->rule_list; rr!= NULL && cr_uri_already_used(rr->host, used_dests, no_dests); rr = rr->next) {} /* are there any destinations that were not already used? */ if (rr == NULL) { LM_NOTICE("All gateways from this group were already used\n"); return -1; } /* this is a hack: we do not take probabilities into consideration if first destination * was previously tried */ do { int rule_no = kam_rand() % rf->rule_num; //LM_DBG("CR: trying rule_no=%d \n", rule_no); for (rr = rf->rule_list; (rule_no > 0) && (rr->next!=NULL) ; rule_no-- , rr = rr->next) {} } while (cr_uri_already_used(rr->host, used_dests, no_dests)); LM_DBG("CR: candidate selected destination is: <%.*s>\n", rr->host.len, rr->host.s); } } } /*This should be regarded as an ELSE branch for the if above * ( status exists for mode == CARRIERROUTE_MODE_FILE */ if (!rr->status) { if (!rr->backup) { LM_ERR("all routes are off\n"); return -1; } else { if (!rr->backup->rr) { LM_ERR("all routes are off\n"); return -1; } rr = rr->backup->rr; } } if (cr_avoid_failed_dests) { //LM_DBG("CR: destination is: <%.*s>\n", rr->host.len, rr->host.s); cr_new_uri.s = rr->host; /* insert used destination into avp, in case corresponding request fails and * another destination has to be used; this new destination must not be one * that failed before */ if (mode == CARRIERROUTE_MODE_DB){ if ( add_avp( AVP_VAL_STR | AVP_NAME_STR, cr_uris_avp, cr_new_uri) < 0){ LM_ERR("set AVP failed\n"); return -1; } //print_cr_uri_avp(); } } break; } case alg_crc32_nofallback: if ((prob = (hash_func(msg, hash_source, rf->max_targets))) < 0) { LM_ERR("could not hash message with CRC32"); return -1; } /* Instead of search the whole rule_list if there is something broken * this function just tries only a backup rule and otherwise * returns -1. This way we get an error */ if ((rr = get_rule_by_hash(rf, prob + 1)) == NULL) { LM_CRIT("no route found\n"); return -1; } break; default: LM_ERR("invalid hash algorithm\n"); return -1; } return actually_rewrite(rr, dest, msg, user, descavp); }
/** * writes the uri dest using the flags and rule list of rf_head * * @param rf_head the head of the route flags list * @param flags user defined flags * @param dest the returned new destination URI * @param msg the sip message * @param user the localpart of the uri to be rewritten * @param hash_source the SIP header used for hashing * @param alg the algorithm used for hashing * @param descavp the name of the AVP where the description is stored * * @return 0 on success, -1 on failure, 1 on empty rule list */ static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest, struct sip_msg * msg, const str * user, const enum hash_source hash_source, const enum hash_algorithm alg, gparam_t *descavp) { struct route_flags * rf; struct route_rule * rr; int prob; assert(rf_head != NULL); LM_DBG("searching for matching routing rules"); for (rf = rf_head; rf != NULL; rf = rf->next) { /* LM_DBG("actual flags %i, searched flags %i, mask %i and match %i", rf->flags, flags, rf->mask, flags&rf->mask); */ if ((flags&rf->mask) == rf->flags) break; } if (rf==NULL) { LM_INFO("did not find a match for flags %d\n", flags); return -1; } if (rf->rule_list == NULL) { LM_INFO("empty rule list\n"); return 1; } switch (alg) { case alg_crc32: if(rf->dice_max == 0) { LM_ERR("invalid dice_max value\n"); return -1; } if ((prob = hash_func(msg, hash_source, rf->dice_max)) < 0) { LM_ERR("could not hash message with CRC32"); return -1; } /* This auto-magically takes the last rule if anything is broken. * Sometimes the hash result is zero. If the first rule is off * (has a probablility of zero) then it has also a dice_to of * zero and the message could not be routed at all if we use * '<' here. Thus the '<=' is necessary. */ for (rr = rf->rule_list; rr->next != NULL && rr->dice_to <= prob; rr = rr->next) {} if (!rr->status) { if (!rr->backup) { LM_ERR("all routes are off\n"); return -1; } else { if (!rr->backup->rr) { LM_ERR("all routes are off\n"); return -1; } rr = rr->backup->rr; } } break; case alg_crc32_nofallback: if ((prob = (hash_func(msg, hash_source, rf->max_targets))) < 0) { LM_ERR("could not hash message with CRC32"); return -1; } /* Instead of search the whole rule_list if there is something broken * this function just tries only a backup rule and otherwise * returns -1. This way we get an error */ if ((rr = get_rule_by_hash(rf, prob + 1)) == NULL) { LM_CRIT("no route found\n"); return -1; } break; default: LM_ERR("invalid hash algorithm\n"); return -1; } return actually_rewrite(rr, dest, msg, user, descavp); }