/** * traverses the failure routing tree until a matching rule is found. * The longest match is taken, so it is possible to define * failure route rules for a single number * * @param failure_tree the current routing tree node * @param uri the uri to be rewritten at the current position * @param host last tried host * @param reply_code the last reply code * @param flags flags for the failure route rule * @param dstavp the name of the AVP where to store the next domain * * @return 0 on success, -1 on failure, 1 on no more matching child node and no rule list */ static int set_next_domain_recursor(const struct failure_route_tree_item *failure_tree, const str *uri, const str *host, const str *reply_code, const flag_t flags, const struct multiparam_t *dstavp) { int ret; struct failure_route_tree_item *re_tree; str re_uri = *uri; /* Skip over non-digits. */ while (re_uri.len > 0 && !isdigit(*re_uri.s)) { ++re_uri.s; --re_uri.len; } if (re_uri.len == 0 || failure_tree->nodes[*re_uri.s - '0'] == NULL) { if (failure_tree->rule_list == NULL) { LM_INFO("URI or route tree nodes empty, empty rule list\n"); return 1; } else { return set_next_domain_on_rule(failure_tree, host, reply_code, flags, dstavp); } } else { /* match, goto the next digit of the uri and try again */ re_tree = failure_tree->nodes[*re_uri.s - '0']; re_uri.s++; re_uri.len--; ret = set_next_domain_recursor(re_tree, &re_uri, host, reply_code, flags, dstavp); switch (ret) { case 0: return 0; case 1: if (failure_tree->rule_list != NULL) { return set_next_domain_on_rule(failure_tree, host, reply_code, flags, dstavp); } else { LM_INFO("empty rule list for host [%.*s]%.*s\n", re_uri.len, re_uri.s, host->len, host->s); return 1; } default: return -1; } } }
/** * Loads next domain from failure routing table and stores it in an AVP. * * @param _msg the current SIP message * @param _carrier the requested carrier * @param _domain the requested routing domain * @param _prefix_matching the user to be used for prefix matching * @param _host the host name to be used for rule matching * @param _reply_code the reply code to be used for rule matching * @param _dstavp the name of the destination AVP * * @return 1 on success, -1 on failure */ int cr_load_next_domain(struct sip_msg * _msg, gparam_t *_carrier, gparam_t *_domain, gparam_t *_prefix_matching, gparam_t *_host, gparam_t *_reply_code, gparam_t *_dstavp) { int carrier_id, domain_id, ret = -1; str prefix_matching, host, reply_code; flag_t flags; struct route_data_t * rd; struct carrier_data_t * carrier_data; struct domain_data_t * domain_data; if (fixup_get_svalue(_msg, _prefix_matching, &prefix_matching)<0) { LM_ERR("cannot print the prefix_matching\n"); return -1; } if (fixup_get_svalue(_msg, _host, &host)<0) { LM_ERR("cannot print the host\n"); return -1; } if (fixup_get_svalue(_msg, _reply_code, &reply_code)<0) { LM_ERR("cannot print the reply_code\n"); return -1; } flags = _msg->flags; do { rd = get_data(); } while (rd == NULL); carrier_id = cr_gp2id(_msg, _carrier, rd->carrier_map, rd->carrier_num); if (carrier_id < 0) { LM_ERR("invalid carrier id %d\n", carrier_id); release_data(rd); return -1; } domain_id = cr_gp2id(_msg, _domain, rd->domain_map, rd->domain_num); if (domain_id < 0) { LM_ERR("invalid domain id %d\n", domain_id); release_data(rd); return -1; } carrier_data=NULL; if (carrier_id < 0) { if (cfg_get(carrierroute, carrierroute_cfg, fallback_default)) { LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id); carrier_data = get_carrier_data(rd, rd->default_carrier_id); } } else if (carrier_id == 0) { carrier_data = get_carrier_data(rd, rd->default_carrier_id); } else { carrier_data = get_carrier_data(rd, carrier_id); if (carrier_data == NULL) { if (cfg_get(carrierroute, carrierroute_cfg, fallback_default)) { LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id); carrier_data = get_carrier_data(rd, rd->default_carrier_id); } } } if (carrier_data == NULL) { LM_ERR("cannot get carrier data\n"); goto unlock_and_out; } domain_data = get_domain_data(carrier_data, domain_id); if (domain_data == NULL) { LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n", prefix_matching.len, prefix_matching.s, carrier_id, domain_id); goto unlock_and_out; } if (set_next_domain_recursor(domain_data->failure_tree, &prefix_matching, &host, &reply_code, flags, _dstavp) != 0) { LM_INFO("set_next_domain_recursor doesn't complete, prefix '%.*s', carrier %d, domain %d\n", prefix_matching.len, prefix_matching.s, carrier_id, domain_id); goto unlock_and_out; } ret = 1; unlock_and_out: release_data(rd); return ret; }
/** * Loads next domain from failure routing table and stores it in an AVP. * * @param _msg the current SIP message * @param _carrier the requested carrier * @param _domain the requested routing domain * @param _prefix_matching the user to be used for prefix matching * @param _host the host name to be used for rule matching * @param _reply_code the reply code to be used for rule matching * @param _dstavp the name of the destination AVP * * @return 1 on success, -1 on failure */ int cr_load_next_domain(struct sip_msg * _msg, struct multiparam_t *_carrier, struct multiparam_t *_domain, pv_elem_t *_prefix_matching, pv_elem_t *_host, pv_elem_t *_reply_code, struct multiparam_t *_dstavp) { int carrier_id; int domain_id; str prefix_matching; str host; str reply_code; flag_t flags; struct rewrite_data * rd; struct carrier_tree * ct; struct route_tree * rt; int ret; ret = -1; carrier_id = mp2carrier_id(_msg, _carrier); domain_id = mp2domain_id(_msg, _domain); if (domain_id < 0) { LM_ERR("invalid domain id %d\n", domain_id); return -1; } if (pv_printf_s(_msg, _prefix_matching, &prefix_matching)<0) { LM_ERR("cannot print the prefix_matching\n"); return -1; } if (pv_printf_s(_msg, _host, &host)<0) { LM_ERR("cannot print the host\n"); return -1; } if (pv_printf_s(_msg, _reply_code, &reply_code)<0) { LM_ERR("cannot print the reply_code\n"); return -1; } flags = _msg->flags; do { rd = get_data(); } while (rd == NULL); ct=NULL; if (carrier_id < 0) { if (fallback_default) { LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id); ct = rd->carriers[rd->default_carrier_index]; } } else if (carrier_id == 0) { ct = rd->carriers[rd->default_carrier_index]; } else { ct = get_carrier_tree(carrier_id, rd); if (ct == NULL) { if (fallback_default) { LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id); ct = rd->carriers[rd->default_carrier_index]; } } } if (ct == NULL) { LM_ERR("cannot get carrier tree\n"); goto unlock_and_out; } rt = get_route_tree_by_id(ct, domain_id); if (rt == NULL) { LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n", prefix_matching.len, prefix_matching.s, carrier_id, domain_id); goto unlock_and_out; } if (set_next_domain_recursor(rt->failure_tree, &prefix_matching, &host, &reply_code, flags, _dstavp) != 0) { LM_ERR("during set_next_domain_recursor, prefix '%.*s', carrier %d, domain %d\n", prefix_matching.len, prefix_matching.s, carrier_id, domain_id); goto unlock_and_out; } ret = 1; unlock_and_out: release_data(rd); return ret; }