dp_db.c

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