modules_k/pdt/pdt.c

00001 
00034 /*
00035  * Prefix-Domains Translation - ser module
00036  * Ramona Modroiu
00037  */
00038 
00039 #include <stdio.h>
00040 #include <unistd.h>
00041 #include <stdlib.h>
00042 
00043 #include "../../lib/srdb1/db_op.h"
00044 #include "../../sr_module.h"
00045 #include "../../lib/srdb1/db.h"
00046 #include "../../mem/shm_mem.h"
00047 #include "../../mem/mem.h"
00048 #include "../../dprint.h"
00049 #include "../../parser/parse_uri.h"
00050 #include "../../timer.h"
00051 #include "../../ut.h"
00052 #include "../../locking.h"
00053 #include "../../action.h"
00054 #include "../../mod_fix.h"
00055 #include "../../parser/parse_from.h"
00056 #include "../../rpc.h"
00057 #include "../../rpc_lookup.h"
00058 
00059 #include "pdtree.h"
00060 
00061 MODULE_VERSION
00062 
00063 
00064 #define NR_KEYS                 3
00065 
00066 int pdt_fetch_rows = 1000;
00067 
00069 pdt_tree_t **_ptree = NULL; 
00070 
00072 static db1_con_t *db_con = NULL;
00073 static db_func_t pdt_dbf;
00074 
00075 
00077 static str db_url = str_init(DEFAULT_DB_URL);
00078 static str db_table = str_init("pdt");
00079 static str sdomain_column = str_init("sdomain");
00080 static str prefix_column  = str_init("prefix");
00081 static str domain_column  = str_init("domain");
00082 static int pdt_check_domain  = 1;
00083 
00085 str pdt_prefix = {"", 0};
00086 /* List of allowed chars for a prefix*/
00087 str pdt_char_list = {"0123456789", 10};
00088 
00089 /* lock, ref counter and flag used for reloading the date */
00090 static gen_lock_t *pdt_lock = 0;
00091 static volatile int pdt_tree_refcnt = 0;
00092 static volatile int pdt_reload_flag = 0;
00093 
00094 static int  w_prefix2domain(struct sip_msg* msg, char* str1, char* str2);
00095 static int  w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2);
00096 static int  w_prefix2domain_2(struct sip_msg* msg, char* mode, char* sd_en);
00097 static int  mod_init(void);
00098 static void mod_destroy(void);
00099 static int  child_init(int rank);
00100 static int  pd_translate(sip_msg_t *msg, str *sdomain, int rmode, int fmode);
00101 
00102 static int w_pd_translate(struct sip_msg* msg, char* str1, char* str2);
00103 static int fixup_translate(void** param, int param_no);
00104 
00105 static int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode);
00106 static int pdt_init_rpc(void);
00107 
00108 static cmd_export_t cmds[]={
00109         {"prefix2domain", (cmd_function)w_prefix2domain,   0, 0,
00110                 0, REQUEST_ROUTE|FAILURE_ROUTE},
00111         {"prefix2domain", (cmd_function)w_prefix2domain_1, 1, fixup_igp_null,
00112                 0, REQUEST_ROUTE|FAILURE_ROUTE},
00113         {"prefix2domain", (cmd_function)w_prefix2domain_2, 2, fixup_igp_igp,
00114                 0, REQUEST_ROUTE|FAILURE_ROUTE},
00115         {"pd_translate", (cmd_function)w_pd_translate,     2, fixup_translate,
00116                 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00117         {0, 0, 0, 0, 0, 0}
00118 };
00119 
00120 static param_export_t params[]={
00121         {"db_url",         STR_PARAM, &db_url.s},
00122         {"db_table",       STR_PARAM, &db_table.s},
00123         {"sdomain_column", STR_PARAM, &sdomain_column.s},
00124         {"prefix_column",  STR_PARAM, &prefix_column.s},
00125         {"domain_column",  STR_PARAM, &domain_column.s},
00126         {"prefix",         STR_PARAM, &pdt_prefix.s},
00127         {"char_list",      STR_PARAM, &pdt_char_list.s},
00128         {"fetch_rows",     INT_PARAM, &pdt_fetch_rows},
00129         {"check_domain",   INT_PARAM, &pdt_check_domain},
00130         {0, 0, 0}
00131 };
00132 
00133 
00134 struct module_exports exports = {
00135         "pdt",
00136         DEFAULT_DLFLAGS, /* dlopen flags */
00137         cmds,
00138         params,
00139         0,
00140         0,              /* exported MI functions */
00141         0,              /* exported pseudo-variables */
00142         0,              /* extra processes */
00143         mod_init,       /* module initialization function */
00144         0,              /* response function */
00145         mod_destroy,    /* destroy function */
00146         child_init      /* per child init function */
00147 };
00148 
00149 
00150 
00154 static int mod_init(void)
00155 {
00156 
00157 #ifndef PDT_NO_MI
00158         if(pdt_init_mi(exports.name)<0)
00159         {
00160                 LM_ERR("cannot register MI commands\n");
00161                 return -1;
00162         }
00163 #endif
00164 
00165         if(pdt_init_rpc()<0)
00166         {
00167                 LM_ERR("failed to register RPC commands\n");
00168                 return -1;
00169         }
00170 
00171         db_url.len = strlen(db_url.s);
00172         db_table.len = strlen(db_table.s);
00173         sdomain_column.len = strlen(sdomain_column.s);
00174         prefix_column.len = strlen(prefix_column.s);
00175         domain_column.len = strlen(domain_column.s);
00176         pdt_prefix.len = strlen(pdt_prefix.s);
00177 
00178         if(pdt_fetch_rows<=0)
00179                 pdt_fetch_rows = 1000;
00180 
00181         pdt_char_list.len = strlen(pdt_char_list.s);
00182         if(pdt_char_list.len<=0)
00183         {
00184                 LM_ERR("invalid pdt char list\n");
00185                 return -1;
00186         }
00187         LM_INFO("pdt_char_list=%s \n",pdt_char_list.s);
00188 
00189         /* binding to mysql module */
00190         if(db_bind_mod(&db_url, &pdt_dbf))
00191         {
00192                 LM_ERR("database module not found\n");
00193                 return -1;
00194         }
00195 
00196         if (!DB_CAPABILITY(pdt_dbf, DB_CAP_ALL))
00197         {
00198                 LM_ERR("database module does not "
00199                     "implement all functions needed by the module\n");
00200                 return -1;
00201         }
00202 
00203         /* open a connection with the database */
00204         db_con = pdt_dbf.init(&db_url);
00205         if(db_con==NULL)
00206         {
00207                 LM_ERR("failed to connect to the database\n");        
00208                 return -1;
00209         }
00210         
00211         if (pdt_dbf.use_table(db_con, &db_table) < 0)
00212         {
00213                 LM_ERR("failed to use_table\n");
00214                 goto error1;
00215         }
00216         LM_DBG("database connection opened successfully\n");
00217         
00218         if ( (pdt_lock=lock_alloc())==0) {
00219                 LM_CRIT("failed to alloc lock\n");
00220                 goto error1;
00221         }
00222         if (lock_init(pdt_lock)==0 ) {
00223                 LM_CRIT("failed to init lock\n");
00224                 goto error1;
00225         }
00226         
00227         /* tree pointer in shm */
00228         _ptree = (pdt_tree_t**)shm_malloc( sizeof(pdt_tree_t*) );
00229         if (_ptree==0) {
00230                 LM_ERR("out of shm mem for pdtree\n");
00231                 goto error1;
00232         }
00233         *_ptree=0;
00234 
00235         /* loading all information from database */
00236         if(pdt_load_db()!=0)
00237         {
00238                 LM_ERR("cannot load info from database\n");     
00239                 goto error1;
00240         }
00241                 
00242         pdt_dbf.close(db_con);
00243         db_con = 0;
00244 
00245 #if 0
00246         pdt_print_tree(*_ptree);
00247 #endif
00248 
00249         /* success code */
00250         return 0;
00251 
00252 error1:
00253         if (pdt_lock)
00254         {
00255                 lock_destroy( pdt_lock );
00256                 lock_dealloc( pdt_lock );
00257                 pdt_lock = 0;
00258         }
00259         if(_ptree!=0)
00260         {
00261                 shm_free(_ptree);
00262                 _ptree = 0;
00263         }
00264 
00265         if(db_con!=NULL)
00266         {
00267                 pdt_dbf.close(db_con);
00268                 db_con = 0;
00269         }
00270         return -1;
00271 }
00272 
00273 /* each child get a new connection to the database */
00274 static int child_init(int rank)
00275 {
00276         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00277                 return 0; /* do nothing for the main process */
00278 
00279         if(pdt_init_db()<0)
00280         {
00281                 LM_ERR("cannot initialize database connection\n");
00282                 return -1;
00283         }
00284         LM_DBG("#%d: database connection opened successfully\n", rank);
00285         return 0;
00286 }
00287 
00288 
00289 static void mod_destroy(void)
00290 {
00291         LM_DBG("cleaning up\n");
00292         if (_ptree!=NULL)
00293         {
00294                 if (*_ptree!=NULL)
00295                         pdt_free_tree(*_ptree);
00296                 shm_free(_ptree);
00297         }
00298         if (db_con!=NULL && pdt_dbf.close!=NULL)
00299                 pdt_dbf.close(db_con);
00300                 /* destroy lock */
00301         if (pdt_lock)
00302         {
00303                 lock_destroy( pdt_lock );
00304                 lock_dealloc( pdt_lock );
00305                 pdt_lock = 0;
00306         }
00307 
00308 }
00309 
00310 
00311 static int w_prefix2domain(struct sip_msg* msg, char* str1, char* str2)
00312 {
00313         str sdall={"*",1};
00314         return pd_translate(msg, &sdall, 0, 0);
00315 }
00316 
00317 static int w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2)
00318 {
00319         str sdall={"*",1};
00320         int md;
00321 
00322         if(fixup_get_ivalue(msg, (gparam_p)mode, &md)!=0)
00323         {
00324                 LM_ERR("no mode value\n");
00325                 return -1;
00326         }
00327 
00328         if(md!=1 && md!=2)
00329                 md = 0;
00330 
00331         return pd_translate(msg, &sdall, md, 0);
00332 }
00333 
00334 static int w_prefix2domain_2(struct sip_msg* msg, char* mode, char* sdm)
00335 {
00336         int m, s, f;
00337         str sdomain={"*",1};
00338         sip_uri_t *furi;
00339 
00340         if(fixup_get_ivalue(msg, (gparam_p)mode, &m)!=0)
00341         {
00342                 LM_ERR("no mode value\n");
00343                 return -1;
00344         }
00345 
00346         if(m!=1 && m!=2)
00347                 m = 0;
00348 
00349         if(fixup_get_ivalue(msg, (gparam_p)sdm, &s)!=0)
00350         {
00351                 LM_ERR("no multi-domain mode value\n");
00352                 return -1;
00353         }
00354 
00355         if(s!=1 && s!=2)
00356                 s = 0;
00357 
00358         f = 0;
00359         if(s==1 || s==2)
00360         {
00361                 /* take the domain from  FROM uri as sdomain */
00362                 if((furi = parse_from_uri(msg))==NULL)
00363                 {
00364                         LM_ERR("cannot parse FROM header URI\n");
00365                         return -1;
00366                 }
00367                 sdomain = furi->host;
00368                 if(s==2)
00369                         f = 1;
00370         }
00371         return pd_translate(msg, &sdomain, m, f);
00372 }
00373 
00383 static int pd_translate(sip_msg_t *msg, str *sdomain, int rmode, int fmode)
00384 {
00385         str *d, p;
00386         str sdall={"*",1};
00387         int plen;
00388         
00389         if(msg==NULL)
00390         {
00391                 LM_ERR("received null msg\n");
00392                 return -1;
00393         }
00394         
00395         if(parse_sip_msg_uri(msg)<0)
00396         {
00397                 LM_ERR("failed to parse the R-URI\n");
00398                 return -1;
00399         }
00400 
00401     /* if the user part begin with the prefix, extract the code*/
00402         if (msg->parsed_uri.user.len<=0)
00403         {
00404                 LM_DBG("user part of the message is empty\n");
00405                 return -1;
00406         }   
00407     
00408         if(pdt_prefix.len>0)
00409         {
00410                 if (msg->parsed_uri.user.len<=pdt_prefix.len)
00411                 {
00412                         LM_DBG("user part is less than prefix parameter\n");
00413                         return -1;
00414                 }   
00415                 if(strncasecmp(pdt_prefix.s, msg->parsed_uri.user.s,
00416                                         pdt_prefix.len)!=0)
00417                 {
00418                         LM_DBG("prefix parameter did not matched\n");
00419                         return -1;
00420                 }
00421         }   
00422         
00423         p.s   = msg->parsed_uri.user.s + pdt_prefix.len;
00424         p.len = msg->parsed_uri.user.len - pdt_prefix.len;
00425 
00426 again:
00427         lock_get( pdt_lock );
00428         if (pdt_reload_flag) {
00429                 lock_release( pdt_lock );
00430                 sleep_us(5);
00431                 goto again;
00432         }
00433         pdt_tree_refcnt++;
00434         lock_release( pdt_lock );
00435 
00436 
00437         if((d=pdt_get_domain(*_ptree, sdomain, &p, &plen))==NULL)
00438         {
00439                 plen = 0;
00440                 if((fmode==0) || (d=pdt_get_domain(*_ptree, &sdall, &p, &plen))==NULL)
00441                 {
00442                         LM_INFO("no prefix PDT prefix matched [%.*s]\n", p.len, p.s);
00443                         goto error;
00444                 }
00445         }
00446 
00447         
00448         /* update the new uri */
00449         if(update_new_uri(msg, plen, d, rmode)<0)
00450         {
00451                 LM_ERR("new_uri cannot be updated\n");
00452                 goto error;
00453         }
00454 
00455         lock_get( pdt_lock );
00456         pdt_tree_refcnt--;
00457         lock_release( pdt_lock );
00458         return 1;
00459 
00460 error:
00461         lock_get( pdt_lock );
00462         pdt_tree_refcnt--;
00463         lock_release( pdt_lock );
00464         return -1;
00465 }
00466 
00470 static int fixup_translate(void** param, int param_no)
00471 {
00472         if(param_no==1)
00473                 return fixup_spve_null(param, 1);
00474         if(param_no==2)
00475                 return fixup_igp_null(param, 1);
00476         return 0;
00477 }
00478 
00482 static int w_pd_translate(sip_msg_t* msg, char* sdomain, char* mode)
00483 {
00484         int md;
00485         str sd;
00486 
00487         if(fixup_get_svalue(msg, (gparam_p)sdomain, &sd)!=0)
00488         {
00489                 LM_ERR("no source domain value\n");
00490                 return -1;
00491         }
00492 
00493 
00494         if(fixup_get_ivalue(msg, (gparam_p)mode, &md)!=0)
00495         {
00496                 LM_ERR("no multi-domain mode value\n");
00497                 return -1;
00498         }
00499 
00500         if(md!=1 && md!=2)
00501                 md = 0;
00502 
00503         return pd_translate(msg, &sd, md, 0);
00504 }
00505 
00509 static int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode)
00510 {
00511         struct action act;
00512         struct run_act_ctx ra_ctx;
00513         if(msg==NULL || d==NULL)
00514         {
00515                 LM_ERR("bad parameters\n");
00516                 return -1;
00517         }
00518         
00519         if(mode==0 || (mode==1 && pdt_prefix.len>0))
00520         {
00521                 memset(&act, '\0', sizeof(act));
00522                 act.type = STRIP_T;
00523                 act.val[0].type = NUMBER_ST;
00524                 if(mode==0)
00525                         act.val[0].u.number = plen + pdt_prefix.len;
00526                 else
00527                         act.val[0].u.number = pdt_prefix.len;
00528 
00529                 init_run_actions_ctx(&ra_ctx);
00530                 if (do_action(&ra_ctx, &act, msg) < 0)
00531                 {
00532                         LM_ERR("failed to remove prefix parameter\n");
00533                         return -1;
00534                 }
00535         }
00536         
00537         memset(&act, '\0', sizeof(act));
00538         act.type = SET_HOSTALL_T;
00539         act.val[0].type = STRING_ST;
00540         act.val[0].u.string = d->s;
00541         init_run_actions_ctx(&ra_ctx);
00542         if (do_action(&ra_ctx, &act, msg) < 0)
00543         {
00544                 LM_ERR("failed to change domain\n");
00545                 return -1;
00546         }
00547 
00548         LM_DBG("len=%d uri=%.*s\n", msg->new_uri.len, 
00549                         msg->new_uri.len, msg->new_uri.s);
00550         
00551         return 0;
00552 }
00553 
00554 int pdt_init_db(void)
00555 {
00556         /* db handler initialization */
00557         db_con = pdt_dbf.init(&db_url);
00558         if(db_con==NULL)
00559         {
00560                 LM_ERR("failed to connect to database\n");
00561                 return -1;
00562         }
00563 
00564         if (pdt_dbf.use_table(db_con, &db_table) < 0)
00565         {
00566                 LM_ERR("use_table failed\n");
00567                 return -1;
00568         }
00569         return 0;
00570 }
00571 
00572 int pdt_load_db(void)
00573 {
00574         db_key_t db_cols[3] = {&sdomain_column, &prefix_column, &domain_column};
00575         str p, d, sdomain;
00576         db1_res_t* db_res = NULL;
00577         int i, ret;
00578         pdt_tree_t *_ptree_new = NULL; 
00579         pdt_tree_t *old_tree = NULL; 
00580 
00581         if(db_con==NULL)
00582         {
00583                 LM_ERR("no db connection\n");
00584                 return -1;
00585         }
00586                 
00587         if (pdt_dbf.use_table(db_con, &db_table) < 0)
00588         {
00589                 LM_ERR("failed to use_table\n");
00590                 return -1;
00591         }
00592 
00593         if (DB_CAPABILITY(pdt_dbf, DB_CAP_FETCH)) {
00594                 if(pdt_dbf.query(db_con,0,0,0,db_cols,0,3,&sdomain_column,0) < 0)
00595                 {
00596                         LM_ERR("Error while querying db\n");
00597                         return -1;
00598                 }
00599                 if(pdt_dbf.fetch_result(db_con, &db_res, pdt_fetch_rows)<0)
00600                 {
00601                         LM_ERR("Error while fetching result\n");
00602                         if (db_res)
00603                                 pdt_dbf.free_result(db_con, db_res);
00604                         goto error;
00605                 } else {
00606                         if(RES_ROW_N(db_res)==0)
00607                         {
00608                                 return 0;
00609                         }
00610                 }
00611         } else {
00612                 if((ret=pdt_dbf.query(db_con, NULL, NULL, NULL, db_cols,
00613                                 0, 3, &sdomain_column, &db_res))!=0
00614                         || RES_ROW_N(db_res)<=0 )
00615                 {
00616                         pdt_dbf.free_result(db_con, db_res);
00617                         if( ret==0)
00618                         {
00619                                 return 0;
00620                         } else {
00621                                 goto error;
00622                         }
00623                 }
00624         }
00625 
00626         do {
00627                 for(i=0; i<RES_ROW_N(db_res); i++)
00628                 {
00629                         /* check for NULL values ?!?! */
00630                         sdomain.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
00631                         sdomain.len = strlen(sdomain.s);
00632 
00633                         p.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val);
00634                         p.len = strlen(p.s);
00635                         
00636                         d.s = (char*)(RES_ROWS(db_res)[i].values[2].val.string_val);
00637                         d.len = strlen(d.s);
00638 
00639                         if(p.s==NULL || d.s==NULL || sdomain.s==NULL ||
00640                                         p.len<=0 || d.len<=0 || sdomain.len<=0)
00641                         {
00642                                 LM_ERR("Error - bad values in db\n");
00643                                 continue;
00644                         }
00645                 
00646                         if(pdt_check_domain!=0 && _ptree_new!=NULL
00647                                         && pdt_check_pd(_ptree_new, &sdomain, &p, &d)==1)
00648                         {
00649                                 LM_ERR("sdomain [%.*s]: prefix [%.*s] or domain <%.*s> "
00650                                         "duplicated\n", sdomain.len, sdomain.s, p.len, p.s,
00651                                         d.len, d.s);
00652                                 continue;
00653                         }
00654 
00655                         if(pdt_add_to_tree(&_ptree_new, &sdomain, &p, &d)<0)
00656                         {
00657                                 LM_ERR("Error adding info to tree\n");
00658                                 goto error;
00659                         }
00660                 }
00661                 if (DB_CAPABILITY(pdt_dbf, DB_CAP_FETCH)) {
00662                         if(pdt_dbf.fetch_result(db_con, &db_res, pdt_fetch_rows)<0) {
00663                                 LM_ERR("Error while fetching!\n");
00664                                 if (db_res)
00665                                         pdt_dbf.free_result(db_con, db_res);
00666                                 goto error;
00667                         }
00668                 } else {
00669                         break;
00670                 }
00671         }  while(RES_ROW_N(db_res)>0);
00672         pdt_dbf.free_result(db_con, db_res);
00673 
00674 
00675         /* block all readers */
00676         lock_get( pdt_lock );
00677         pdt_reload_flag = 1;
00678         lock_release( pdt_lock );
00679 
00680         while (pdt_tree_refcnt) {
00681                 sleep_us(10);
00682         }
00683 
00684         old_tree = *_ptree;
00685         *_ptree = _ptree_new;
00686 
00687         pdt_reload_flag = 0;
00688 
00689         /* free old data */
00690         if (old_tree!=NULL)
00691                 pdt_free_tree(old_tree);
00692 
00693         return 0;
00694 
00695 error:
00696         pdt_dbf.free_result(db_con, db_res);
00697         if (_ptree_new!=NULL)
00698                 pdt_free_tree(_ptree_new);
00699         return -1;
00700 }
00701 
00702 
00703 /* return the pointer to char list */
00704 str* pdt_get_char_list(void)
00705 {
00706         return &pdt_char_list;
00707 }
00708 
00709 /* return head of pdt trees */
00710 pdt_tree_t **pdt_get_ptree(void)
00711 {
00712         return _ptree;
00713 }
00714 
00715 
00716 /*** RPC commands implementation ***/
00717 
00718 static const char* pdt_rpc_reload_doc[2] = {
00719         "Reload PDT database records",
00720         0
00721 };
00722 
00723 
00724 /*
00725  * RPC command to reload pdt db records
00726  */
00727 static void pdt_rpc_reload(rpc_t* rpc, void* ctx)
00728 {
00729         if(pdt_load_db()<0) {
00730                 LM_ERR("cannot re-load pdt records from database\n");   
00731                 rpc->fault(ctx, 500, "Reload Failed");
00732                 return;
00733         }
00734         return;
00735 }
00736 
00737 
00738 rpc_export_t pdt_rpc_cmds[] = {
00739         {"pdt.reload", pdt_rpc_reload,
00740                 pdt_rpc_reload_doc, 0},
00741         {0, 0, 0, 0}
00742 };
00743 
00744 
00748 static int pdt_init_rpc(void)
00749 {
00750         if (rpc_register_array(pdt_rpc_cmds)!=0)
00751         {
00752                 LM_ERR("failed to register RPC commands\n");
00753                 return -1;
00754         }
00755         return 0;
00756 }