dp_db.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dp_db.c 5054 2008-10-09 13:06:23Z juhe $
00003  *
00004  * Copyright (C)  2007-2008 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  * History:
00023  * --------
00024  *  2007-08-01 initial version (ancuta onofrei)
00025  *  2008-10-09 module is now using pcre regexp lib (juha heinanen)
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; /* database connection handle */
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    /* Find a database module */
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 /*load rules from DB*/
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       /*select the whole table and all the columns*/
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    /*update data*/
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 /* Compile pcre pattern and return pointer to shm copy of result */
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 /*compile the expressions, and if ok, build the rule */
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    /*set the rest of the rule fields*/
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    /*search for the corresponding dpl_id*/
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    /*didn't find a dpl_id*/
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    /*search for the corresponding dpl_index*/
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    /*add as first index*/
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    /*destroy repl_exp*/
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 /*FOR DEBUG PURPOSE*/
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 }

Generated on Tue May 22 16:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6