00001
00034
00035
00036
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
00087 str pdt_char_list = {"0123456789", 10};
00088
00089
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,
00137 cmds,
00138 params,
00139 0,
00140 0,
00141 0,
00142 0,
00143 mod_init,
00144 0,
00145 mod_destroy,
00146 child_init
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
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
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
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
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
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
00274 static int child_init(int rank)
00275 {
00276 if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00277 return 0;
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
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
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
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
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
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
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
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
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
00704 str* pdt_get_char_list(void)
00705 {
00706 return &pdt_char_list;
00707 }
00708
00709
00710 pdt_tree_t **pdt_get_ptree(void)
00711 {
00712 return _ptree;
00713 }
00714
00715
00716
00717
00718 static const char* pdt_rpc_reload_doc[2] = {
00719 "Reload PDT database records",
00720 0
00721 };
00722
00723
00724
00725
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 }