/**
* $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 <ramona@voice-system.ro>
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#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<RES_ROW_N(db_res); i++)
{
/* check for NULL values ?!?! */
sdomain.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
sdomain.len = strlen(sdomain.s);
p.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val);
p.len = strlen(p.s);
d.s = (char*)(RES_ROWS(db_res)[i].values[2].val.string_val);
d.len = strlen(d.s);
if(p.s==NULL || d.s==NULL || sdomain.s==NULL ||
p.len<=0 || d.len<=0 || sdomain.len<=0)
{
LOG(L_ERR, "PDT:pdt_load_db: Error - bad values in db\n");
continue;
}
if(pdt_check_pd(_dhash, &sdomain, &p, &d)==1)
{
LOG(L_ERR,
"PDT:pdt_load_db:sdomain [%.*s]: prefix [%.*s] or domain <%.*s> 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->idsync<ito->id)
{
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; i<h->hash_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;
}
syntax highlighted by Code2HTML, v. 0.9.1