cr_func.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cr_func.c 5497 2009-01-22 13:43:17Z henningw $
00003  *
00004  * Copyright (C) 2007-2008 1&1 Internet AG
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio 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  * Kamailio 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 
00023 /**
00024  * \file cr_func.c
00025  * \brief Routing and balancing functions.
00026  * \ingroup carrierroute
00027  * - Module; \ref carrierroute
00028  */
00029 
00030 #include <ctype.h>
00031 #include <assert.h>
00032 #include <stdlib.h>
00033 #include "cr_func.h"
00034 #include "cr_db.h"
00035 #include "../../sr_module.h"
00036 #include "../../action.h"
00037 #include "../../parser/parse_uri.h"
00038 #include "../../parser/parse_from.h"
00039 #include "../../ut.h"
00040 #include "../../parser/digest/digest.h"
00041 #include "../../parser/hf.h"
00042 #include "../../mem/mem.h"
00043 #include "../../qvalue.h"
00044 #include "../../dset.h"
00045 #include "cr_map.h"
00046 #include "cr_rule.h"
00047 #include "cr_domain.h"
00048 #include "cr_carrier.h"
00049 #include "carrierroute.h"
00050 
00051 
00052 enum hash_algorithm {
00053    alg_crc32 = 1, /*!< hashing algorithm is CRC32 */
00054    alg_prime, /*!< hashing algorithm is (right 18 digits of hash_source % prime_number) % max_targets + 1 */
00055    alg_error
00056 };
00057 
00058 
00059 static const str SIP_URI  = { .s="sip:",  .len=4 };
00060 static const str SIPS_URI = { .s="sips:", .len=5 };
00061 static const str AT_SIGN  = { .s="@",     .len=1 };
00062 
00063 
00064 /**
00065  * Get the id that belongs to a string name from gparam_t structure.
00066  *
00067  * Get the id that belongs to a string name from gparam_t structure, use the
00068  * search_id function for the lookup.
00069  * @param _msg SIP message
00070  * @param gp id as integer, pseudo-variable or AVP name of carrier
00071  * @param map lookup function
00072  * @param size size of the list
00073  * @return id on success, -1 otherwise
00074  */
00075 static inline int cr_gp2id(struct sip_msg *_msg, gparam_t *gp, struct name_map_t *map, int size) {
00076    int id;
00077    struct usr_avp *avp;
00078    int_str avp_val;
00079    str tmp;
00080 
00081    switch (gp->type) {
00082    case GPARAM_TYPE_INT:
00083       return gp->v.ival;
00084       break;
00085    case GPARAM_TYPE_PVE:
00086       /* does this PV hold an AVP? */
00087       if (gp->v.pve->spec.type==PVT_AVP) {
00088          avp = search_first_avp(gp->v.pve->spec.pvp.pvn.u.isname.type,
00089                   gp->v.pve->spec.pvp.pvn.u.isname.name, &avp_val, 0);
00090          if (!avp) {
00091             LM_ERR("cannot find AVP '%.*s'\n", gp->v.pve->spec.pvp.pvn.u.isname.name.s.len,
00092                   gp->v.pve->spec.pvp.pvn.u.isname.name.s.s);
00093             return -1;
00094          }
00095          if ((avp->flags&AVP_VAL_STR)==0) {
00096             return avp_val.n;
00097          } else {
00098             id = map_name2id(map, size, &avp_val.s);
00099             if (id < 0) {
00100                LM_ERR("could not find id '%.*s' from AVP\n",
00101                      gp->v.pve->spec.pvp.pvn.u.isname.name.s.len,
00102                      gp->v.pve->spec.pvp.pvn.u.isname.name.s.s);
00103                return -1;
00104             }
00105             return id;
00106          }
00107       } else {
00108          /* retrieve name from parameter */
00109          if (fixup_get_svalue(_msg, gp, &tmp)<0) {
00110             LM_ERR("cannot print the name from PV\n");
00111             return -1;
00112          }
00113          id = map_name2id(map, size, &tmp);
00114          if (id < 0) {
00115             LM_ERR("could not find id '%.*s' from PV\n", tmp.len, tmp.s);
00116             return -1;
00117          }
00118          return id;
00119       }
00120    default:
00121       LM_ERR("invalid parameter type\n");
00122       return -1;
00123    }
00124 }
00125 
00126 
00127 /**
00128  * Try to match the reply code rc to the reply code with wildcards.
00129  *
00130  * @param rcw reply code specifier with wildcards
00131  * @param rc the current reply code
00132  *
00133  * @return 0 on match, -1 otherwise
00134  */
00135 static inline int reply_code_matcher(const str *rcw, const str *rc) {
00136    int i;
00137    
00138    if (rcw->len==0) return 0;
00139    
00140    if (rcw->len != rc->len) return -1;
00141    
00142    for (i=0; i<rc->len; i++) {
00143       if (rcw->s[i]!='.' && rcw->s[i]!=rc->s[i]) return -1;
00144    }
00145    
00146    return 0;
00147 }
00148 
00149 
00150 /**
00151  * writes the next_domain avp using the rule list of failure_tree
00152  *
00153  * @param frr_head the head of the failure route rule list
00154  * @param host last tried host
00155  * @param reply_code the last reply code
00156  * @param flags flags for the failure route rule
00157  * @param dstavp the name of the AVP where to store the next domain
00158  *
00159  * @return 0 on success, -1 on failure
00160  */
00161 static int set_next_domain_on_rule(struct failure_route_rule *frr_head,
00162       const str *host, const str *reply_code, const flag_t flags,
00163       const gparam_t *dstavp) {
00164    struct failure_route_rule * rr;
00165    int_str avp_val;
00166    
00167    assert(frr_head != NULL);
00168    
00169    LM_DBG("searching for matching routing rules");
00170    for (rr = frr_head; rr != NULL; rr = rr->next) {
00171       /*
00172       LM_DBG("rr.flags=%d rr.mask=%d flags=%d\n", rr->flags, rr->mask, flags);
00173       LM_DBG("rr.host.len=%d host.len=%d\n", rr->host.len, host->len);
00174       LM_DBG("rr.host.s='%.*s' host.s='%.*s'\n", rr->host.len, rr->host.s, host->len, host->s);
00175       LM_DBG("rr.reply_code.len=%d reply_code.len=%d\n", rr->reply_code.len, reply_code->len);
00176       LM_DBG("rr.reply_code.s='%.*s' reply_code.s='%.*s'\n", rr->reply_code.len, rr->reply_code.s, reply_code->len, reply_code->s);
00177       */
00178       if (((rr->mask & flags) == rr->flags) &&
00179             ((rr->host.len == 0) || (str_strcmp(host, &rr->host)==0)) &&
00180             (reply_code_matcher(&(rr->reply_code), reply_code)==0)) {
00181          avp_val.n = rr->next_domain;
00182          if (add_avp(dstavp->v.pve->spec.pvp.pvn.u.isname.type,
00183                dstavp->v.pve->spec.pvp.pvn.u.isname.name, avp_val)<0) {
00184             LM_ERR("set AVP failed\n");
00185             return -1;
00186          }
00187          
00188          LM_INFO("next_domain is %d\n", rr->next_domain);
00189          return 0;
00190       }
00191    }
00192    
00193    LM_INFO("no matching rule for (flags=%d, host='%.*s', reply_code='%.*s') found\n", flags, host->len, host->s, reply_code->len, reply_code->s);
00194    return -1;
00195 }
00196 
00197 
00198 /**
00199  * traverses the failure routing tree until a matching rule is found.
00200  * The longest match is taken, so it is possible to define
00201  * failure route rules for a single number
00202  *
00203  * @param failure_node the current routing tree node
00204  * @param uri the uri to be rewritten at the current position
00205  * @param host last tried host
00206  * @param reply_code the last reply code
00207  * @param flags flags for the failure route rule
00208  * @param dstavp the name of the AVP where to store the next domain
00209  *
00210  * @return 0 on success, -1 on failure, 1 on no more matching child node and no rule list
00211  */
00212 static int set_next_domain_recursor(struct dtrie_node_t *failure_node,
00213       const str *uri, const str *host, const str *reply_code, const flag_t flags,
00214       const gparam_t *dstavp) {
00215    str re_uri = *uri;
00216    void **ret;
00217    
00218    /* Skip over non-digits.  */
00219    while (re_uri.len > 0 && (!isdigit(*re_uri.s) && cr_match_mode == 10)) {
00220       ++re_uri.s;
00221       --re_uri.len;
00222    }
00223    ret = dtrie_longest_match(failure_node, re_uri.s, re_uri.len, NULL, cr_match_mode);
00224 
00225    if (ret == NULL) {
00226       LM_INFO("URI or prefix tree nodes empty, empty rule list\n");
00227       return 1;
00228    }
00229    else return set_next_domain_on_rule(*ret, host, reply_code, flags, dstavp);
00230 }
00231 
00232 
00233 /**
00234  * searches for a rule int rt with hash_index prob - 1
00235  * If the rule with the desired hash index is deactivated,
00236  * the next working rule is used.
00237  *
00238  * @param rf the route_flags node to search for rule
00239  * @param prob the hash index
00240  *
00241  * @return pointer to route rule on success, NULL on failure
00242  */
00243 static struct route_rule * get_rule_by_hash(const struct route_flags * rf,
00244       const int prob) {
00245    struct route_rule * act_hash = NULL;
00246 
00247    if (prob > rf->rule_num) {
00248       LM_WARN("too large desired hash, taking highest\n");
00249       act_hash = rf->rules[rf->rule_num - 1];
00250    }
00251    act_hash = rf->rules[prob - 1];
00252 
00253    if (!act_hash->status) {
00254       if (act_hash->backup && act_hash->backup->rr) {
00255          act_hash = act_hash->backup->rr;
00256       } else {
00257          act_hash = NULL;
00258       }
00259    }
00260    LM_INFO("desired hash was %i, return %i\n", prob, act_hash ? act_hash->hash_index : -1);
00261    return act_hash;
00262 }
00263 
00264 
00265 /**
00266  * does the work for rewrite_on_rule, writes the new URI into dest
00267  *
00268  * @param rs the route rule used for rewriting
00269  * @param dest the returned new destination URI
00270  * @param msg the sip message
00271  * @param user the localpart of the uri to be rewritten
00272  * @param descavp the name of the AVP where the description is stored
00273  *
00274  * @return 0 on success, -1 on failure
00275  *
00276  * @see rewrite_on_rule()
00277  */
00278 static int actually_rewrite(const struct route_rule *rs, str *dest,
00279       const struct sip_msg *msg, const str * user, gparam_t *descavp) {
00280    size_t len;
00281    char *p;
00282    int_str avp_val;
00283    int strip = 0;
00284 
00285    strip = (rs->strip > user->len ? user->len : rs->strip);
00286    strip = (strip < 0 ? 0 : strip);
00287 
00288    len = rs->local_prefix.len + user->len + rs->local_suffix.len +
00289          AT_SIGN.len + rs->host.len - strip;
00290    if (msg->parsed_uri.type == SIPS_URI_T) {
00291       len += SIPS_URI.len;
00292    } else {
00293       len += SIP_URI.len;
00294    }
00295    dest->len = 0;
00296    dest->s = (char *)pkg_malloc(len + 1);
00297    if (dest->s == NULL) {
00298       PKG_MEM_ERROR;
00299       return -1;
00300    }
00301    dest->len = len;
00302    p = dest->s;
00303    if (msg->parsed_uri.type == SIPS_URI_T) {
00304       memcpy(p, SIPS_URI.s, SIPS_URI.len);
00305       p += SIPS_URI.len;
00306    } else {
00307       memcpy(p, SIP_URI.s, SIP_URI.len);
00308       p += SIP_URI.len;
00309    }
00310    if (user->len) {
00311       memcpy(p, rs->local_prefix.s, rs->local_prefix.len);
00312       p += rs->local_prefix.len;
00313       memcpy(p, user->s + strip, user->len - strip);
00314       p += user->len - strip;
00315       memcpy(p, rs->local_suffix.s, rs->local_suffix.len);
00316       p += rs->local_suffix.len;
00317       memcpy(p, AT_SIGN.s, AT_SIGN.len);
00318       p += AT_SIGN.len;
00319    }
00320    /* this could be an error, or a blacklisted destination */
00321    if (rs->host.len == 0) {
00322       *p = '\0';
00323       pkg_free(dest->s);
00324       return -1;
00325    }
00326    memcpy(p, rs->host.s, rs->host.len);
00327    p += rs->host.len;
00328    *p = '\0';
00329 
00330    if (descavp) {
00331       avp_val.s = rs->comment;
00332       if (add_avp(AVP_VAL_STR | descavp->v.pve->spec.pvp.pvn.u.isname.type,
00333                descavp->v.pve->spec.pvp.pvn.u.isname.name, avp_val)<0) {
00334          LM_ERR("set AVP failed\n");
00335          pkg_free(dest->s);
00336          return -1;
00337       }
00338    }
00339 
00340    return 0;
00341 }
00342 
00343 
00344 /**
00345  * writes the uri dest using the flags and rule list of rf_head
00346  *
00347  * @param rf_head the head of the route flags list
00348  * @param flags user defined flags
00349  * @param dest the returned new destination URI
00350  * @param msg the sip message
00351  * @param user the localpart of the uri to be rewritten
00352  * @param hash_source the SIP header used for hashing
00353  * @param alg the algorithm used for hashing
00354  * @param dstavp the name of the destination AVP where the used host name is stored
00355  *
00356  * @return 0 on success, -1 on failure, 1 on empty rule list
00357  */
00358 static int rewrite_on_rule(struct route_flags *rf_head, flag_t flags, str * dest,
00359       struct sip_msg * msg, const str * user, const enum hash_source hash_source,
00360       const enum hash_algorithm alg, gparam_t *dstavp) {
00361    struct route_flags * rf;
00362    struct route_rule * rr;
00363    int prob;
00364 
00365    assert(rf_head != NULL);
00366 
00367    LM_DBG("searching for matching routing rules");
00368    for (rf = rf_head; rf != NULL; rf = rf->next) {
00369       /* LM_DBG("actual flags %i, searched flags %i, mask %i and match %i", rf->flags, flags, rf->mask, flags&rf->mask); */
00370       if ((flags&rf->mask) == rf->flags) break;
00371    }
00372 
00373    if (rf==NULL) {
00374       LM_INFO("did not find a match for flags %d\n", flags);
00375       return -1;
00376    }
00377 
00378    if (rf->rule_list == NULL) {
00379       LM_INFO("empty rule list\n");
00380       return 1;
00381    }
00382 
00383    switch (alg) {
00384       case alg_prime:
00385          if ((prob = prime_hash_func(msg, hash_source, rf->max_targets)) < 0) {
00386             LM_ERR("could not hash message with prime algorithm");
00387             return -1;
00388          }
00389          if ((rr = get_rule_by_hash(rf, prob)) == NULL) {
00390             LM_CRIT("no route found\n");
00391             return -1;
00392          }
00393          break;
00394       case alg_crc32:
00395          if(rf->dice_max == 0) {
00396             LM_ERR("invalid dice_max value\n");
00397             return -1;
00398          }
00399          if ((prob = hash_func(msg, hash_source, rf->dice_max)) < 0) {
00400             LM_ERR("could not hash message with CRC32");
00401             return -1;
00402          }
00403          /* This auto-magically takes the last rule if anything is broken.
00404           * Sometimes the hash result is zero. If the first rule is off
00405           * (has a probablility of zero) then it has also a dice_to of
00406           * zero and the message could not be routed at all if we use
00407           * '<' here. Thus the '<=' is necessary.
00408           */
00409          for (rr = rf->rule_list;
00410                  rr->next != NULL && rr->dice_to <= prob;
00411               rr = rr->next) {}
00412          if (!rr->status) {
00413             if (!rr->backup) {
00414                LM_ERR("all routes are off\n");
00415                return -1;
00416             } else {
00417                if (!rr->backup->rr) {
00418                   LM_ERR("all routes are off\n");
00419                   return -1;
00420                }
00421                rr = rr->backup->rr;
00422             }
00423          }
00424          break;
00425       default: 
00426          LM_ERR("invalid hash algorithm\n");
00427          return -1;
00428    }
00429    return actually_rewrite(rr, dest, msg, user, dstavp);
00430 }
00431 
00432 
00433 /**
00434  * traverses the routing tree until a matching rule is found
00435  * The longest match is taken, so it is possible to define
00436  * route rules for a single number
00437  *
00438  * @param node the current routing tree node
00439  * @param pm the user to be used for prefix matching
00440  * @param flags user defined flags
00441  * @param dest the returned new destination URI
00442  * @param msg the sip message
00443  * @param user the localpart of the uri to be rewritten
00444  * @param hash_source the SIP header used for hashing
00445  * @param alg the algorithm used for hashing
00446  * @param dstavp the name of the destination AVP where the used host name is stored
00447  *
00448  * @return 0 on success, -1 on failure, 1 on no more matching child node and no rule list
00449  */
00450 static int rewrite_uri_recursor(struct dtrie_node_t * node,
00451       const str * pm, flag_t flags, str * dest, struct sip_msg * msg, const str * user,
00452       const enum hash_source hash_source, const enum hash_algorithm alg,
00453       gparam_t *dstavp) {
00454    str re_pm = *pm;
00455    void **ret;
00456    
00457    /* Skip over non-digits.  */
00458    while (re_pm.len > 0 && (!isdigit(*re_pm.s) && cr_match_mode == 10)) {
00459       ++re_pm.s;
00460       --re_pm.len;
00461    }
00462    ret = dtrie_longest_match(node, re_pm.s, re_pm.len, NULL, cr_match_mode);
00463 
00464    if (ret == NULL) {
00465       LM_INFO("URI or prefix tree nodes empty, empty rule list\n");
00466       return 1;
00467    }
00468    else return rewrite_on_rule(*ret, flags, dest, msg, user, hash_source, alg, dstavp);
00469 }
00470 
00471 
00472 /**
00473  * rewrites the request URI of msg after determining the
00474  * new destination URI
00475  *
00476  * @param _msg the current SIP message
00477  * @param _carrier the requested carrier
00478  * @param _domain the requested routing domain
00479  * @param _prefix_matching the user to be used for prefix matching
00480  * @param _rewrite_user the localpart of the URI to be rewritten
00481  * @param _hsrc the SIP header used for hashing
00482  * @param _halg the hash algorithm used for hashing
00483  * @param _dstavp the name of the destination AVP where the used host name is stored
00484  *
00485  * @return 1 on success, -1 on failure
00486  */
00487 int cr_do_route(struct sip_msg * _msg, gparam_t *_carrier,
00488       gparam_t *_domain, gparam_t *_prefix_matching,
00489       gparam_t *_rewrite_user, enum hash_source _hsrc,
00490       enum hash_algorithm _halg, gparam_t *_dstavp) {
00491 
00492    int carrier_id, domain_id, ret = -1;
00493    str rewrite_user, prefix_matching, dest;
00494    flag_t flags;
00495    struct route_data_t * rd;
00496    struct carrier_data_t * carrier_data;
00497    struct domain_data_t * domain_data;
00498    struct action act;
00499 
00500    if (fixup_get_svalue(_msg, _rewrite_user, &rewrite_user)<0) {
00501       LM_ERR("cannot print the rewrite_user\n");
00502       return -1;
00503    }
00504 
00505    if (fixup_get_svalue(_msg, _prefix_matching, &prefix_matching)<0) {
00506       LM_ERR("cannot print the prefix_matching\n");
00507       return -1;
00508    }
00509 
00510    flags = _msg->flags;
00511 
00512    do {
00513       rd = get_data();
00514    } while (rd == NULL);
00515 
00516    carrier_id = cr_gp2id(_msg, _carrier, rd->carrier_map, rd->carrier_num);
00517    if (carrier_id < 0) {
00518       LM_ERR("invalid carrier id %d\n", carrier_id);
00519       release_data(rd);
00520       return -1;
00521    }
00522 
00523    domain_id = cr_gp2id(_msg, _domain, rd->domain_map, rd->domain_num);
00524    if (domain_id < 0) {
00525       LM_ERR("invalid domain id %d\n", domain_id);
00526       release_data(rd);
00527       return -1;
00528    }
00529    
00530    carrier_data=NULL;
00531    if (carrier_id < 0) {
00532       if (fallback_default) {
00533          LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
00534          carrier_data = get_carrier_data(rd, rd->default_carrier_id);
00535       }
00536    } else if (carrier_id == 0) {
00537       carrier_data = get_carrier_data(rd, rd->default_carrier_id);
00538    } else {
00539       carrier_data = get_carrier_data(rd, carrier_id);
00540       if (carrier_data == NULL) {
00541          if (fallback_default) {
00542             LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
00543             carrier_data = get_carrier_data(rd, rd->default_carrier_id);
00544          }
00545       }
00546    }
00547    if (carrier_data == NULL) {
00548       LM_ERR("cannot get carrier data\n");
00549       goto unlock_and_out;
00550    }
00551 
00552    domain_data = get_domain_data(carrier_data, domain_id);
00553    if (domain_data == NULL) {
00554       LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n",
00555          prefix_matching.len, prefix_matching.s, carrier_id, domain_id);
00556       goto unlock_and_out;
00557    }
00558 
00559    if (rewrite_uri_recursor(domain_data->tree, &prefix_matching, flags, &dest, _msg, &rewrite_user, _hsrc, _halg, _dstavp) != 0) {
00560       /* this is not necessarily an error, rewrite_recursor does already some error logging */
00561       LM_INFO("rewrite_uri_recursor doesn't complete, uri %.*s, carrier %d, domain %d\n", prefix_matching.len,
00562          prefix_matching.s, carrier_id, domain_id);
00563       goto unlock_and_out;
00564    }
00565 
00566    LM_INFO("uri %.*s was rewritten to %.*s, carrier %d, domain %d\n", rewrite_user.len, rewrite_user.s, dest.len, dest.s, carrier_id, domain_id);
00567 
00568    act.type = SET_URI_T;
00569    act.elem[0].type= STRING_ST;
00570    act.elem[0].u.string = dest.s;
00571    act.next = NULL;
00572 
00573    ret = do_action(&act, _msg);
00574    if (ret < 0) {
00575       LM_ERR("Error in do_action()\n");
00576    }
00577    pkg_free(dest.s);
00578 
00579 unlock_and_out:
00580    release_data(rd);
00581    return ret;
00582 }
00583 
00584 
00585 /**
00586  * Loads user carrier from subscriber table and stores it in an AVP.
00587  *
00588  * @param _msg the current SIP message
00589  * @param _user the user to determine the carrier data
00590  * @param _domain the domain to determine the domain data
00591  * @param _dstavp the name of the AVP where to store the carrier id
00592  *
00593  * @return 1 on success, -1 on failure
00594  */
00595 int cr_load_user_carrier(struct sip_msg * _msg, gparam_t *_user, gparam_t *_domain, gparam_t *_dstavp) {
00596    str user, domain;
00597    int_str avp_val;
00598    
00599    if (fixup_get_svalue(_msg, _user, &user)<0) {
00600       LM_ERR("cannot print the user\n");
00601       return -1;
00602    }
00603 
00604    if (fixup_get_svalue(_msg, _domain, &domain)<0) {
00605       LM_ERR("cannot print the domain\n");
00606       return -1;
00607    }
00608    
00609    /* get carrier id */
00610    if ((avp_val.n = load_user_carrier(&user, &domain)) < 0) {
00611       LM_ERR("error in load user carrier");
00612       return -1;
00613    } else {
00614       /* set avp */
00615       if (add_avp(_dstavp->v.pve->spec.pvp.pvn.u.isname.type,
00616                _dstavp->v.pve->spec.pvp.pvn.u.isname.name, avp_val)<0) {
00617          LM_ERR("add AVP failed\n");
00618          return -1;
00619       }
00620    }
00621    return 1;
00622 }
00623 
00624 
00625 /**
00626  * rewrites the request URI of msg after determining the
00627  * new destination URI with the crc32 hash algorithm.
00628  *
00629  * @param _msg the current SIP message
00630  * @param _carrier the requested carrier
00631  * @param _domain the requested routing domain
00632  * @param _prefix_matching the user to be used for prefix matching
00633  * @param _rewrite_user the localpart of the URI to be rewritten
00634  * @param _hsrc the SIP header used for hashing
00635  * @param _dstavp the name of the destination AVP where the used host name is stored
00636  *
00637  * @return 1 on success, -1 on failure
00638  */
00639 int cr_route(struct sip_msg * _msg, gparam_t *_carrier,
00640       gparam_t *_domain, gparam_t *_prefix_matching,
00641       gparam_t *_rewrite_user, enum hash_source _hsrc,
00642       gparam_t *_dstavp)
00643 {
00644    return cr_do_route(_msg, _carrier, _domain, _prefix_matching,
00645       _rewrite_user, _hsrc, alg_crc32, _dstavp);
00646 }
00647 
00648 
00649 /**
00650  * rewrites the request URI of msg after determining the
00651  * new destination URI with the prime hash algorithm.
00652  *
00653  * @param _msg the current SIP message
00654  * @param _carrier the requested carrier
00655  * @param _domain the requested routing domain
00656  * @param _prefix_matching the user to be used for prefix matching
00657  * @param _rewrite_user the localpart of the URI to be rewritten
00658  * @param _hsrc the SIP header used for hashing
00659  * @param _dstavp the name of the destination AVP where the used host name is stored
00660  *
00661  * @return 1 on success, -1 on failure
00662  */
00663 int cr_prime_route(struct sip_msg * _msg, gparam_t *_carrier,
00664       gparam_t *_domain, gparam_t *_prefix_matching,
00665       gparam_t *_rewrite_user, enum hash_source _hsrc,
00666       gparam_t *_dstavp)
00667 {
00668    return cr_do_route(_msg, _carrier, _domain, _prefix_matching,
00669       _rewrite_user, _hsrc, alg_prime, _dstavp);
00670 }
00671 
00672 
00673 /**
00674  * Loads next domain from failure routing table and stores it in an AVP.
00675  *
00676  * @param _msg the current SIP message
00677  * @param _carrier the requested carrier
00678  * @param _domain the requested routing domain
00679  * @param _prefix_matching the user to be used for prefix matching
00680  * @param _host the host name to be used for rule matching
00681  * @param _reply_code the reply code to be used for rule matching
00682  * @param _dstavp the name of the destination AVP
00683  *
00684  * @return 1 on success, -1 on failure
00685  */
00686 int cr_load_next_domain(struct sip_msg * _msg, gparam_t *_carrier,
00687       gparam_t *_domain, gparam_t *_prefix_matching,
00688       gparam_t *_host, gparam_t *_reply_code, gparam_t *_dstavp) {
00689 
00690    int carrier_id, domain_id, ret = -1;
00691    str prefix_matching, host, reply_code;
00692    flag_t flags;
00693    struct route_data_t * rd;
00694    struct carrier_data_t * carrier_data;
00695    struct domain_data_t * domain_data;
00696 
00697    if (fixup_get_svalue(_msg, _prefix_matching, &prefix_matching)<0) {
00698       LM_ERR("cannot print the prefix_matching\n");
00699       return -1;
00700    }
00701    if (fixup_get_svalue(_msg, _host, &host)<0) {
00702       LM_ERR("cannot print the host\n");
00703       return -1;
00704    }
00705    if (fixup_get_svalue(_msg, _reply_code, &reply_code)<0) {
00706       LM_ERR("cannot print the reply_code\n");
00707       return -1;
00708    }
00709 
00710    flags = _msg->flags;
00711 
00712    do {
00713       rd = get_data();
00714    } while (rd == NULL);
00715    
00716    carrier_id = cr_gp2id(_msg, _carrier, rd->carrier_map, rd->carrier_num);
00717    if (carrier_id < 0) {
00718       LM_ERR("invalid carrier id %d\n", carrier_id);
00719       release_data(rd);
00720       return -1;
00721    }
00722 
00723    domain_id = cr_gp2id(_msg, _domain, rd->domain_map, rd->domain_num);
00724    if (domain_id < 0) {
00725       LM_ERR("invalid domain id %d\n", domain_id);
00726       release_data(rd);
00727       return -1;
00728    }
00729 
00730    carrier_data=NULL;
00731    if (carrier_id < 0) {
00732       if (fallback_default) {
00733          LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
00734          carrier_data = get_carrier_data(rd, rd->default_carrier_id);
00735       }
00736    } else if (carrier_id == 0) {
00737       carrier_data = get_carrier_data(rd, rd->default_carrier_id);
00738    } else {
00739       carrier_data = get_carrier_data(rd, carrier_id);
00740       if (carrier_data == NULL) {
00741          if (fallback_default) {
00742             LM_NOTICE("invalid tree id %i specified, using default tree\n", carrier_id);
00743             carrier_data = get_carrier_data(rd, rd->default_carrier_id);
00744          }
00745       }
00746    }
00747    if (carrier_data == NULL) {
00748       LM_ERR("cannot get carrier data\n");
00749       goto unlock_and_out;
00750    }
00751 
00752    domain_data = get_domain_data(carrier_data, domain_id);
00753    if (domain_data == NULL) {
00754       LM_ERR("desired routing domain doesn't exist, prefix %.*s, carrier %d, domain %d\n",
00755          prefix_matching.len, prefix_matching.s, carrier_id, domain_id);
00756       goto unlock_and_out;
00757    }
00758 
00759    if (set_next_domain_recursor(domain_data->failure_tree, &prefix_matching, &host, &reply_code, flags, _dstavp) != 0) {
00760       LM_INFO("set_next_domain_recursor doesn't complete, prefix '%.*s', carrier %d, domain %d\n", prefix_matching.len,
00761          prefix_matching.s, carrier_id, domain_id);
00762       goto unlock_and_out;
00763    }
00764    
00765    ret = 1;
00766    
00767 unlock_and_out:
00768    release_data(rd);
00769    return ret;
00770 }

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6