drouting.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2005-2009 Voice Sistem SRL
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  * History:
00024  * ---------
00025  *  2005-02-20  first version (cristian)
00026  *  2005-02-27  ported to 0.9.0 (bogdan)
00027  */
00028 
00029 #include "stdlib.h"
00030 #include "stdio.h"
00031 #include "assert.h"
00032 #include <unistd.h>
00033 
00034 #include "../../sr_module.h"
00035 #include "../../str.h"
00036 #include "../../dprint.h"
00037 #include "../../usr_avp.h"
00038 #include "../../lib/srdb1/db.h"
00039 #include "../../mem/mem.h"
00040 #include "../../mem/shm_mem.h"
00041 #include "../../locking.h"
00042 #include "../../action.h"
00043 #include "../../error.h"
00044 #include "../../ut.h"
00045 #include "../../resolve.h"
00046 #include "../../parser/parse_from.h"
00047 #include "../../parser/parse_uri.h"
00048 #include "../../dset.h"
00049 #include "../../lib/kmi/mi.h"
00050 
00051 #include "dr_load.h"
00052 #include "prefix_tree.h"
00053 #include "routing.h"
00054 
00055 
00056 /*** DB relatede stuff ***/
00057 /* parameters  */
00058 static str db_url = {NULL,0};
00059 static str drg_table = str_init("dr_groups");
00060 static str drd_table = str_init("dr_gateways");
00061 static str drr_table = str_init("dr_rules");
00062 static str drl_table = str_init("dr_gw_lists");
00063 /* DRG use domain */
00064 static int use_domain = 1;
00070 static int sort_order = 0;
00071 int dr_fetch_rows = 1000;
00072 int dr_force_dns = 1;
00073 
00074 /* DRG table columns */
00075 static str drg_user_col = str_init("username");
00076 static str drg_domain_col = str_init("domain");
00077 static str drg_grpid_col = str_init("groupid");
00078 /* variables */
00079 static db1_con_t  *db_hdl=0;     /* DB handler */
00080 static db_func_t dr_dbf;        /* DB functions */
00081 
00082 /* current dr data - pointer to a pointer in shm */
00083 static rt_data_t **rdata = 0;
00084 
00085 /* AVP used to store serial RURIs */
00086 static struct _ruri_avp{
00087         unsigned short type; /* AVP ID */
00088         int_str name; /* AVP name*/
00089 }ruri_avp = { 0, {.n=(int)0xad346b2f} };
00090 static str ruri_avp_spec = {0,0};
00091 
00092 /* AVP used to store serial ATTRs */
00093 static struct _attrs_avp{
00094         unsigned short type; /* AVP ID */
00095         int_str name; /* AVP name*/
00096 }attrs_avp = { 0, {.n=(int)0xad346b30} };
00097 static str attrs_avp_spec = {0,0};
00098 
00099 /* statistic data */
00100 int tree_size = 0;
00101 int inode = 0;
00102 int unode = 0;
00103 
00104 /* lock, ref counter and flag used for reloading the date */
00105 static gen_lock_t *ref_lock = 0;
00106 static int* data_refcnt = 0;
00107 static int* reload_flag = 0;
00108 
00109 static int dr_init(void);
00110 static int dr_child_init(int rank);
00111 static int dr_exit(void);
00112 
00113 static int fixup_do_routing(void** param, int param_no);
00114 static int fixup_from_gw(void** param, int param_no);
00115 
00116 static int do_routing(struct sip_msg* msg, dr_group_t *drg);
00117 static int do_routing_0(struct sip_msg* msg, char* str1, char* str2);
00118 static int do_routing_1(struct sip_msg* msg, char* str1, char* str2);
00119 static int use_next_gw(struct sip_msg* msg);
00120 static int is_from_gw_0(struct sip_msg* msg, char* str1, char* str2);
00121 static int is_from_gw_1(struct sip_msg* msg, char* str1, char* str2);
00122 static int is_from_gw_2(struct sip_msg* msg, char* str1, char* str2);
00123 static int goes_to_gw_0(struct sip_msg* msg, char* f1, char* f2);
00124 static int goes_to_gw_1(struct sip_msg* msg, char* f1, char* f2);
00125 
00126 static struct mi_root* dr_reload_cmd(struct mi_root *cmd_tree, void *param);
00127 
00128 #define RELOAD_MI_CMD  "dr_reload"
00129 
00130 
00131 MODULE_VERSION
00132 
00133 /*
00134  * Exported functions
00135  */
00136 static cmd_export_t cmds[] = {
00137         {"do_routing",  (cmd_function)do_routing_0,   0,  0, 0,
00138                 REQUEST_ROUTE|FAILURE_ROUTE},
00139         {"do_routing",  (cmd_function)do_routing_1,   1,  fixup_do_routing, 0,
00140                 REQUEST_ROUTE|FAILURE_ROUTE},
00141         {"use_next_gw",  (cmd_function)use_next_gw,   0,  0, 0,
00142                 REQUEST_ROUTE|FAILURE_ROUTE},
00143         {"next_routing",  (cmd_function)use_next_gw, 0,  0, 0,
00144                 FAILURE_ROUTE},
00145         {"is_from_gw",  (cmd_function)is_from_gw_0,   0,  0, 0,
00146                 REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
00147         {"is_from_gw",  (cmd_function)is_from_gw_1,   1,  fixup_from_gw, 0,
00148                 REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
00149         {"is_from_gw",  (cmd_function)is_from_gw_2,   2,  fixup_from_gw, 0,
00150                 REQUEST_ROUTE},
00151         {"goes_to_gw",  (cmd_function)goes_to_gw_0,   0,  0, 0,
00152                 REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
00153         {"goes_to_gw",  (cmd_function)goes_to_gw_1,   1,  fixup_from_gw, 0,
00154                 REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
00155         {0, 0, 0, 0, 0, 0}
00156 };
00157 
00158 
00159 /*
00160  * Exported parameters
00161  */
00162 static param_export_t params[] = {
00163         {"db_url",          STR_PARAM, &db_url.s        },
00164         {"drd_table",       STR_PARAM, &drd_table.s     },
00165         {"drr_table",       STR_PARAM, &drr_table.s     },
00166         {"drg_table",       STR_PARAM, &drg_table.s     },
00167         {"drl_table",       STR_PARAM, &drl_table.s     },
00168         {"use_domain",      INT_PARAM, &use_domain      },
00169         {"drg_user_col",    STR_PARAM, &drg_user_col.s  },
00170         {"drg_domain_col",  STR_PARAM, &drg_domain_col.s},
00171         {"drg_grpid_col",   STR_PARAM, &drg_grpid_col.s },
00172         {"ruri_avp",        STR_PARAM, &ruri_avp_spec.s },
00173         {"attrs_avp",       STR_PARAM, &attrs_avp_spec.s},
00174         {"sort_order",      INT_PARAM, &sort_order      },
00175         {"fetch_rows",      INT_PARAM, &dr_fetch_rows   },
00176         {"force_dns",       INT_PARAM, &dr_force_dns    },
00177         {0, 0, 0}
00178 };
00179 
00180 
00181 /*
00182  * Exported MI functions
00183  */
00184 static mi_export_t mi_cmds[] = {
00185         { RELOAD_MI_CMD, dr_reload_cmd, MI_NO_INPUT_FLAG, 0, 0 },
00186         { 0, 0, 0, 0, 0}
00187 };
00188 
00189 
00190 
00191 struct module_exports exports = {
00192         "drouting",
00193         DEFAULT_DLFLAGS, /* dlopen flags */
00194         cmds,            /* Exported functions */
00195         params,          /* Exported parameters */
00196         0,               /* exported statistics */
00197         mi_cmds,         /* exported MI functions */
00198         0,               /* exported pseudo-variables */
00199         0,               /* additional processes */
00200         dr_init,         /* Module initialization function */
00201         (response_function) 0,
00202         (destroy_function) dr_exit,
00203         (child_init_function) dr_child_init /* per-child init function */
00204 };
00205 
00206 
00210 static inline int rewrite_ruri(struct sip_msg* _m, char* _s)
00211 {
00212    struct action act;
00213    struct run_act_ctx ra_ctx;
00214 
00215    memset(&act, '\0', sizeof(act));
00216    act.type = SET_URI_T;
00217    act.val[0].type = STRING_ST;
00218    act.val[0].u.string = _s;
00219    init_run_actions_ctx(&ra_ctx);
00220    if (do_action(&ra_ctx, &act, _m) < 0)
00221    {
00222       LM_ERR("do_action failed\n");
00223       return -1;
00224    }
00225    return 0;
00226 }
00227 
00228 static inline int dr_reload_data( void )
00229 {
00230         rt_data_t *new_data;
00231         rt_data_t *old_data;
00232 
00233         new_data = dr_load_routing_info( &dr_dbf, db_hdl,
00234                 &drd_table, &drl_table, &drr_table);
00235         if ( new_data==0 ) {
00236                 LM_CRIT("failed to load routing info\n");
00237                 return -1;
00238         }
00239 
00240         /* block access to data for all readers */
00241         lock_get( ref_lock );
00242         *reload_flag = 1;
00243         lock_release( ref_lock );
00244 
00245         /* wait for all readers to finish - it's a kind of busy waitting but
00246          * it's not critical;
00247          * at this point, data_refcnt can only be decremented */
00248         while (*data_refcnt) {
00249                 usleep(10);
00250         }
00251 
00252         /* no more activ readers -> do the swapping */
00253         old_data = *rdata;
00254         *rdata = new_data;
00255 
00256         /* release the readers */
00257         *reload_flag = 0;
00258 
00259         /* destroy old data */
00260         if (old_data)
00261                 free_rt_data( old_data, 1 );
00262 
00263         return 0;
00264 }
00265 
00266 
00267 
00268 static int dr_init(void)
00269 {
00270         pv_spec_t avp_spec;
00271 
00272         LM_INFO("DRouting - initializing\n");
00273 
00274         if(register_mi_mod(exports.name, mi_cmds)!=0)
00275         {
00276                 LM_ERR("failed to register MI commands\n");
00277                 return -1;
00278         }
00279 
00280         /* check the module params */
00281         if (db_url.s==NULL || db_url.s[0]==0) {
00282                 LM_CRIT("mandatory parameter \"DB_URL\" found empty\n");
00283                 goto error;
00284         }
00285         db_url.len = strlen(db_url.s);
00286 
00287         drd_table.len = strlen(drd_table.s);
00288         if (drd_table.s[0]==0) {
00289                 LM_CRIT("mandatory parameter \"DRD_TABLE\" found empty\n");
00290                 goto error;
00291         }
00292 
00293         drr_table.len = strlen(drr_table.s);
00294         if (drr_table.s[0]==0) {
00295                 LM_CRIT("mandatory parameter \"DRR_TABLE\" found empty\n");
00296                 goto error;
00297         }
00298 
00299         drg_table.len = strlen(drg_table.s);
00300         if (drg_table.s[0]==0) {
00301                 LM_CRIT("mandatory parameter \"DRG_TABLE\"  found empty\n");
00302                 goto error;
00303         }
00304 
00305         drl_table.len = strlen(drl_table.s);
00306         if (drl_table.s[0]==0) {
00307                 LM_CRIT("mandatory parameter \"DRL_TABLE\"  found empty\n");
00308                 goto error;
00309         }
00310 
00311         drg_user_col.len = strlen(drg_user_col.s);
00312         drg_domain_col.len = strlen(drg_domain_col.s);
00313         drg_grpid_col.len = strlen(drg_grpid_col.s);
00314 
00315         /* fix AVP spec */
00316         if (ruri_avp_spec.s) {
00317                 ruri_avp_spec.len = strlen(ruri_avp_spec.s);
00318 
00319                 if (pv_parse_spec( &ruri_avp_spec, &avp_spec)==0
00320                 || avp_spec.type!=PVT_AVP) {
00321                         LM_ERR("malformed or non AVP [%.*s] for RURI AVP definition\n",
00322                                 ruri_avp_spec.len, ruri_avp_spec.s);
00323                         return E_CFG;
00324                 }
00325 
00326                 if( pv_get_avp_name(0, &(avp_spec.pvp), &(ruri_avp.name),
00327                 &(ruri_avp.type) )!=0) {
00328                         LM_ERR("[%.*s]- invalid AVP definition for RURI AVP\n",
00329                                 ruri_avp_spec.len, ruri_avp_spec.s);
00330                         return E_CFG;
00331                 }
00332         }
00333         if (attrs_avp_spec.s) {
00334                 attrs_avp_spec.len = strlen(attrs_avp_spec.s);
00335 
00336                 if (pv_parse_spec( &attrs_avp_spec, &avp_spec)==0
00337                 || avp_spec.type!=PVT_AVP) {
00338                         LM_ERR("malformed or non AVP [%.*s] for ATTRS AVP definition\n",
00339                                 attrs_avp_spec.len, attrs_avp_spec.s);
00340                         return E_CFG;
00341                 }
00342 
00343                 if( pv_get_avp_name(0, &(avp_spec.pvp), &(attrs_avp.name),
00344                 &(attrs_avp.type) )!=0) {
00345                         LM_ERR("[%.*s]- invalid AVP definition for ATTRS AVP\n",
00346                                 attrs_avp_spec.len, attrs_avp_spec.s);
00347                         return E_CFG;
00348                 }
00349         }
00350 
00351         /* data pointer in shm */
00352         rdata = (rt_data_t**)shm_malloc( sizeof(rt_data_t*) );
00353         if (rdata==0) {
00354                 LM_CRIT("failed to get shm mem for data ptr\n");
00355                 goto error;
00356         }
00357         *rdata = 0;
00358 
00359         /* create & init lock */
00360         if ( (ref_lock=lock_alloc())==0) {
00361                 LM_CRIT("failed to alloc ref_lock\n");
00362                 goto error;
00363         }
00364         if (lock_init(ref_lock)==0 ) {
00365                 LM_CRIT("failed to init ref_lock\n");
00366                 goto error;
00367         }
00368         data_refcnt = (int*)shm_malloc(sizeof(int));
00369         reload_flag = (int*)shm_malloc(sizeof(int));
00370         if(!data_refcnt || !reload_flag)
00371         {
00372                 LM_ERR("no more shared memory\n");
00373                 goto error;
00374         }
00375         *data_refcnt = 0;
00376         *reload_flag = 0;
00377 
00378         /* bind to the mysql module */
00379         if (db_bind_mod( &db_url, &dr_dbf  )) {
00380                 LM_CRIT("cannot bind to database module! "
00381                         "Did you forget to load a database module ?\n");
00382                 goto error;
00383         }
00384 
00385         if (!DB_CAPABILITY( dr_dbf, DB_CAP_QUERY)) {
00386                 LM_CRIT( "database modules does not "
00387                         "provide QUERY functions needed by DRounting module\n");
00388                 return -1;
00389         }
00390 
00391         return 0;
00392 error:
00393         if (ref_lock) {
00394                 lock_destroy( ref_lock );
00395                 lock_dealloc( ref_lock );
00396                 ref_lock = 0;
00397         }
00398         if (db_hdl) {
00399                 dr_dbf.close(db_hdl);
00400                 db_hdl = 0;
00401         }
00402         if (rdata) {
00403                 shm_free(rdata);
00404                 rdata = 0;
00405         }
00406         return -1;
00407 }
00408 
00409 
00410 
00411 static int dr_child_init(int rank)
00412 {
00413         /* only workers needs DB connection */
00414         if (rank==PROC_MAIN || rank==PROC_TCP_MAIN || rank==PROC_INIT)
00415                 return 0;
00416 
00417         /* init DB connection */
00418         if ( (db_hdl=dr_dbf.init(&db_url))==0 ) {
00419                 LM_CRIT("cannot initialize database connection\n");
00420                 return -1;
00421         }
00422 
00423         /* child 1 load the routing info */
00424         if ( (rank==1) && dr_reload_data()!=0 ) {
00425                 LM_CRIT("failed to load routing data\n");
00426                 return -1;
00427         }
00428 
00429         /* set GROUP table for workers */
00430         if (dr_dbf.use_table( db_hdl, &drg_table) < 0) {
00431                 LM_ERR("cannot select table \"%.*s\"\n", drg_table.len, drg_table.s);
00432                 return -1;
00433         }
00434         srand(getpid()+time(0)+rank);
00435         return 0;
00436 }
00437 
00438 
00439 static int dr_exit(void)
00440 {
00441         /* close DB connection */
00442         if (db_hdl) {
00443                 dr_dbf.close(db_hdl);
00444                 db_hdl = 0;
00445         }
00446 
00447         /* destroy data */
00448         if ( rdata) {
00449                 if (*rdata)
00450                         free_rt_data( *rdata, 1 );
00451                 shm_free( rdata );
00452                 rdata = 0;
00453         }
00454 
00455         /* destroy lock */
00456         if (ref_lock) {
00457                 lock_destroy( ref_lock );
00458                 lock_dealloc( ref_lock );
00459                 ref_lock = 0;
00460         }
00461         
00462         if(reload_flag)
00463                 shm_free(reload_flag);
00464         if(data_refcnt)
00465                 shm_free(data_refcnt);
00466 
00467         return 0;
00468 }
00469 
00470 
00471 
00472 static struct mi_root* dr_reload_cmd(struct mi_root *cmd_tree, void *param)
00473 {
00474         int n;
00475 
00476         LM_INFO("\"%s\" MI command received!\n",RELOAD_MI_CMD);
00477 
00478         /* init DB connection if needed */
00479         if (db_hdl==NULL) {
00480                 db_hdl=dr_dbf.init(&db_url);
00481                 if(db_hdl==0 ) {
00482                         LM_CRIT("cannot initialize database connection\n");
00483                         goto error;
00484                 }
00485         }
00486 
00487         if ( (n=dr_reload_data())!=0 ) {
00488                 LM_CRIT("failed to load routing data\n");
00489                 goto error;
00490         }
00491 
00492         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00493 error:
00494         return init_mi_tree( 500, "Failed to reload",16);
00495 }
00496 
00497 
00498 
00499 static inline int get_group_id(struct sip_uri *uri)
00500 {
00501         db_key_t keys_ret[1];
00502         db_key_t keys_cmp[2];
00503         db_val_t vals_cmp[2];
00504         db1_res_t* res;
00505         int n;
00506 
00507 
00508         /* user */
00509         keys_cmp[0] = &drg_user_col;
00510         vals_cmp[0].type = DB1_STR;
00511         vals_cmp[0].nul  = 0;
00512         vals_cmp[0].val.str_val = uri->user;
00513         n = 1;
00514 
00515         if (use_domain) {
00516                 keys_cmp[1] = &drg_domain_col;
00517                 vals_cmp[1].type = DB1_STR;
00518                 vals_cmp[1].nul  = 0;
00519                 vals_cmp[1].val.str_val = uri->host;
00520                 n++;
00521         }
00522 
00523         keys_ret[0] = &drg_grpid_col;
00524         res = 0;
00525 
00526         if ( dr_dbf.query(db_hdl,keys_cmp,0,vals_cmp,keys_ret,n,1,0,&res)<0 ) {
00527                 LM_ERR("DB query failed\n");
00528                 goto error;
00529         }
00530 
00531         if (RES_ROW_N(res) == 0) {
00532                 LM_ERR("no group for user "
00533                         "\"%.*s\"@\"%.*s\"\n", uri->user.len, uri->user.s,
00534                         uri->host.len, uri->host.s);
00535                 goto error;
00536         }
00537         if (res->rows[0].values[0].nul || res->rows[0].values[0].type!=DB1_INT) {
00538                 LM_ERR("null or non-integer group_id\n");
00539                 goto error;
00540         }
00541         n = res->rows[0].values[0].val.int_val;
00542 
00543         dr_dbf.free_result(db_hdl, res);
00544         return n;
00545 error:
00546         if (res)
00547                 dr_dbf.free_result(db_hdl, res);
00548         return -1;
00549 }
00550 
00551 
00552 
00553 static inline str* build_ruri(struct sip_uri *uri, int strip, str *pri,
00554                                                                                                                                 str *hostport)
00555 {
00556         static str uri_str;
00557         char *p;
00558 
00559         if (uri->user.len<=strip) {
00560                 LM_ERR("stripping %d makes "
00561                         "username <%.*s> null\n",strip,uri->user.len,uri->user.s);
00562                 return 0;
00563         }
00564 
00565         uri_str.len = 4 /*sip:*/ + uri->user.len - strip +pri->len +
00566                 (uri->passwd.s?(uri->passwd.len+1):0) + 1/*@*/ + hostport->len +
00567                 (uri->params.s?(uri->params.len+1):0) +
00568                 (uri->headers.s?(uri->headers.len+1):0);
00569 
00570         if ( (uri_str.s=(char*)pkg_malloc( uri_str.len + 1))==0) {
00571                 LM_ERR("no more pkg mem\n");
00572                 return 0;
00573         }
00574 
00575         p = uri_str.s;
00576         *(p++)='s';
00577         *(p++)='i';
00578         *(p++)='p';
00579         *(p++)=':';
00580         if (pri->len) {
00581                 memcpy(p, pri->s, pri->len);
00582                 p += pri->len;
00583         }
00584         memcpy(p, uri->user.s+strip, uri->user.len-strip);
00585         p += uri->user.len-strip;
00586         if (uri->passwd.len) {
00587                 *(p++)=':';
00588                 memcpy(p, uri->passwd.s, uri->passwd.len);
00589                 p += uri->passwd.len;
00590         }
00591         *(p++)='@';
00592         memcpy(p, hostport->s, hostport->len);
00593         p += hostport->len;
00594         if (uri->params.len) {
00595                 *(p++)=';';
00596                 memcpy(p, uri->params.s, uri->params.len);
00597                 p += uri->params.len;
00598         }
00599         if (uri->headers.len) {
00600                 *(p++)='?';
00601                 memcpy(p, uri->headers.s, uri->headers.len);
00602                 p += uri->headers.len;
00603         }
00604         *p = 0;
00605 
00606         if (p-uri_str.s!=uri_str.len) {
00607                 LM_CRIT("difference between allocated(%d)"
00608                         " and written(%d)\n",uri_str.len,(int)(long)(p-uri_str.s));
00609                 return 0;
00610         }
00611         return &uri_str;
00612 }
00613 
00614 
00615 static int do_routing_0(struct sip_msg* msg, char* str1, char* str2)
00616 {
00617         return do_routing(msg, NULL);
00618 }
00619 
00620 static int do_routing_1(struct sip_msg* msg, char* str1, char* str2)
00621 {
00622         return do_routing(msg, (dr_group_t*)str1);
00623 }
00624 
00625 
00626 static int use_next_gw(struct sip_msg* msg)
00627 {
00628         struct usr_avp *avp;
00629         int_str val;
00630 
00631         /* search for the first RURI AVP containing a string */
00632         do {
00633                 avp = search_first_avp(ruri_avp.type, ruri_avp.name, &val, 0);
00634         }while (avp && (avp->flags&AVP_VAL_STR)==0 );
00635 
00636         if (!avp) return -1;
00637 
00638         if (rewrite_ruri(msg, val.s.s)==-1) {
00639                 LM_ERR("failed to rewite RURI\n");
00640                 return -1;
00641         }
00642         destroy_avp(avp);
00643         LM_DBG("new RURI set to <%.*s>\n", val.s.len,val.s.s);
00644 
00645         /* remove the old attrs */
00646         avp = NULL;
00647         do {
00648                 if (avp) destroy_avp(avp);
00649                 avp = search_first_avp(attrs_avp.type, attrs_avp.name, NULL, 0);
00650         }while (avp && (avp->flags&AVP_VAL_STR)==0 );
00651         if (avp) destroy_avp(avp);
00652 
00653         return 1;
00654 }
00655 
00656 
00657 static int do_routing(struct sip_msg* msg, dr_group_t *drg)
00658 {
00659         struct to_body  *from;
00660         struct sip_uri  uri;
00661         rt_info_t      *rt_info;
00662         int    grp_id;
00663         int    i, j, l, t;
00664         str    *ruri;
00665         int_str val;
00666         struct usr_avp *avp;
00667 #define DR_MAX_GWLIST   32
00668         static int local_gwlist[DR_MAX_GWLIST];
00669         int gwlist_size;
00670         int ret;
00671 
00672         ret = -1;
00673 
00674         if ( (*rdata)==0 || (*rdata)->pgw_l==0 ) {
00675                 LM_DBG("empty ruting table\n");
00676                 goto error1;
00677         }
00678 
00679         /* get the username from FROM_HDR */
00680         if (parse_from_header(msg)!=0) {
00681                 LM_ERR("unable to parse from hdr\n");
00682                 goto error1;
00683         }
00684         from = (struct to_body*)msg->from->parsed;
00685         /* parse uri */
00686         if (parse_uri( from->uri.s, from->uri.len, &uri)!=0) {
00687                 LM_ERR("unable to parse from uri\n");
00688                 goto error1;
00689         }
00690 
00691         /* get user's routing group */
00692         if(drg==NULL)
00693         {
00694                 grp_id = get_group_id( &uri );
00695                 if (grp_id<0) {
00696                         LM_ERR("failed to get group id\n");
00697                         goto error1;
00698                 }
00699         } else {
00700                 if(drg->type==0)
00701                         grp_id = (int)drg->u.grp_id;
00702                 else if(drg->type==1) {
00703                         grp_id = 0; /* call get avp here */
00704                         if((avp=search_first_avp( drg->u.avp_id.type,
00705                         drg->u.avp_id.name, &val, 0))==NULL||(avp->flags&AVP_VAL_STR)) {
00706                                 LM_ERR( "failed to get group id\n");
00707                                 goto error1;
00708                         }
00709                         grp_id = val.n;
00710                 } else
00711                         grp_id = 0; 
00712         }
00713         LM_DBG("using dr group %d\n",grp_id);
00714 
00715         /* get the number */
00716         ruri = GET_RURI(msg);
00717         /* parse ruri */
00718         if (parse_uri( ruri->s, ruri->len, &uri)!=0) {
00719                 LM_ERR("unable to parse RURI\n");
00720                 goto error1;
00721         }
00722 
00723         /* ref the data for reading */
00724 again:
00725         lock_get( ref_lock );
00726         /* if reload must be done, do un ugly busy waiting 
00727          * until reload is finished */
00728         if (*reload_flag) {
00729                 lock_release( ref_lock );
00730                 usleep(5);
00731                 goto again;
00732         }
00733         *data_refcnt = *data_refcnt + 1;
00734         lock_release( ref_lock );
00735 
00736         /* search a prefix */
00737         rt_info = get_prefix( (*rdata)->pt, &uri.user , (unsigned int)grp_id);
00738         if (rt_info==0) {
00739                 LM_DBG("no matching for prefix \"%.*s\"\n",
00740                         uri.user.len, uri.user.s);
00741                 /* try prefixless rules */
00742                 rt_info = check_rt( &(*rdata)->noprefix, (unsigned int)grp_id);
00743                 if (rt_info==0) {
00744                         LM_DBG("no prefixless matching for "
00745                                 "grp %d\n", grp_id);
00746                         goto error2;
00747                 }
00748         }
00749 
00750         if (rt_info->route_idx>0 && rt_info->route_idx<RT_NO) {
00751                 ret = run_top_route(main_rt.rlist[rt_info->route_idx], msg, 0);
00752                 if (ret<1) {
00753                         /* drop the action */
00754                         LM_DBG("script route %d drops routing "
00755                                 "by %d\n", rt_info->route_idx, ret);
00756                         goto error2;
00757                 }
00758                 ret = -1;
00759         }
00760 
00761         gwlist_size
00762                 = (rt_info->pgwa_len>DR_MAX_GWLIST)?DR_MAX_GWLIST:rt_info->pgwa_len;
00763         
00764         /* set gw order */
00765         if(sort_order>=1&&gwlist_size>1)
00766         {
00767                 j = 0;
00768                 t = 0;
00769                 while(j<gwlist_size)
00770                 {
00771                         /* identify the group: [j..i) */
00772                         for(i=j+1; i<gwlist_size; i++)
00773                                 if(rt_info->pgwl[j].grpid!=rt_info->pgwl[i].grpid)
00774                                         break;
00775                         if(i-j==1)
00776                         {
00777                                 local_gwlist[t++] = j;
00778                                 /*LM_DBG("selected gw[%d]=%d\n",
00779                                         j, local_gwlist[j]);*/
00780                         } else {
00781                                 if(i-j==2)
00782                                 {
00783                                         local_gwlist[t++]   = j + rand()%2;
00784                                         if(sort_order==1)
00785                                         {
00786                                                 local_gwlist[t++] = j + (local_gwlist[j]-j+1)%2;
00787                                                 /*LM_DBG("selected gw[%d]=%d"
00788                                                  *  " gw[%d]=%d\n", j, local_gwlist[j], j+1,
00789                                                  *  local_gwlist[j+1]);*/
00790                                         }
00791                                 } else {
00792                                         local_gwlist[t++]   = j + rand()%(i-j);
00793                                         if(sort_order==1)
00794                                         {
00795                                                 do{
00796                                                         local_gwlist[t] = j + rand()%(i-j);
00797                                                 }while(local_gwlist[t]==local_gwlist[t-1]);
00798                                                 t++;
00799 
00800                                                 /*
00801                                                 LM_DBG("selected gw[%d]=%d"
00802                                                         " gw[%d]=%d.\n",
00803                                                         j, local_gwlist[j], j+1, local_gwlist[j+1]); */
00804                                                 /* add the rest in this group */
00805                                                 for(l=j; l<i; l++)
00806                                                 {
00807                                                         if(l==local_gwlist[j] || l==local_gwlist[j+1])
00808                                                                 continue;
00809                                                         local_gwlist[t++] = l;
00810                                                         /* LM_DBG("selected gw[%d]=%d.\n",
00811                                                                 j+k, local_gwlist[t]); */
00812                                                 }
00813                                         }
00814                                 }
00815                         }
00816                         /* next group starts from i */
00817                         j=i;
00818                 }
00819         } else {
00820                 for(i=0; i<gwlist_size; i++)
00821                         local_gwlist[i] = i;
00822                 t = i;
00823         }
00824 
00825         /* do some cleanup first */
00826         destroy_avps( ruri_avp.type, ruri_avp.name, 1);
00827 
00828         /* push gwlist into avps in reverse order */
00829         for( j=t-1 ; j>=1 ; j-- ) {
00830                 /* build uri*/
00831                 ruri = build_ruri(&uri, rt_info->pgwl[local_gwlist[j]].pgw->strip,
00832                                 &rt_info->pgwl[local_gwlist[j]].pgw->pri,
00833                                 &rt_info->pgwl[local_gwlist[j]].pgw->ip);
00834                 if (ruri==0) {
00835                         LM_ERR("failed to build avp ruri\n");
00836                         goto error2;
00837                 }
00838                 LM_DBG("adding gw [%d] as avp \"%.*s\"\n",
00839                         local_gwlist[j], ruri->len, ruri->s);
00840                 /* add ruri avp */
00841                 val.s = *ruri;
00842                 if (add_avp( AVP_VAL_STR|(ruri_avp.type),ruri_avp.name, val)!=0 ) {
00843                         LM_ERR("failed to insert ruri avp\n");
00844                         pkg_free(ruri->s);
00845                         goto error2;
00846                 }
00847                 pkg_free(ruri->s);
00848                 /* add attrs avp */
00849                 val.s = rt_info->pgwl[local_gwlist[j]].pgw->attrs;
00850                 LM_DBG("setting attr [%.*s] as avp\n",val.s.len,val.s.s);
00851                 if (add_avp( AVP_VAL_STR|(attrs_avp.type),attrs_avp.name, val)!=0 ) {
00852                         LM_ERR("failed to insert attrs avp\n");
00853                         goto error2;
00854                 }
00855         }
00856 
00857         /* use first GW in RURI */
00858         ruri = build_ruri(&uri, rt_info->pgwl[local_gwlist[0]].pgw->strip,
00859                         &rt_info->pgwl[local_gwlist[0]].pgw->pri,
00860                         &rt_info->pgwl[local_gwlist[0]].pgw->ip);
00861 
00862         /* add attrs avp */
00863         val.s = rt_info->pgwl[local_gwlist[0]].pgw->attrs;
00864         LM_DBG("setting attr [%.*s] as for ruri\n",val.s.len,val.s.s);
00865         if (add_avp( AVP_VAL_STR|(attrs_avp.type),attrs_avp.name, val)!=0 ) {
00866                 LM_ERR("failed to insert attrs avp\n");
00867                 goto error2;
00868         }
00869 
00870         /* we are done reading -> unref the data */
00871         lock_get( ref_lock );
00872         *data_refcnt = *data_refcnt - 1;
00873         lock_release( ref_lock );
00874 
00875         /* what hev we get here?? */
00876         if (ruri==0) {
00877                 LM_ERR("failed to build ruri\n");
00878                 goto error1;
00879         }
00880         LM_DBG("setting the gw [%d] as ruri \"%.*s\"\n",
00881                         local_gwlist[0], ruri->len, ruri->s);
00882         if (msg->new_uri.s)
00883                 pkg_free(msg->new_uri.s);
00884         msg->new_uri = *ruri;
00885         msg->parsed_uri_ok = 0;
00886         ruri_mark_new();
00887 
00888         return 1;
00889 error2:
00890         /* we are done reading -> unref the data */
00891         lock_get( ref_lock );
00892         *data_refcnt = *data_refcnt - 1;
00893         lock_release( ref_lock );
00894 error1:
00895         return ret;
00896 }
00897 
00898 
00899 static int fixup_do_routing(void** param, int param_no)
00900 {
00901         char *s;
00902         dr_group_t *drg;
00903         pv_spec_t avp_spec;
00904         str r;
00905 
00906         s = (char*)*param;
00907 
00908         if (param_no==1)
00909         {
00910                 drg = (dr_group_t*)pkg_malloc(sizeof(dr_group_t));
00911                 if(drg==NULL)
00912                 {
00913                         LM_ERR( "no more memory\n");
00914                         return E_OUT_OF_MEM;
00915                 }
00916                 memset(drg, 0, sizeof(dr_group_t));
00917 
00918                 if ( s==NULL || s[0]==0 ) {
00919                         LM_CRIT("empty group id definition");
00920                         return E_CFG;
00921                 }
00922 
00923                 if (s[0]=='$') {
00924                         /* param is a PV (AVP only supported) */
00925                         r.s = s;
00926                         r.len = strlen(s);
00927                         if (pv_parse_spec( &r, &avp_spec)==0
00928                         || avp_spec.type!=PVT_AVP) {
00929                                 LM_ERR("malformed or non AVP %s AVP definition\n", s);
00930                                 return E_CFG;
00931                         }
00932 
00933                         if( pv_get_avp_name(0, &(avp_spec.pvp), &(drg->u.avp_id.name),
00934                         &(drg->u.avp_id.type) )!=0) {
00935                                 LM_ERR("[%s]- invalid AVP definition\n", s);
00936                                 return E_CFG;
00937                         }
00938                         drg->type = 1;
00939                         /* do not free the param as the AVP spec may point inside 
00940                            this string*/
00941                 } else {
00942                         while(s && *s) {
00943                                 if(*s<'0' || *s>'9') {
00944                                         LM_ERR( "bad number\n");
00945                                         return E_UNSPEC;
00946                                 }
00947                                 drg->u.grp_id = (drg->u.grp_id)*10+(*s-'0');
00948                                 s++;
00949                         }
00950                         pkg_free(*param);
00951                 }
00952                 *param = (void*)drg;
00953         }
00954 
00955         return 0;
00956 }
00957 
00958 
00959 static int fixup_from_gw( void** param, int param_no)
00960 {
00961         unsigned long type;
00962         int err;
00963 
00964         if (param_no == 1 || param_no == 2) {
00965                 type = str2s(*param, strlen(*param), &err);
00966                 if (err == 0) {
00967                         pkg_free(*param);
00968                         *param = (void *)type;
00969                         return 0;
00970                 } else {
00971                         LM_ERR( "bad number <%s>\n",
00972                                 (char *)(*param));
00973                         return E_CFG;
00974                 }
00975         }
00976         return 0;
00977 }
00978 
00979 static int strip_username(struct sip_msg* msg, int strip)
00980 {
00981         struct action act;
00982    struct run_act_ctx ra_ctx;
00983  
00984         act.type = STRIP_T;
00985         act.val[0].type = NUMBER_ST;
00986         act.val[0].u.number = strip;
00987         act.next = 0;
00988 
00989    init_run_actions_ctx(&ra_ctx);
00990    if (do_action(&ra_ctx, &act, msg) < 0)
00991         {
00992                 LM_ERR( "Error in do_action\n");
00993                 return -1;
00994         }
00995         return 0;
00996 }
00997 
00998 
00999 static int is_from_gw_0(struct sip_msg* msg, char* str, char* str2)
01000 {
01001         pgw_addr_t *pgwa = NULL;
01002 
01003         if(rdata==NULL || *rdata==NULL || msg==NULL)
01004                 return -1;
01005         
01006         pgwa = (*rdata)->pgw_addr_l;
01007         while(pgwa) {
01008                 if( (pgwa->port==0 || pgwa->port==msg->rcv.src_port) &&
01009                 ip_addr_cmp(&pgwa->ip, &msg->rcv.src_ip))
01010                         return 1;
01011                 pgwa = pgwa->next;
01012         }
01013         return -1;
01014 }
01015 
01016 
01017 static int is_from_gw_1(struct sip_msg* msg, char* str, char* str2)
01018 {
01019         pgw_addr_t *pgwa = NULL;
01020         int type = (int)(long)str;
01021 
01022         if(rdata==NULL || *rdata==NULL || msg==NULL)
01023                 return -1;
01024         
01025         pgwa = (*rdata)->pgw_addr_l;
01026         while(pgwa) {
01027                 if( type==pgwa->type && 
01028                 (pgwa->port==0 || pgwa->port==msg->rcv.src_port) &&
01029                 ip_addr_cmp(&pgwa->ip, &msg->rcv.src_ip) )
01030                         return 1;
01031                 pgwa = pgwa->next;
01032         }
01033         return -1;
01034 }
01035 
01036 static int is_from_gw_2(struct sip_msg* msg, char* str1, char* str2)
01037 {
01038         pgw_addr_t *pgwa = NULL;
01039         int type = (int)(long)str1;
01040         int flags = (int)(long)str2;
01041 
01042         if(rdata==NULL || *rdata==NULL || msg==NULL)
01043                 return -1;
01044         
01045         pgwa = (*rdata)->pgw_addr_l;
01046         while(pgwa) {
01047                 if( type==pgwa->type &&
01048                 (pgwa->port==0 || pgwa->port==msg->rcv.src_port) &&
01049                 ip_addr_cmp(&pgwa->ip, &msg->rcv.src_ip) ) {
01050                         if (flags!=0 && pgwa->strip>0)
01051                                 strip_username(msg, pgwa->strip);
01052                         return 1;
01053                 }
01054                 pgwa = pgwa->next;
01055         }
01056         return -1;
01057 }
01058 
01059 
01060 static int goes_to_gw_1(struct sip_msg* msg, char* _type, char* _f2)
01061 {
01062         pgw_addr_t *pgwa = NULL;
01063         struct sip_uri puri;
01064         struct ip_addr *ip;
01065         str *uri;
01066         int type;
01067 
01068         if(rdata==NULL || *rdata==NULL || msg==NULL)
01069                 return -1;
01070 
01071         uri = GET_NEXT_HOP(msg);
01072         type = (int)(long)_type;
01073 
01074         if (parse_uri(uri->s, uri->len, &puri)<0){
01075                 LM_ERR("bad uri <%.*s>\n", uri->len, uri->s);
01076                 return -1;
01077         }
01078 
01079         if ( ((ip=str2ip(&puri.host))!=0)
01080 #ifdef USE_IPV6
01081         || ((ip=str2ip6(&puri.host))!=0)
01082 #endif
01083         ){
01084                 pgwa = (*rdata)->pgw_addr_l;
01085                 while(pgwa) {
01086                         if( (type<0 || type==pgwa->type) && ip_addr_cmp(&pgwa->ip, ip))
01087                                 return 1;
01088                         pgwa = pgwa->next;
01089                 }
01090         }
01091 
01092         return -1;
01093 }
01094 
01095 
01096 static int goes_to_gw_0(struct sip_msg* msg, char* _type, char* _f2)
01097 {
01098         return goes_to_gw_1(msg, (char*)(long)-1, _f2);
01099 }
01100