/** * $Id: pdt.c 1808 2007-03-10 17:36:19Z bogdan_iancu $ * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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 * * History: * ------- * 2003-04-07: a structure for both hashes introduced (ramona) * 2003-04-06: db connection closed in mod_init (janakj) * 2004-06-07: updated to the new DB api (andrei) * 2005-01-26: removed terminating code (ramona) * prefix hash replaced with tree (ramona) * FIFO commands to add/list/delete prefix domains (ramona) * pdt cache per process for fast translation (ramona) * 2006-01-30: multi domain support added */ /* * Prefix-Domains Translation - ser module * Ramona Modroiu */ #include #include #include #include "../../db/db_op.h" #include "../../sr_module.h" #include "../../db/db.h" #include "../../mem/shm_mem.h" #include "../../mem/mem.h" #include "../../dprint.h" #include "../../parser/parse_uri.h" #include "../../timer.h" #include "../../ut.h" #include "../../action.h" #include "../../parser/parse_from.h" #include "domains.h" #include "pdtree.h" MODULE_VERSION #define NR_KEYS 3 int hs_two_pow = 2; /** structures containing prefix-domain pairs */ hash_list_t *_dhash = NULL; pdt_tree_t *_ptree = NULL; time_t last_sync; /** database connection */ static db_con_t *db_con = NULL; static db_func_t pdt_dbf; /** parameters */ static char *db_url = "mysql://root@127.0.0.1/pdt"; char *db_table = "pdt"; char *sdomain_column = "sdomain"; char *prefix_column = "prefix"; char *domain_column = "domain"; /** pstn prefix */ str prefix = {"", 0}; int sync_time = 600; int clean_time = 900; static int w_prefix2domain(struct sip_msg* msg, char* str1, char* str2); static int w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2); static int w_prefix2domain_2(struct sip_msg* msg, char* mode, char* sd_en); static int mod_init(void); static void mod_destroy(void); static int child_init(); static int mod_child_init(int r); static int prefix2domain(struct sip_msg*, int mode, int sd_en); static struct mi_root* pdt_mi_add(struct mi_root*, void* param); static struct mi_root* pdt_mi_delete(struct mi_root*, void* param); static struct mi_root* pdt_mi_list(struct mi_root*, void* param); int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode); int pdt_load_db(); int pdt_sync_cache(); void pdt_clean_cache(unsigned int ticks, void *param); static cmd_export_t cmds[]={ {"prefix2domain", w_prefix2domain, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE}, {"prefix2domain", w_prefix2domain_1, 1, 0, REQUEST_ROUTE|FAILURE_ROUTE}, {"prefix2domain", w_prefix2domain_2, 2, 0, REQUEST_ROUTE|FAILURE_ROUTE}, {0, 0, 0, 0, 0} }; static param_export_t params[]={ {"db_url", STR_PARAM, &db_url}, {"db_table", STR_PARAM, &db_table}, {"sdomain_column", STR_PARAM, &sdomain_column}, {"prefix_column", STR_PARAM, &prefix_column}, {"domain_column", STR_PARAM, &domain_column}, {"prefix", STR_PARAM, &prefix.s}, {"hsize_2pow", INT_PARAM, &hs_two_pow}, {"sync_time", INT_PARAM, &sync_time}, {"clean_time", INT_PARAM, &clean_time}, {0, 0, 0} }; static mi_export_t mi_cmds[] = { { "pdt_add", pdt_mi_add, 0, 0, child_init }, { "pdt_delete", pdt_mi_delete, 0, 0, 0 }, { "pdt_list", pdt_mi_list, 0, 0, 0 }, { 0, 0, 0, 0, 0} }; struct module_exports exports = { "pdt", DEFAULT_DLFLAGS, /* dlopen flags */ cmds, params, 0, mi_cmds, /* exported MI functions */ 0, /* exported pseudo-variables */ mod_init, /* module initialization function */ 0, /* response function */ mod_destroy, /* destroy function */ mod_child_init /* per child init function */ }; /** * init module function */ static int mod_init(void) { DBG("PDT: initializing...\n"); if(hs_two_pow<0) { LOG(L_ERR, "PDT:mod_init: hash_size_two_pow must be" " positive and less than %d\n", MAX_HSIZE_TWO_POW); return -1; } prefix.len = strlen(prefix.s); /* binding to mysql module */ if(bind_dbmod(db_url, &pdt_dbf)) { LOG(L_ERR, "PDT:mod_init: Database module not found\n"); return -1; } if (!DB_CAPABILITY(pdt_dbf, DB_CAP_ALL)) { LOG(L_ERR, "PDT: mod_init: Database module does not " "implement all functions needed by the module\n"); return -1; } /* open a connection with the database */ db_con = pdt_dbf.init(db_url); if(db_con==NULL) { LOG(L_ERR, "PDT: mod_init: Error while connecting to database\n"); return -1; } if (pdt_dbf.use_table(db_con, db_table) < 0) { LOG(L_ERR, "PDT: mod_init: Error in use_table\n"); goto error1; } DBG("PDT: mod_init: Database connection opened successfully\n"); /* init the hash and tree in share memory */ if( (_dhash = init_hash_list(hs_two_pow)) == NULL) { LOG(L_ERR, "PDT:mod_init: domain hash could not be allocated\n"); goto error1; } /* loading all information from database */ if(pdt_load_db()!=0) { LOG(L_ERR, "PDT:mod_init: cannot load info from database\n"); goto error2; } pdt_dbf.close(db_con); db_con = 0; pdt_print_tree(_ptree); DBG("PDT:mod_init: -------------------\n"); pdt_print_hash_list(_dhash); last_sync = time(NULL); register_timer(pdt_clean_cache, 0, clean_time); /* success code */ return 0; error2: if(_dhash!=NULL) { free_hash_list(_dhash); _dhash = 0; } error1: if(db_con!=NULL) { pdt_dbf.close(db_con); db_con = 0; } return -1; } static int child_init() { db_con = pdt_dbf.init(db_url); if(db_con==NULL) { LOG(L_ERR,"ERROR:PDT:child_init: failed to connect to database\n"); return -1; } if (pdt_dbf.use_table(db_con, db_table) < 0) { LOG(L_ERR, "ERROR:PDT:child_init: use_table failed\n"); return -1; } return 0; } /* each child get a new connection to the database */ static int mod_child_init(int r) { if(r>0) { if(_dhash==NULL) { LOG(L_ERR,"ERROR:PDT:mod_child_init #%d: no domain hash\n", r); return -1; } lock_get(&_dhash->hl_lock); _dhash->workers++; lock_release(&_dhash->hl_lock); } else { if(_ptree!=NULL) { pdt_free_tree(_ptree); _ptree = 0; } } if ( child_init()!=0 ) return -1; if(sync_time<=0) sync_time = 300; sync_time += r%60; DBG("PDT:mod_child_init #%d: Database connection opened successfully\n",r); return 0; } static void mod_destroy(void) { DBG("PDT: mod_destroy : Cleaning up\n"); if (_dhash!=NULL) free_hash_list(_dhash); if (_ptree!=NULL) pdt_free_tree(_ptree); if (db_con!=NULL && pdt_dbf.close!=NULL) pdt_dbf.close(db_con); } static int w_prefix2domain(struct sip_msg* msg, char* str1, char* str2) { return prefix2domain(msg, 0, 0); } static int w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2) { if(mode!=NULL && *mode=='1') return prefix2domain(msg, 1, 0); else if(mode!=NULL && *mode=='2') return prefix2domain(msg, 2, 0); else return prefix2domain(msg, 0, 0); } static int w_prefix2domain_2(struct sip_msg* msg, char* mode, char* sd_en) { int tmp=0; if((sd_en==NULL) || ((sd_en!=NULL) && (*sd_en!='0') && (*sd_en!='1') && (*sd_en!='2'))) return -1; if (*sd_en=='1') tmp = 1; if (*sd_en=='2') tmp = 2; if(mode!=NULL && *mode=='1') return prefix2domain(msg, 1, tmp); else if(mode!=NULL && *mode=='2') return prefix2domain(msg, 2, tmp); else return prefix2domain(msg, 0, tmp); } /* change the r-uri if it is a PSTN format */ static int prefix2domain(struct sip_msg* msg, int mode, int sd_en) { str *d, p, all={"*",1}; time_t crt_time; int plen; struct sip_uri uri; if(msg==NULL) { LOG(L_ERR,"PDT:prefix2domain: weird error\n"); return -1; } /* parse the uri, if not yet */ if(msg->parsed_uri_ok==0) if(parse_sip_msg_uri(msg)<0) { LOG(L_ERR,"PDT:prefix2domain: ERROR while parsing the R-URI\n"); return -1; } /* if the user part begin with the prefix for PSTN users, extract the code*/ if (msg->parsed_uri.user.len<=0) { DBG("PDT:prefix2domain: user part of the message is empty\n"); return -1; } if(prefix.len>0) { if (msg->parsed_uri.user.len<=prefix.len) { DBG("PDT:prefix2domain: user part is less than prefix\n"); return -1; } if(strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0) { DBG("PDT:prefix2domain: PSTN prefix did not matched\n"); return -1; } } if(prefix.len>0 && prefix.len < msg->parsed_uri.user.len && strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0) { DBG("PDT:prefix2domain: PSTN prefix did not matched\n"); return 1; } p.s = msg->parsed_uri.user.s + prefix.len; p.len = msg->parsed_uri.user.len - prefix.len; pdt_print_tree(_ptree); /* check if need for sync */ crt_time = time(NULL); if(last_sync + sync_time < crt_time) { last_sync = crt_time; if(pdt_sync_cache()) { /* keep reporting but continue */ LOG(L_ERR, "PDT:prefix2domain: cannot update the cache\n"); /* return -1; */ } } if(sd_en==2) { /* take the domain from FROM uri as sdomain */ if(parse_from_header(msg)<0 || msg->from == NULL || get_from(msg)==NULL) { LOG(L_ERR, "prefix_to_domain: ERROR cannot parse FROM header\n"); return -1; } memset(&uri, 0, sizeof(struct sip_uri)); if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0) { LOG(L_ERR,"prefix_to_domain: failed to parse From uri\n"); return -1; } /* find the domain that corresponds to this prefix */ plen = 0; if((d=pdt_get_domain(_ptree, &uri.host, &p, &plen))==NULL) { plen = 0; if((d=pdt_get_domain(_ptree, &all, &p, &plen))==NULL) { LOG(L_INFO, "PDT:prefix2domain: no prefix found in [%.*s]\n", p.len, p.s); return -1; } } } else if(sd_en==1) { /* take the domain from FROM uri as sdomain */ if(parse_from_header(msg)<0 || msg->from == NULL || get_from(msg)==NULL) { LOG(L_ERR, "prefix_to_domain: ERROR cannot parse FROM header\n"); return -1; } memset(&uri, 0, sizeof(struct sip_uri)); if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0) { LOG(L_ERR,"prefix_to_domain: failed to parse From uri\n"); return -1; } /* find the domain that corresponds to this prefix */ plen = 0; if((d=pdt_get_domain(_ptree, &uri.host, &p, &plen))==NULL) { LOG(L_INFO, "PDT:prefix2domain: no prefix found in [%.*s]\n", p.len, p.s); return -1; } } else { /* find the domain that corresponds to this prefix */ plen = 0; if((d=pdt_get_domain(_ptree, &all, &p, &plen))==NULL) { LOG(L_INFO, "PDT:prefix2domain: no prefix found in [%.*s]\n", p.len, p.s); return -1; } } /* update the new uri */ if(update_new_uri(msg, plen, d, mode)<0) { LOG(L_ERR, "PDT:prefix2domain: new_uri cannot be updated\n"); return -1; } return 1; } /* change the uri according to translation of the prefix */ int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode) { struct action act; if(msg==NULL || d==NULL) { LOG(L_ERR, "PDT:update_new_uri: bad parameters\n"); return -1; } if(mode==0 || (mode==1 && prefix.len>0)) { act.type = STRIP_T; act.elem[0].type = NUMBER_ST; if(mode==0) act.elem[0].u.number = plen + prefix.len; else act.elem[0].u.number = prefix.len; act.next = 0; if (do_action(&act, msg) < 0) { LOG(L_ERR, "PDT:update_new_uri:Error removing prefix\n"); return -1; } } act.type = SET_HOSTPORT_T; act.elem[0].type = STRING_ST; act.elem[0].u.string = d->s; act.next = 0; if (do_action(&act, msg) < 0) { LOG(L_ERR, "PDT:update_new_uri:Error changing domain\n"); return -1; } DBG("PDT: update_new_uri: len=%d uri=%.*s\n", msg->new_uri.len, msg->new_uri.len, msg->new_uri.s); return 0; } int pdt_load_db() { db_key_t db_cols[3] = {sdomain_column, prefix_column, domain_column}; str p, d, sdomain; db_res_t* db_res = NULL; int i; if(db_con==NULL) { LOG(L_ERR, "PDT:pdt_load_db: no db connection\n"); return -1; } if (pdt_dbf.use_table(db_con, db_table) < 0) { LOG(L_ERR, "PDT:pdt_load_db: Error in use_table\n"); return -1; } if(pdt_dbf.query(db_con, NULL, NULL, NULL, db_cols, 0, 3, sdomain_column, &db_res)==0) { for(i=0; i duplicated\n", sdomain.len, sdomain.s, p.len, p.s, d.len, d.s); continue; } if(pdt_add_to_tree(&_ptree, &sdomain, &p, &d)<0) { LOG(L_ERR, "PDT:pdt_load_db: Error adding info to tree\n"); goto error; } if(pdt_add_to_hash(_dhash, &sdomain, &p, &d, 0)!=0) { LOG(L_ERR, "PDT:pdt_load_db: Error adding info to hash\n"); goto error; } } } pdt_dbf.free_result(db_con, db_res); return 0; error: pdt_dbf.free_result(db_con, db_res); return -1; } int pdt_sync_cache() { pd_op_t *ito; hash_t *it; pdt_tree_t *itree; DBG("PDT:pdt_sync_cache: ...\n"); if(_dhash==NULL || _ptree==NULL) { LOG(L_ERR, "PDT:pdt_sync_cache: strange situation\n"); return -1; } lock_get(&_dhash->hl_lock); it = _dhash->hash; while(it != NULL) { itree = pdt_get_tree(_ptree, &it->sdomain); if(itree!=NULL && itree->idsync >= it->max_id) { it = it->next; continue; } ito = it->diff; while(ito!=NULL && itree->idsync >= ito->id) ito = ito->n; while(ito!=NULL && itree->idsyncid) { switch(ito->op) { case PDT_ADD: LOG(L_ERR, "PDT:pdt_sync_cache: add (%d) [%.*s-%.*s => %.*s]\n", ito->id, it->sdomain.len, it->sdomain.s, ito->cell->prefix.len, ito->cell->prefix.s, ito->cell->domain.len, ito->cell->domain.s); if(pdt_add_to_tree(&_ptree, &it->sdomain, &ito->cell->prefix, &ito->cell->domain)<0) { LOG(L_ERR, "PDT:pdt_sync_cache: Error to insert into tree\n"); break; } break; case PDT_DELETE: if(itree==NULL) { LOG(L_ERR, "PDT:pdt_sync_cache: Error to remove from tree, tree does not exist\n"); goto error; } LOG(L_ERR, "PDT:pdt_sync_cache: adel (%d) [%.*s-%.*s]\n", ito->id, it->sdomain.len, it->sdomain.s, ito->cell->prefix.len, ito->cell->prefix.s); if(pdt_remove_prefix_from_tree(itree, &it->sdomain, &ito->cell->prefix)!=0) { LOG(L_ERR, "PDT:pdt_sync_cache: Error to remove from tree\n"); break; } break; default: LOG(L_ERR, "PDT:pdt_sync_cache: unknown operation %d (%d)\n", ito->op, ito->id); } ito->count++; ito = ito->n; } if(it->diff!=NULL) itree->idsync = it->diff->id; it = it->next; } lock_release(&_dhash->hl_lock); return 0; error: lock_release(&_dhash->hl_lock); return -1; } void pdt_clean_cache(unsigned int ticks, void *param) { pd_op_t *ito, *tmp; hash_t *it; /* DBG("PDT:pdt_clean_cache: ...\n"); */ if(_dhash==NULL) { LOG(L_ERR, "PDT:pdt_clean_cache: strange situation\n"); return; } lock_get(&_dhash->hl_lock); it = _dhash->hash; while(it!=NULL) { ito = it->diff; while(ito!=NULL) { if(ito->count >= _dhash->workers) { DBG("PDT:pdt_clean_cache: cleaning sdomain<%.*s> op[%d]=%d...\n", it->sdomain.len, it->sdomain.s, ito->id, ito->op); free_cell(ito->cell); if(ito->p!=NULL) (ito->p)->n = ito->n; else it->diff = ito->n; if(ito->n!=NULL) (ito->n)->p = ito->p; tmp = ito; ito = ito->n; shm_free(tmp); } else ito = ito->n; } it = it->next; } lock_release(&_dhash->hl_lock); return; } /**************************** MI ***************************/ /** * "pdt_add" syntax : * sdomain * prefix * domain */ struct mi_root* pdt_mi_add(struct mi_root* cmd_tree, void* param) { db_key_t db_keys[NR_KEYS] = {sdomain_column, prefix_column, domain_column}; db_val_t db_vals[NR_KEYS]; db_op_t db_ops[NR_KEYS] = {OP_EQ, OP_EQ}; int i= 0; str sd, sp, sdomain; struct mi_node* node= NULL; if(_dhash==NULL) { LOG(L_ERR, "PDT:pdt_mi_add: strange situation\n"); return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN); } /* read sdomain */ node = cmd_tree->node.kids; if(node == NULL) goto error1; sdomain = node->value; if(sdomain.s == NULL || sdomain.len== 0) return init_mi_tree( 404, "domain not found", 16); if(*sdomain.s=='.' ) return init_mi_tree( 400, "empty param",11); /* read prefix */ node = node->next; if(node == NULL) goto error1; sp= node->value; if(sp.s== NULL || sp.len==0) { LOG(L_ERR, "PDT:pdt_mi_add: could not read prefix\n"); return init_mi_tree( 404, "prefix not found", 16); } if(*sp.s=='.') return init_mi_tree(400, "empty param", 11); while(i< sp.len) { if(sp.s[i] < '0' || sp.s[i] > '9') return init_mi_tree( 400, "bad prefix", 10); i++; } /* read domain */ node= node->next; if(node == NULL || node->next!=NULL) goto error1; sd= node->value; if(sd.s== NULL || sd.len==0) { LOG(L_ERR, "PDT:pdt_mi_add: could not read domain\n"); return init_mi_tree( 400, "domain not found", 16); } if(*sd.s=='.') return init_mi_tree( 400, "empty param", 11); if(pdt_check_pd(_dhash, &sdomain, &sp, &sd)==1) { LOG(L_ERR, "PDT:pdt_mi_add: (sdomain,prefix,domain) exists\n"); return init_mi_tree( 400, "(sdomain,prefix,domain) exists already", 38); } db_vals[0].type = DB_STR; db_vals[0].nul = 0; db_vals[0].val.str_val.s = sdomain.s; db_vals[0].val.str_val.len = sdomain.len; db_vals[1].type = DB_STR; db_vals[1].nul = 0; db_vals[1].val.str_val.s = sp.s; db_vals[1].val.str_val.len = sp.len; db_vals[2].type = DB_STR; db_vals[2].nul = 0; db_vals[2].val.str_val.s = sd.s; db_vals[2].val.str_val.len = sd.len; /* insert a new domain into database */ if(pdt_dbf.insert(db_con, db_keys, db_vals, NR_KEYS)<0) { LOG(L_ERR, "PDT:pdt_mi_add: error storing new prefix/domain\n"); return init_mi_tree( 500,"Cannot store prefix/domain", 26); } if(pdt_add_to_hash(_dhash, &sdomain, &sp, &sd, 1)!=0) { LOG(L_ERR, "PDT:pdt_mi_add: could not add to cache\n"); goto error; } DBG("PDT:pdt_mi_add: new prefix added %.*s-%.*s => %.*s\n", sdomain.len, sdomain.s, sp.len, sp.s, sd.len, sd.s); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); error: if(pdt_dbf.delete(db_con, db_keys, db_ops, db_vals, NR_KEYS)<0) LOG(L_ERR,"PDT:pdt_mi_add: database/cache are inconsistent\n"); return init_mi_tree( 500, "could not add to cache", 23 ); error1: return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); } /** * "pdt_delete" syntax: * sdomain * domain */ struct mi_root* pdt_mi_delete(struct mi_root* cmd_tree, void* param) { str sd, sdomain; int ret; struct mi_node* node= NULL; db_key_t db_keys[2] = {sdomain_column, domain_column}; db_val_t db_vals[2]; db_op_t db_ops[2] = {OP_EQ, OP_EQ}; if(_dhash==NULL) { LOG(L_ERR, "PDT:pdt_mi_delete: strange situation\n"); return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN); } /* read sdomain */ node = cmd_tree->node.kids; if(node == NULL) goto error; sdomain = node->value; if(sdomain.s == NULL || sdomain.len== 0) return init_mi_tree( 404, "domain not found", 16); if( *sdomain.s=='.' ) return init_mi_tree( 400, "400 empty param",11); /* read domain */ node= node->next; if(node == NULL || node->next!=NULL) goto error; sd= node->value; if(sd.s== NULL || sd.len==0) { LOG(L_ERR, "PDT:pdt_mi_delete: could not read domain\n"); return init_mi_tree(404, "domain not found", 16); } if(*sd.s=='.') return init_mi_tree( 400, "empty param", 11); if((ret = pdt_remove_from_hash_list(_dhash, &sdomain, &sd))<0) { DBG("PDT:pdt_mi_delete: error encountered when deleting domain\n"); return 0; } if(ret==1) { DBG("PDT:pdt_mi_delete: prefix for sdomain [%.*s]domain [%.*s] " "not found\n", sdomain.len, sdomain.s, sd.len, sd.s); return init_mi_tree( 404, "domain not found", 16); } db_vals[0].type = DB_STR; db_vals[0].nul = 0; db_vals[0].val.str_val.s = sdomain.s; db_vals[0].val.str_val.len = sdomain.len; db_vals[1].type = DB_STR; db_vals[1].nul = 0; db_vals[1].val.str_val.s = sd.s; db_vals[1].val.str_val.len = sd.len; if(pdt_dbf.delete(db_con, db_keys, db_ops, db_vals, 2)<0) { LOG(L_ERR,"PDT:pdt_mi_delete: database/cache are inconsistent\n"); return init_mi_tree( 500, "database/cache are inconsistent", 31 ); } DBG("PDT:pdt_mi_delete: prefix for sdomain [%.*s] domain [%.*s] " "removed\n", sdomain.len, sdomain.s, sd.len, sd.s); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); error: return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); } /** * "pdt_list" syntax : * sdomain * prefix * domain * * - '.' (dot) means NULL value and will match anything * - the comparison operation is 'START WITH' -- if domain is 'a' then * all domains starting with 'a' are listed * * Examples * pdt_list o 2 . - lists the entries where sdomain is starting with 'o', * prefix is starting with '2' and domain is anything * * pdt_list . 2 open - lists the entries where sdomain is anything, prefix * starts with '2' and domain starts with 'open' */ struct mi_root* pdt_mi_list(struct mi_root* cmd_tree, void* param) { str sd, sp, sdomain; pd_t *it; unsigned int i= 0; hash_t *h; struct mi_root* rpl_tree = NULL; struct mi_node* rpl = NULL; struct mi_node* node = NULL; struct mi_attr* attr= NULL; DBG("PDT:pdt_mi_list ...\n"); if(_dhash==NULL) { LOG(L_ERR, "PDT:pdt_mi_list: empty domain list\n"); return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN); } /* read sdomain */ sdomain.s = 0; sdomain.len = 0; sp.s = 0; sp.len = 0; sd.s = 0; sd.len = 0; node = cmd_tree->node.kids; if(node != NULL) { sdomain = node->value; if(sdomain.s == NULL || sdomain.len== 0) return init_mi_tree( 404, "domain not found", 16); if(*sdomain.s=='.') sdomain.s = 0; /* read prefix */ node = node->next; if(node != NULL) { sp= node->value; if(sp.s== NULL || sp.len==0 || *sp.s=='.') sp.s = NULL; else { while(sp.s!=NULL && i!=sp.len) { if(sp.s[i] < '0' || sp.s[i] > '9') { LOG(L_ERR, "PDT:pdt_mi_list: bad prefix [%.*s]\n", sp.len, sp.s); return init_mi_tree( 400, "bad prefix", 10); } i++; } } /* read domain */ node= node->next; if(node != NULL) { sd= node->value; if(sd.s== NULL || sd.len==0 || *sd.s=='.') sd.s = NULL; } } } rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN ); if(rpl_tree == NULL) return 0; rpl = &rpl_tree->node; lock_get(&_dhash->hl_lock); h = _dhash->hash; while(h!=NULL) { if(sdomain.s==NULL || (sdomain.s!=NULL && h->sdomain.len>=sdomain.len && strncmp(h->sdomain.s, sdomain.s, sdomain.len)==0)) { for(i=0; ihash_size; i++) { it = h->dhash[i]; while(it!=NULL) { if((sp.s==NULL && sd.s==NULL) ||(sp.s==NULL && (sd.s!=NULL && it->domain.len>=sd.len && strncasecmp(it->domain.s, sd.s, sd.len)==0)) || ( sd.s==NULL && (sp.s!=NULL && it->prefix.len>=sp.len && strncmp(it->prefix.s, sp.s, sp.len)==0)) || ((sp.s!=NULL && it->prefix.len>=sp.len && strncmp(it->prefix.s, sp.s, sp.len)==0) && (sd.s!=NULL && it->domain.len>=sd.len && strncasecmp(it->domain.s, sd.s, sd.len)==0))) { node = add_mi_node_child(rpl, 0 ,"PDT", 3, 0, 0); if(node == NULL) goto error; attr = add_mi_attr(node, MI_DUP_VALUE, "SDOMAIN", 7, h->sdomain.s, h->sdomain.len); if(attr == NULL) goto error; attr = add_mi_attr(node, MI_DUP_VALUE, "PREFIX", 6, it->prefix.s, it->prefix.len); if(attr == NULL) goto error; attr = add_mi_attr(node, MI_DUP_VALUE,"DOMAIN", 6, it->domain.s, it->domain.len); if(attr == NULL) goto error; } it = it->n; } } } h = h->next; } lock_release(&_dhash->hl_lock); return rpl_tree; error: lock_release(&_dhash->hl_lock); free_mi_tree(rpl_tree); return 0; }