#include "../../lib/srdb1/db.h" #include "ul_db.h" #include "p_usrloc_mod.h" #include "ul_db_layer.h" #include "ul_db_api.h" typedef struct res_list { db1_con_t ** h; db1_res_t * r; struct res_list * next; } res_list_t; static void add_res(db1_res_t * _r, db1_con_t ** _h); static db1_con_t ** get_handle_by_res(db1_res_t * _r); static void drop_res(db1_res_t * _r); static ul_db_api_t p_ul_dbf; static db_func_t dbf; static res_list_t * used = NULL; static res_list_t * unused = NULL; static ul_domain_db_list_t * domain_db_list = NULL; int ul_db_layer_init(void) { if(bind_ul_db(&p_ul_dbf) < 0) { LM_ERR("could not bind ul_db_api.\n"); return -1; } if(db_bind_mod(&default_db_url, &dbf) < 0) { LM_ERR("could not bind db.\n"); return -1; } return 0; } void ul_db_layer_destroy(void) { res_list_t * tmp, * del; tmp = used; while(tmp) { del = tmp; tmp = tmp->next; pkg_free(del); } tmp = unused; while(tmp) { del = tmp; tmp = tmp->next; pkg_free(del); } return; } int ul_db_layer_single_connect(udomain_t * domain, str * url) { if((domain->dbh = dbf.init(url)) == NULL){ return -1; } return 1; } int ul_db_layer_insert(udomain_t * domain, str * user, str * sipdomain, db_key_t* _k, db_val_t* _v, int _n) { ul_domain_db_t * d; switch(domain->dbt) { case DB_TYPE_CLUSTER: return p_ul_dbf.insert(domain->name, user, sipdomain, _k, _v, _n); case DB_TYPE_SINGLE: if(!domain->dbh){ if((d = ul_find_domain(domain->name->s)) == 0){ return -1; } if(ul_db_layer_single_connect(domain, &d->url) < 0){ return -1; } } if(dbf.use_table(domain->dbh, domain->name) < 0) { return -1; } return dbf.insert(domain->dbh, _k, _v, _n); default: return -1; } } int ul_db_layer_update(udomain_t * domain, str * user, str * sipdomain, db_key_t* _k, db_op_t* _o, db_val_t* _v, db_key_t* _uk, db_val_t* _uv, int _n, int _un) { ul_domain_db_t * d; switch(domain->dbt) { case DB_TYPE_CLUSTER: return p_ul_dbf.update(domain->name, user, sipdomain, _k, _o, _v, _uk, _uv, _n, _un); case DB_TYPE_SINGLE: if(!domain->dbh){ if((d = ul_find_domain(domain->name->s)) == 0){ return -1; } if(ul_db_layer_single_connect(domain, &d->url) < 0){ return -1; } } if(dbf.use_table(domain->dbh, domain->name) < 0) { return -1; } return dbf.update(domain->dbh, _k, _o, _v, _uk, _uv, _n, _un); default: return -1; } } int ul_db_layer_replace (udomain_t * domain, str * user, str * sipdomain, db_key_t* _k, db_val_t* _v, int _n, int _un) { ul_domain_db_t * d; switch(domain->dbt) { case DB_TYPE_CLUSTER: { return p_ul_dbf.replace(domain->name, user, sipdomain, _k, _v, _n, _un);;} case DB_TYPE_SINGLE: if(!domain->dbh){ if((d = ul_find_domain(domain->name->s)) == 0){ return -1; } if(ul_db_layer_single_connect(domain, &d->url) < 0){ return -1; } } if(dbf.use_table(domain->dbh, domain->name) < 0) { return -1; } return dbf.replace(domain->dbh, _k, _v, _n, _un, 0); default: return -1; } } int ul_db_layer_delete(udomain_t * domain, str * user, str * sipdomain, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n) { ul_domain_db_t * d; switch(domain->dbt) { case DB_TYPE_CLUSTER: return p_ul_dbf.delete(domain->name, user, sipdomain, _k, _o, _v, _n); case DB_TYPE_SINGLE: if(!domain->dbh){ if((d = ul_find_domain(domain->name->s)) == 0){ return -1; } if(ul_db_layer_single_connect(domain, &d->url) < 0){ return -1; } } if(dbf.use_table(domain->dbh, domain->name) < 0) { return -1; } return dbf.delete(domain->dbh, _k, _o, _v, _n); default: return -1; } } int ul_db_layer_query(udomain_t * domain, str * user, str * sipdomain, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc, db_key_t _o, db1_res_t** _r) { ul_domain_db_t * d; db1_con_t ** h; int ret; switch(domain->dbt) { case DB_TYPE_CLUSTER:{ if((ret = p_ul_dbf.query(domain->name, user, sipdomain, &h, _k, _op, _v, _c, _n, _nc, _o, _r)) < 0 || (!_r)) { return -1; } add_res(*_r, h); return ret; } case DB_TYPE_SINGLE: if(!domain->dbh){ if((d = ul_find_domain(domain->name->s)) == 0){ return -1; } if(ul_db_layer_single_connect(domain, &d->url) < 0){ return -1; } } if(dbf.use_table(domain->dbh, domain->name) < 0) { return -1; } return dbf.query(domain->dbh, _k, _op, _v, _c, _n, _nc, _o, _r); default: return -1; } } int ul_db_layer_raw_query(udomain_t * domain, str* _s, db1_res_t** _r) { ul_domain_db_t * d; switch(domain->dbt) { case DB_TYPE_CLUSTER: { return -1; // not useful in this mode } case DB_TYPE_SINGLE: if(!domain->dbh){ if((d = ul_find_domain(domain->name->s)) == 0){ return -1; } if(ul_db_layer_single_connect(domain, &d->url) < 0){ return -1; } } if(dbf.use_table(domain->dbh, domain->name) < 0) { return -1; } return dbf.raw_query(domain->dbh, _s, _r); default: return -1; } } int ul_db_layer_free_result(udomain_t * domain, db1_res_t * res) { db1_con_t ** h; int ret; switch(domain->dbt) { case DB_TYPE_CLUSTER: if((h = get_handle_by_res(res)) == NULL) { return -1; } ret = p_ul_dbf.free_result(h, res); drop_res(res); return ret; case DB_TYPE_SINGLE: return dbf.free_result(domain->dbh, res); default: return -1; } } int ul_add_domain_db(str * d, int t, str * url) { ul_domain_db_list_t * new_d = NULL; LM_DBG("%.*s, type: %s\n", d->len, d->s, t==DB_TYPE_SINGLE ? "SINGLE" : "CLUSTER"); if((new_d = pkg_malloc(sizeof(ul_domain_db_list_t))) == NULL) { return -1; } memset(new_d, 0, sizeof(ul_domain_db_list_t)); if(!d){ return -1; } if(!d->s){ return -1; } if((new_d->domain.name.s = pkg_malloc(d->len + 1)) == NULL) { return -1; } if(t == DB_TYPE_SINGLE) { if(url) { LM_DBG("url: %.*s", url->len, url->s); if((new_d->domain.url.s = pkg_malloc(url->len + 1)) == NULL) { return -1; } strncpy(new_d->domain.url.s, url->s, url->len); new_d->domain.url.s[url->len] = '\0'; new_d->domain.url.len = url->len; } else { if((new_d->domain.url.s = pkg_malloc(default_db_url.len + 1)) == NULL) { return -1; } strcpy(new_d->domain.url.s, default_db_url.s); new_d->domain.url.len = default_db_url.len; } } strncpy(new_d->domain.name.s, d->s, d->len); new_d->domain.name.len = d->len; new_d->domain.dbt = t; new_d->next = domain_db_list; domain_db_list = new_d; return 1; } ul_domain_db_t * ul_find_domain(const char * s) { ul_domain_db_list_t * tmp; str d; if(!domain_db_list){ if(parse_domain_db(&domain_db) < 0){ LM_ERR("could not parse domain parameter.\n"); return NULL; } } tmp = domain_db_list; while(tmp){ LM_DBG("searched domain: %s, actual domain: %.*s, length: %i, type: %s\n", s, tmp->domain.name.len, tmp->domain.name.s, tmp->domain.name.len, tmp->domain.dbt==DB_TYPE_SINGLE ? "SINGLE" : "CLUSTER"); if((strlen(s) == tmp->domain.name.len) && (memcmp(s, tmp->domain.name.s, tmp->domain.name.len) == 0)){ return &tmp->domain; } tmp = tmp->next; } if((d.s = pkg_malloc(strlen(s) + 1)) == NULL){ return NULL; } strcpy(d.s, s); d.len = strlen(s); if(ul_add_domain_db(&d, default_dbt, &default_db_url)){ pkg_free(d.s); return ul_find_domain(s); } pkg_free(d.s); return NULL; } void free_all_udomains(void) { ul_domain_db_list_t * tmp, * del; tmp = domain_db_list; while(tmp){ del = tmp; tmp = tmp->next; pkg_free(del->domain.name.s); if(del->domain.dbt == DB_TYPE_SINGLE){ pkg_free(del->domain.url.s); } pkg_free(del); } return; } int parse_domain_db(str * _d) { #define STATE_START 0 #define STATE_DOMAIN 1 #define STATE_TYPE 2 #define STATE_URL 3 char * domains; char * end; str d = {NULL, 0}, u = {NULL, 0}, t = {NULL, 0}; int type = 0; int state; if (_d->len==0) { return -1; } domains = _d->s; end = domains + _d->len; state = STATE_START; while(domains <= end) { switch(*domains) { case '=': switch(state) { case STATE_START: return -1; case STATE_DOMAIN: LM_DBG("found domain %.*s\n", d.len, d.s); state = STATE_TYPE; t.s = domains + 1; t.len = 0; break; case STATE_TYPE: return -1; case STATE_URL: return -1; default: return -1; } break; case ';': switch(state) { case STATE_START: return 1; case STATE_DOMAIN: return -1; case STATE_TYPE: LM_DBG("found type %.*s\n", t.len, t.s); if(strncmp(t.s, DB_TYPE_CLUSTER_STR, strlen(DB_TYPE_CLUSTER_STR)) == 0) { type = DB_TYPE_CLUSTER; } else { type = DB_TYPE_SINGLE; } state = STATE_URL; u.s = domains + 1; u.len = 0; break; case STATE_URL: return -1; break; default: break; } break; case ',': switch(state) { case STATE_START: return -1; case STATE_DOMAIN: return -1; case STATE_TYPE: LM_DBG("found type %.*s\n", t.len, t.s); if(strncmp(t.s, DB_TYPE_CLUSTER_STR, strlen(DB_TYPE_CLUSTER_STR)) == 0) { type = DB_TYPE_CLUSTER; } else { type = DB_TYPE_SINGLE; } ul_add_domain_db(&d, type, NULL); state = STATE_START; break; case STATE_URL: LM_DBG("found url %.*s\n", u.len, u.s); state = STATE_START; ul_add_domain_db(&d, type, &u); break; default: return -1; } break; case '\0': switch(state) { case STATE_START: return 1; case STATE_DOMAIN: return -1; case STATE_TYPE: LM_DBG("found type %.*s\n", t.len, t.s); if(strncmp(t.s, DB_TYPE_CLUSTER_STR, strlen(DB_TYPE_CLUSTER_STR)) == 0) { type = DB_TYPE_CLUSTER; } else { type = DB_TYPE_SINGLE; } ul_add_domain_db(&d, type, NULL); return 1; case STATE_URL: LM_DBG("found url %.*s\n", u.len, u.s); ul_add_domain_db(&d, type, &u); return 1; default: return -1; } break; default: switch(state) { case STATE_START: state = STATE_DOMAIN; d.s = domains; d.len = 1; break; case STATE_DOMAIN: d.len++; break; case STATE_TYPE: t.len++; break; case STATE_URL: u.len++; break; default: break; } break; } domains++; } return 1; } static void add_res(db1_res_t * _r, db1_con_t ** _h) { res_list_t * new_res; if(!unused) { if((new_res = pkg_malloc(sizeof(res_list_t))) == NULL) { return; } memset(new_res, 0, sizeof(res_list_t)); } else { new_res = unused; unused = unused->next; } new_res->h = _h; new_res->r = _r; new_res->next = used; used = new_res; return; } static db1_con_t ** get_handle_by_res(db1_res_t * _r) { res_list_t * tmp = used; while(tmp) { if(_r == tmp->r) { return tmp->h; } tmp = tmp->next; } return NULL; } static void drop_res(db1_res_t * _r) { res_list_t * prev = NULL; res_list_t * tmp; tmp = used; while(tmp) { if(_r == tmp->r) { if(prev==NULL) { used = tmp->next; } else { prev->next = tmp->next; } tmp->next = unused; unused = tmp; return; } prev = tmp; tmp = tmp->next; } return; }