/** * $Id$ * * Copyright (C) 2008 Elena-Ramona Modroiu (asipto.com) * * This file is part of kamailio, a free SIP server. * * Kamailio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * Kamailio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "../../dprint.h" #include "../../usr_avp.h" #include "../../ut.h" #include "../../lib/srdb1/db.h" #include "ht_db.h" /** database connection */ db1_con_t *ht_db_con = NULL; db_func_t ht_dbf; str ht_array_size_suffix = str_init("::size"); /** db parameters */ str ht_db_url = {0, 0}; str ht_db_name_column = str_init("key_name"); str ht_db_ktype_column = str_init("key_type"); str ht_db_vtype_column = str_init("value_type"); str ht_db_value_column = str_init("key_value"); str ht_db_expires_column= str_init("expires"); int ht_fetch_rows = 100; /** * init module parameters */ int ht_db_init_params(void) { if(ht_db_url.s==0) return 0; if(ht_fetch_rows<=0) ht_fetch_rows = 100; if(ht_array_size_suffix.s==NULL || ht_array_size_suffix.s[0]=='\0') ht_array_size_suffix.s = "::size"; ht_array_size_suffix.len = strlen(ht_array_size_suffix.s); ht_db_url.len = strlen(ht_db_url.s); ht_db_name_column.len = strlen(ht_db_name_column.s); ht_db_ktype_column.len = strlen(ht_db_ktype_column.s); ht_db_vtype_column.len = strlen(ht_db_vtype_column.s); ht_db_value_column.len = strlen(ht_db_value_column.s); return 0; } /** * initialize database connection */ int ht_db_init_con(void) { /* binding to DB module */ if(db_bind_mod(&ht_db_url, &ht_dbf)) { LM_ERR("database module not found\n"); return -1; } if (!DB_CAPABILITY(ht_dbf, DB_CAP_ALL)) { LM_ERR("database module does not " "implement all functions needed by the module\n"); return -1; } return 0; } /** * open database connection */ int ht_db_open_con(void) { /* open a connection with the database */ ht_db_con = ht_dbf.init(&ht_db_url); if(ht_db_con==NULL) { LM_ERR("failed to connect to the database\n"); return -1; } LM_DBG("database connection opened successfully\n"); return 0; } /** * close database connection */ int ht_db_close_con(void) { if (ht_db_con!=NULL && ht_dbf.close!=NULL) ht_dbf.close(ht_db_con); ht_db_con=NULL; return 0; } #define HT_NAME_BUF_SIZE 256 static char ht_name_buf[HT_NAME_BUF_SIZE]; /** * load content of a db table in hash table */ int ht_db_load_table(ht_t *ht, str *dbtable, int mode) { db_key_t db_cols[5] = {&ht_db_name_column, &ht_db_ktype_column, &ht_db_vtype_column, &ht_db_value_column, &ht_db_expires_column}; db_key_t db_ord = &ht_db_name_column; db1_res_t* db_res = NULL; str kname; str pname; str hname; str kvalue; int ktype; int vtype; int last_ktype; int n; int_str val; int_str expires; int i; int ret; int cnt; int now; int ncols; if(ht_db_con==NULL) { LM_ERR("no db connection\n"); return -1; } if (ht_dbf.use_table(ht_db_con, dbtable) < 0) { LM_ERR("failed to use_table\n"); return -1; } LM_DBG("=============== loading hash table [%.*s] from database [%.*s]\n", ht->name.len, ht->name.s, dbtable->len, dbtable->s); cnt = 0; ncols = 4; if(ht->htexpire > 0 && ht_db_expires_flag!=0) ncols = 5; if (DB_CAPABILITY(ht_dbf, DB_CAP_FETCH)) { if(ht_dbf.query(ht_db_con,0,0,0,db_cols,0,ncols,db_ord,0) < 0) { LM_ERR("Error while querying db\n"); return -1; } if(ht_dbf.fetch_result(ht_db_con, &db_res, ht_fetch_rows)<0) { LM_ERR("Error while fetching result\n"); if (db_res) ht_dbf.free_result(ht_db_con, db_res); goto error; } else { if(RES_ROW_N(db_res)==0) { LM_DBG("Nothing to be loaded in hash table\n"); return 0; } } } else { if((ret=ht_dbf.query(ht_db_con, NULL, NULL, NULL, db_cols, 0, ncols, db_ord, &db_res))!=0 || RES_ROW_N(db_res)<=0 ) { if( ret==0) { ht_dbf.free_result(ht_db_con, db_res); return 0; } else { goto error; } } } pname.len = 0; pname.s = ""; n = 0; last_ktype = 0; now = (int)time(NULL); do { for(i=0; ihtexpire > 0 && ht_db_expires_flag!=0) { expires.n = RES_ROWS(db_res)[i].values[4].val.int_val; if (expires.n > 0 && expires.n < now) { LM_DBG("skipping expired entry [%.*s] (%d)\n", kname.len, kname.s, expires.n-now); continue; } } cnt++; ktype = RES_ROWS(db_res)[i].values[1].val.int_val; if(last_ktype==1) { if(pname.len>0 && (pname.len!=kname.len || strncmp(pname.s, kname.s, pname.len)!=0)) { /* new key name, last was an array => add its size */ snprintf(ht_name_buf, HT_NAME_BUF_SIZE, "%.*s%.*s", pname.len, pname.s, ht_array_size_suffix.len, ht_array_size_suffix.s); hname.s = ht_name_buf; hname.len = strlen(ht_name_buf); val.n = n; if(ht_set_cell(ht, &hname, 0, &val, mode)) { LM_ERR("error adding array size to hash table.\n"); goto error; } pname.len = 0; pname.s = ""; n = 0; } } last_ktype = ktype; pname = kname; if(ktype==1) { snprintf(ht_name_buf, HT_NAME_BUF_SIZE, "%.*s[%d]", kname.len, kname.s, n); hname.s = ht_name_buf; hname.len = strlen(ht_name_buf); n++; } else { hname = kname; } vtype = RES_ROWS(db_res)[i].values[2].val.int_val; kvalue.s = (char*)(RES_ROWS(db_res)[i].values[3].val.string_val); if(kvalue.s==NULL) { LM_ERR("null value in row %d\n", i); goto error; } kvalue.len = strlen(kvalue.s); /* add to hash */ if(vtype==1) str2sint(&kvalue, &val.n); else val.s = kvalue; if(ht_set_cell(ht, &hname, (vtype)?0:AVP_VAL_STR, &val, mode)) { LM_ERR("error adding to hash table\n"); goto error; } /* set expiry */ if (ht->htexpire > 0 && expires.n > 0) { expires.n -= now; if(ht_set_cell_expire(ht, &hname, 0, &expires)) { LM_ERR("error setting expires to hash entry [%*.s]\n", hname.len, hname.s); goto error; } } } if (DB_CAPABILITY(ht_dbf, DB_CAP_FETCH)) { if(ht_dbf.fetch_result(ht_db_con, &db_res, ht_fetch_rows)<0) { LM_ERR("Error while fetching!\n"); goto error; } } else { break; } } while(RES_ROW_N(db_res)>0); if(last_ktype==1) { snprintf(ht_name_buf, HT_NAME_BUF_SIZE, "%.*s%.*s", pname.len, pname.s, ht_array_size_suffix.len, ht_array_size_suffix.s); hname.s = ht_name_buf; hname.len = strlen(ht_name_buf); val.n = n; if(ht_set_cell(ht, &hname, 0, &val, mode)) { LM_ERR("error adding array size to hash table.\n"); goto error; } } ht_dbf.free_result(ht_db_con, db_res); LM_DBG("loaded %d values in hash table\n", cnt); return 0; error: ht_dbf.free_result(ht_db_con, db_res); return -1; } /** * save hash table content back to database */ int ht_db_save_table(ht_t *ht, str *dbtable) { db_key_t db_cols[5] = {&ht_db_name_column, &ht_db_ktype_column, &ht_db_vtype_column, &ht_db_value_column, &ht_db_expires_column}; db_val_t db_vals[5]; ht_cell_t *it; str tmp; int i; time_t now; int ncols; if(ht_db_con==NULL) { LM_ERR("no db connection\n"); return -1; } if (ht_dbf.use_table(ht_db_con, dbtable) < 0) { LM_ERR("failed to use_table\n"); return -1; } LM_DBG("save the content of hash table [%.*s] to database in [%.*s]\n", ht->name.len, ht->name.s, dbtable->len, dbtable->s); now = time(NULL); for(i=0; ihtsize; i++) { lock_get(&ht->entries[i].lock); it = ht->entries[i].first; while(it) { if(it->flags&AVP_VAL_STR) { LM_DBG("entry key: [%.*s] value: [%.*s] (str)\n", it->name.len, it->name.s, it->value.s.len, it->value.s.s); } else { LM_DBG("entry key: [%.*s] value: [%d] (int)\n", it->name.len, it->name.s, it->value.n); } if(ht->htexpire > 0) { if (it->expire <= now) { LM_DBG("skipping expired entry"); it = it->next; continue; } } db_vals[0].type = DB1_STR; db_vals[0].nul = 0; db_vals[0].val.str_val.s = it->name.s; db_vals[0].val.str_val.len = it->name.len; db_vals[1].type = DB1_INT; db_vals[1].nul = 0; db_vals[1].val.int_val = 0; db_vals[2].type = DB1_INT; db_vals[2].nul = 0; db_vals[3].type = DB1_STR; db_vals[3].nul = 0; if(it->flags&AVP_VAL_STR) { db_vals[2].val.int_val = 0; db_vals[3].val.str_val.s = it->value.s.s; db_vals[3].val.str_val.len = it->value.s.len; } else { db_vals[2].val.int_val = 1; tmp.s = sint2str((long)it->value.n, &tmp.len); db_vals[3].val.str_val.s = tmp.s; db_vals[3].val.str_val.len = tmp.len; } ncols = 4; if(ht_db_expires_flag!=0 && ht->htexpire > 0) { db_vals[4].type = DB1_INT; db_vals[4].nul = 0; db_vals[4].val.int_val = (int)it->expire; ncols = 5; } if(ht_dbf.insert(ht_db_con, db_cols, db_vals, ncols) < 0) { LM_ERR("failed to store key [%.*s] in table [%.*s]\n", it->name.len, it->name.s, dbtable->len, dbtable->s); } it = it->next; } } return 0; } /** * delete databse table */ int ht_db_delete_records(str *dbtable) { if(ht_db_con==NULL) { LM_ERR("no db connection\n"); return -1; } if (ht_dbf.use_table(ht_db_con, dbtable) < 0) { LM_ERR("failed to use_table\n"); return -1; } if(ht_dbf.delete(ht_db_con, NULL, NULL, NULL, 0) < 0) LM_ERR("failed to delete db records in [%.*s]\n", dbtable->len, dbtable->s); return 0; }