00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdlib.h>
00029 #include <string.h>
00030
00031 #include "../../dprint.h"
00032 #include "../../ut.h"
00033 #include "../../db/db.h"
00034 #include "../../re.h"
00035 #include "dp_db.h"
00036 #include "dialplan.h"
00037
00038 str dp_db_url = {DEFAULT_RODB_URL, DEFAULT_RODB_URL_LEN};
00039 str dp_table_name = str_init(DP_TABLE_NAME);
00040 str dpid_column = str_init(DPID_COL);
00041 str pr_column = str_init(PR_COL);
00042 str match_op_column = str_init(MATCH_OP_COL);
00043 str match_exp_column= str_init(MATCH_EXP_COL);
00044 str match_len_column= str_init(MATCH_LEN_COL);
00045 str subst_exp_column= str_init(SUBST_EXP_COL);
00046 str repl_exp_column = str_init(REPL_EXP_COL);
00047 str attrs_column = str_init(ATTRS_COL);
00048
00049 extern int dp_fetch_rows;
00050
00051 static db_con_t* dp_db_handle = 0;
00052 static db_func_t dp_dbf;
00053
00054 #define GET_STR_VALUE(_res, _values, _index)\
00055 do{\
00056 (_res).s = VAL_STR((_values)+ (_index)).s;\
00057 (_res).len = strlen(VAL_STR((_values)+ (_index)).s);\
00058 }while(0);
00059
00060 void destroy_rule(dpl_node_t * rule);
00061 void destroy_hash(int);
00062
00063 dpl_node_t * build_rule(db_val_t * values);
00064 int add_rule2hash(dpl_node_t *, int);
00065
00066 void list_rule(dpl_node_t * );
00067 void list_hash(int h_index);
00068
00069
00070 dpl_id_p* rules_hash = NULL;
00071 int * crt_idx, *next_idx;
00072
00073
00074
00075 int init_db_data(void)
00076 {
00077 if(dp_table_name.s == 0){
00078 LM_ERR("invalid database table name\n");
00079 return -1;
00080 }
00081
00082
00083 if (db_bind_mod(&dp_db_url, &dp_dbf) < 0){
00084 LM_ERR("unable to bind to a database driver\n");
00085 return -1;
00086 }
00087
00088 if(dp_connect_db() !=0)
00089 return -1;
00090
00091 if(db_check_table_version(&dp_dbf, dp_db_handle, &dp_table_name,
00092 DP_TABLE_VERSION) < 0) {
00093 LM_ERR("error during table version check.\n");
00094 goto error;
00095 }
00096
00097 if(dp_load_db() != 0){
00098 LM_ERR("failed to load database data\n");
00099 goto error;
00100 }
00101
00102 dp_disconnect_db();
00103
00104 return 0;
00105 error:
00106
00107 dp_disconnect_db();
00108 return -1;
00109 }
00110
00111
00112 int dp_connect_db(void)
00113 {
00114 if(dp_db_handle){
00115 LM_CRIT("BUG: connection to DB already open\n");
00116 return -1;
00117 }
00118
00119 if ((dp_db_handle = dp_dbf.init(&dp_db_url)) == 0){
00120 LM_ERR("unable to connect to the database\n");
00121 return -1;
00122 }
00123
00124 return 0;
00125 }
00126
00127
00128 void dp_disconnect_db(void)
00129 {
00130 if(dp_db_handle){
00131 dp_dbf.close(dp_db_handle);
00132 dp_db_handle = 0;
00133 }
00134 }
00135
00136
00137 int init_data(void)
00138 {
00139 int *p;
00140
00141 rules_hash = (dpl_id_p *)shm_malloc(2*sizeof(dpl_id_p));
00142 if(!rules_hash) {
00143 LM_ERR("out of shm memory\n");
00144 return -1;
00145 }
00146 rules_hash[0] = rules_hash[1] = 0;
00147
00148 p = (int *)shm_malloc(2*sizeof(int));
00149 if(!p){
00150 LM_ERR("out of shm memory\n");
00151 return -1;
00152 }
00153 crt_idx = p;
00154 next_idx = p+1;
00155 *crt_idx = *next_idx = 0;
00156
00157 LM_DBG("trying to initialize data from db\n");
00158 if(init_db_data() != 0)
00159 return -1;
00160
00161 return 0;
00162 }
00163
00164
00165 void destroy_data(void)
00166 {
00167 if(rules_hash){
00168 destroy_hash(0);
00169 destroy_hash(1);
00170 shm_free(rules_hash);
00171 rules_hash = 0;
00172 }
00173
00174 if(crt_idx)
00175 shm_free(crt_idx);
00176 }
00177
00178
00179
00180 int dp_load_db(void)
00181 {
00182 int i, nr_rows;
00183 db_res_t * res = 0;
00184 db_val_t * values;
00185 db_row_t * rows;
00186 db_key_t query_cols[DP_TABLE_COL_NO] = {
00187 &dpid_column, &pr_column,
00188 &match_op_column, &match_exp_column, &match_len_column,
00189 &subst_exp_column, &repl_exp_column, &attrs_column };
00190
00191 db_key_t order = &pr_column;
00192
00193 dpl_node_t *rule;
00194
00195 LM_DBG("init\n");
00196 if( (*crt_idx) != (*next_idx)){
00197 LM_WARN("a load command already generated, aborting reload...\n");
00198 return 0;
00199 }
00200
00201 if (dp_dbf.use_table(dp_db_handle, &dp_table_name) < 0){
00202 LM_ERR("error in use_table\n");
00203 return -1;
00204 }
00205
00206 if (DB_CAPABILITY(dp_dbf, DB_CAP_FETCH)) {
00207 if(dp_dbf.query(dp_db_handle,0,0,0,query_cols, 0,
00208 DP_TABLE_COL_NO, order, 0) < 0){
00209 LM_ERR("failed to query database!\n");
00210 return -1;
00211 }
00212 if(dp_dbf.fetch_result(dp_db_handle, &res, dp_fetch_rows)<0) {
00213 LM_ERR("failed to fetch\n");
00214 if (res)
00215 dp_dbf.free_result(dp_db_handle, res);
00216 return -1;
00217 }
00218 } else {
00219
00220 if(dp_dbf.query(dp_db_handle,0,0,0,query_cols, 0,
00221 DP_TABLE_COL_NO, order, &res) < 0){
00222 LM_ERR("failed to query database\n");
00223 return -1;
00224 }
00225 }
00226
00227 nr_rows = RES_ROW_N(res);
00228
00229 *next_idx = ((*crt_idx) == 0)? 1:0;
00230 destroy_hash(*next_idx);
00231
00232 if(nr_rows == 0){
00233 LM_WARN("no data in the db\n");
00234 goto end;
00235 }
00236
00237 do {
00238 for(i=0; i<RES_ROW_N(res); i++){
00239 rows = RES_ROWS(res);
00240
00241 values = ROW_VALUES(rows+i);
00242
00243 if((rule = build_rule(values)) ==0 )
00244 goto err2;
00245
00246 if(add_rule2hash(rule , *next_idx) != 0)
00247 goto err2;
00248
00249 }
00250 if (DB_CAPABILITY(dp_dbf, DB_CAP_FETCH)) {
00251 if(dp_dbf.fetch_result(dp_db_handle, &res, dp_fetch_rows)<0) {
00252 LM_ERR("failure while fetching!\n");
00253 if (res)
00254 dp_dbf.free_result(dp_db_handle, res);
00255 return -1;
00256 }
00257 } else {
00258 break;
00259 }
00260 } while(RES_ROW_N(res)>0);
00261
00262
00263 end:
00264
00265 *crt_idx = *next_idx;
00266 list_hash(*crt_idx);
00267 dp_dbf.free_result(dp_db_handle, res);
00268 return 0;
00269
00270 err2:
00271 if(rule) destroy_rule(rule);
00272 destroy_hash(*next_idx);
00273 dp_dbf.free_result(dp_db_handle, res);
00274 *next_idx = *crt_idx;
00275 return -1;
00276 }
00277
00278
00279 int str_to_shm(str src, str * dest)
00280 {
00281 if(src.len ==0 || src.s ==0)
00282 return 0;
00283
00284 dest->s = (char*)shm_malloc((src.len+1) * sizeof(char));
00285 if(!dest->s){
00286 LM_ERR("out of shm memory\n");
00287 return -1;
00288 }
00289
00290 memcpy(dest->s, src.s, src.len);
00291 dest->s[src.len] = '\0';
00292 dest->len = src.len;
00293
00294 return 0;
00295 }
00296
00297
00298
00299 static pcre *reg_ex_comp(const char *pattern, int *cap_cnt)
00300 {
00301 pcre *re, *result;
00302 const char *error;
00303 int rc, size, err_offset;
00304
00305 re = pcre_compile(pattern, 0, &error, &err_offset, NULL);
00306 if (re == NULL) {
00307 LM_ERR("PCRE compilation of '%s' failed at offset %d: %s\n",
00308 pattern, err_offset, error);
00309 return (pcre *)0;
00310 }
00311 rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size);
00312 if (rc != 0) {
00313 pcre_free(re);
00314 LM_ERR("pcre_fullinfo on compiled pattern '%s' yielded error: %d\n",
00315 pattern, rc);
00316 return (pcre *)0;
00317 }
00318 rc = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, cap_cnt);
00319 if (rc != 0) {
00320 pcre_free(re);
00321 LM_ERR("pcre_fullinfo on compiled pattern '%s' yielded error: %d\n",
00322 pattern, rc);
00323 return (pcre *)0;
00324 }
00325 result = (pcre *)shm_malloc(size);
00326 if (result == NULL) {
00327 pcre_free(re);
00328 LM_ERR("not enough shared memory for compiled PCRE pattern\n");
00329 return (pcre *)0;
00330 }
00331 memcpy(result, re, size);
00332 pcre_free(re);
00333 return result;
00334 }
00335
00336
00337
00338 dpl_node_t * build_rule(db_val_t * values)
00339 {
00340 pcre *match_comp, *subst_comp;
00341 struct subst_expr *repl_comp;
00342 const char *error;
00343 dpl_node_t * new_rule;
00344 str match_exp, subst_exp, repl_exp, attrs;
00345 int matchop, cap_cnt;
00346
00347 matchop = VAL_INT(values+2);
00348
00349 if((matchop != REGEX_OP) && (matchop!=EQUAL_OP)){
00350 LM_ERR("invalid value for match operator\n");
00351 return NULL;
00352 }
00353
00354 match_comp = subst_comp =0;
00355 repl_comp = 0;
00356 new_rule = 0;
00357 error = NULL;
00358
00359 GET_STR_VALUE(match_exp, values, 3);
00360 if(matchop == REGEX_OP){
00361 match_comp = reg_ex_comp(match_exp.s, &cap_cnt);
00362 if(!match_comp){
00363 LM_ERR("failed to compile match expression %.*s\n",
00364 match_exp.len, match_exp.s);
00365 goto err;
00366 }
00367 }
00368
00369 LM_DBG("build_rule\n");
00370 GET_STR_VALUE(repl_exp, values, 6);
00371 if(repl_exp.len && repl_exp.s){
00372 repl_comp = repl_exp_parse(repl_exp);
00373 if(!repl_comp){
00374 LM_ERR("failed to compile replacing expression %.*s\n",
00375 repl_exp.len, repl_exp.s);
00376 goto err;
00377 }
00378 }
00379
00380 GET_STR_VALUE(subst_exp, values, 5);
00381 if(subst_exp.s && subst_exp.len){
00382 subst_comp = reg_ex_comp(subst_exp.s, &cap_cnt);
00383 if(!subst_comp){
00384 LM_ERR("failed to compile subst expression %.*s\n",
00385 subst_exp.len, subst_exp.s);
00386 goto err;
00387 }
00388 if (cap_cnt > MAX_REPLACE_WITH) {
00389 LM_ERR("subst expression %.*s has too many sub-expressions\n",
00390 subst_exp.len, subst_exp.s);
00391 goto err;
00392 }
00393 }
00394
00395 if (repl_comp && (cap_cnt < repl_comp->max_pmatch) &&
00396 (repl_comp->max_pmatch != 0)) {
00397 LM_ERR("repl_exp %.*s refers to %d sub-expressions, but "
00398 "subst_exp %.*s has only %d\n",
00399 repl_exp.len, repl_exp.s, repl_comp->max_pmatch,
00400 subst_exp.len, subst_exp.s, cap_cnt);
00401 goto err;
00402 }
00403
00404 new_rule = (dpl_node_t *)shm_malloc(sizeof(dpl_node_t));
00405 if(!new_rule){
00406 LM_ERR("out of shm memory(new_rule)\n");
00407 goto err;
00408 }
00409 memset(new_rule, 0, sizeof(dpl_node_t));
00410
00411 if(str_to_shm(match_exp, &new_rule->match_exp)!=0)
00412 goto err;
00413
00414 if(str_to_shm(subst_exp, &new_rule->subst_exp)!=0)
00415 goto err;
00416
00417 if(str_to_shm(repl_exp, &new_rule->repl_exp)!=0)
00418 goto err;
00419
00420
00421 new_rule->dpid = VAL_INT(values);
00422 new_rule->pr = VAL_INT(values+1);
00423 new_rule->matchlen = VAL_INT(values+4);
00424 new_rule->matchop = matchop;
00425 GET_STR_VALUE(attrs, values, 7);
00426 if(str_to_shm(attrs, &new_rule->attrs)!=0)
00427 goto err;
00428
00429 LM_DBG("attrs are %.*s\n", new_rule->attrs.len, new_rule->attrs.s);
00430
00431 new_rule->match_comp = match_comp;
00432 new_rule->subst_comp = subst_comp;
00433 new_rule->repl_comp = repl_comp;
00434
00435 return new_rule;
00436
00437 err:
00438 if(match_comp) shm_free(match_comp);
00439 if(subst_comp) shm_free(subst_comp);
00440 if(repl_comp) repl_expr_free(repl_comp);
00441 if(new_rule) destroy_rule(new_rule);
00442 return NULL;
00443 }
00444
00445
00446 int add_rule2hash(dpl_node_t * rule, int h_index)
00447 {
00448 dpl_id_p crt_idp, last_idp;
00449 dpl_index_p indexp, last_indexp, new_indexp;
00450 int new_id;
00451
00452 if(!rules_hash){
00453 LM_ERR("data not allocated\n");
00454 return -1;
00455 }
00456
00457 new_id = 0;
00458
00459
00460 for(crt_idp = last_idp =rules_hash[h_index]; crt_idp!= NULL;
00461 last_idp = crt_idp, crt_idp = crt_idp->next)
00462 if(crt_idp->dp_id == rule->dpid)
00463 break;
00464
00465
00466 if(!crt_idp){
00467 crt_idp = (dpl_id_t*)shm_malloc(sizeof(dpl_id_t));
00468 if(!crt_idp){
00469 LM_ERR("out of shm memory (crt_idp)\n");
00470 return -1;
00471 }
00472 memset(crt_idp, 0, sizeof(dpl_id_t));
00473 crt_idp->dp_id = rule->dpid;
00474 new_id = 1;
00475 LM_DBG("new dpl_id %i\n", rule->dpid);
00476 }
00477
00478
00479 for(indexp = last_indexp =crt_idp->first_index; indexp!=NULL;
00480 last_indexp = indexp, indexp = indexp->next){
00481 if(indexp->len == rule->matchlen)
00482 goto add_rule;
00483 if((rule->matchlen!=0)&&((indexp->len)?(indexp->len>rule->matchlen):1))
00484 goto add_index;
00485 }
00486
00487 add_index:
00488 LM_DBG("new index , len %i\n", rule->matchlen);
00489
00490 new_indexp = (dpl_index_t *)shm_malloc(sizeof(dpl_index_t));
00491 if(!new_indexp){
00492 LM_ERR("out of shm memory\n");
00493 goto err;
00494 }
00495 memset(new_indexp , 0, sizeof(dpl_index_t));
00496 new_indexp->next = indexp;
00497 new_indexp->len = rule->matchlen;
00498
00499
00500 if(last_indexp == indexp){
00501 crt_idp->first_index = new_indexp;
00502 }else{
00503 last_indexp->next = new_indexp;
00504 }
00505
00506 indexp = new_indexp;
00507
00508 add_rule:
00509 rule->next = 0;
00510 if(!indexp->first_rule)
00511 indexp->first_rule = rule;
00512
00513 if(indexp->last_rule)
00514 indexp->last_rule->next = rule;
00515
00516 indexp->last_rule = rule;
00517
00518 if(new_id){
00519 crt_idp->next = rules_hash[h_index];
00520 rules_hash[h_index] = crt_idp;
00521 }
00522 LM_DBG("added the rule id %i index %i pr %i next %p to the "
00523 "index with %i len\n", rule->dpid, rule->matchlen,
00524 rule->pr, rule->next, indexp->len);
00525
00526 return 0;
00527
00528 err:
00529 if(new_id)
00530 shm_free(crt_idp);
00531 return -1;
00532 }
00533
00534
00535 void destroy_hash(int index)
00536 {
00537 dpl_id_p crt_idp;
00538 dpl_index_p indexp;
00539 dpl_node_p rulep;
00540
00541 if(!rules_hash[index])
00542 return;
00543
00544 for(crt_idp = rules_hash[index]; crt_idp != NULL;){
00545
00546 for(indexp = crt_idp->first_index; indexp != NULL;){
00547
00548 for(rulep = indexp->first_rule; rulep!= NULL;){
00549
00550 destroy_rule(rulep);
00551
00552 indexp->first_rule = rulep->next;
00553 shm_free(rulep);
00554 rulep=0;
00555 rulep= indexp->first_rule;
00556 }
00557 crt_idp->first_index= indexp->next;
00558 shm_free(indexp);
00559 indexp=0;
00560 indexp = crt_idp->first_index;
00561
00562 }
00563
00564 rules_hash[index] = crt_idp->next;
00565 shm_free(crt_idp);
00566 crt_idp = 0;
00567 crt_idp = rules_hash[index];
00568 }
00569
00570 rules_hash[index] = 0;
00571 }
00572
00573
00574 void destroy_rule(dpl_node_t * rule){
00575
00576 if(!rule)
00577 return;
00578
00579 LM_DBG("destroying rule with priority %i\n",
00580 rule->pr);
00581
00582 if(rule->match_comp)
00583 shm_free(rule->match_comp);
00584
00585 if(rule->subst_comp)
00586 shm_free(rule->subst_comp);
00587
00588
00589 if(rule->repl_comp)
00590 repl_expr_free(rule->repl_comp);
00591
00592 if(rule->match_exp.s)
00593 shm_free(rule->match_exp.s);
00594
00595 if(rule->subst_exp.s)
00596 shm_free(rule->subst_exp.s);
00597
00598 if(rule->repl_exp.s)
00599 shm_free(rule->repl_exp.s);
00600
00601 if(rule->attrs.s)
00602 shm_free(rule->attrs.s);
00603 }
00604
00605
00606 dpl_id_p select_dpid(int id)
00607 {
00608 dpl_id_p idp;
00609
00610 if(!rules_hash || !crt_idx)
00611 return NULL;
00612
00613 for(idp = rules_hash[*crt_idx]; idp!=NULL; idp = idp->next)
00614 if(idp->dp_id == id)
00615 return idp;
00616
00617 return NULL;
00618 }
00619
00620
00621
00622 void list_hash(int h_index)
00623 {
00624 dpl_id_p crt_idp;
00625 dpl_index_p indexp;
00626 dpl_node_p rulep;
00627
00628
00629 if(!rules_hash[h_index])
00630 return;
00631
00632 for(crt_idp=rules_hash[h_index]; crt_idp!=NULL; crt_idp = crt_idp->next){
00633 LM_DBG("DPID: %i, pointer %p\n", crt_idp->dp_id, crt_idp);
00634 for(indexp=crt_idp->first_index; indexp!=NULL;indexp= indexp->next){
00635 LM_DBG("INDEX LEN: %i\n", indexp->len);
00636 for(rulep = indexp->first_rule; rulep!= NULL;rulep = rulep->next){
00637 list_rule(rulep);
00638 }
00639 }
00640 }
00641 }
00642
00643
00644 void list_rule(dpl_node_t * rule)
00645 {
00646 LM_DBG("RULE %p: pr %i next %p match_exp %.*s, "
00647 "subst_exp %.*s, repl_exp %.*s and attrs %.*s\n", rule,
00648 rule->pr, rule->next,
00649 rule->match_exp.len, rule->match_exp.s,
00650 rule->subst_exp.len, rule->subst_exp.s,
00651 rule->repl_exp.len, rule->repl_exp.s,
00652 rule->attrs.len, rule->attrs.s);
00653
00654 }