pdt.c

Go to the documentation of this file.
00001 /**
00002  * $Id: pdt.c 4657 2008-08-10 22:51:44Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio 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  * Kamailio 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  * 2003-04-07: a structure for both hashes introduced (ramona) 
00025  * 2003-04-06: db connection closed in mod_init (janakj)
00026  * 2004-06-07: updated to the new DB api (andrei)
00027  * 2005-01-26: removed terminating code (ramona)
00028  *             prefix hash replaced with tree (ramona)
00029  *             FIFO commands to add/list/delete prefix domains (ramona)
00030  *             pdt cache per process for fast translation (ramona)
00031  * 2006-01-30: multi domain support added
00032  */
00033 
00034 /*
00035  * Prefix-Domains Translation - ser module
00036  * Ramona Modroiu <ramona@voice-system.ro>
00037  */
00038 
00039 #include <stdio.h>
00040 #include <unistd.h>
00041 #include <stdlib.h>
00042 
00043 #include "../../db/db_op.h"
00044 #include "../../sr_module.h"
00045 #include "../../db/db.h"
00046 #include "../../mem/shm_mem.h"
00047 #include "../../mem/mem.h"
00048 #include "../../dprint.h"
00049 #include "../../parser/parse_uri.h"
00050 #include "../../timer.h"
00051 #include "../../ut.h"
00052 #include "../../locking.h"
00053 #include "../../action.h"
00054 #include "../../mod_fix.h"
00055 #include "../../parser/parse_from.h"
00056 
00057 #include "pdtree.h"
00058 
00059 MODULE_VERSION
00060 
00061 
00062 #define NR_KEYS         3
00063 
00064 int pdt_fetch_rows = 1000;
00065 
00066 /** structures containing prefix-domain pairs */
00067 pdt_tree_t **_ptree = NULL; 
00068 
00069 /** database connection */
00070 static db_con_t *db_con = NULL;
00071 static db_func_t pdt_dbf;
00072 
00073 
00074 /** parameters */
00075 static str db_url = str_init(DEFAULT_DB_URL);
00076 static str db_table = str_init("pdt");
00077 static str sdomain_column = str_init("sdomain");
00078 static str prefix_column  = str_init("prefix");
00079 static str domain_column  = str_init("domain");
00080 static int pdt_check_domain  = 1;
00081 
00082 /** pstn prefix */
00083 str prefix = {"", 0};
00084 /* List of allowed chars for a prefix*/
00085 str pdt_char_list = {"0123456789", 10};
00086 
00087 /* lock, ref counter and flag used for reloading the date */
00088 static gen_lock_t *pdt_lock = 0;
00089 static volatile int pdt_tree_refcnt = 0;
00090 static volatile int pdt_reload_flag = 0;
00091 
00092 static int  w_prefix2domain(struct sip_msg* msg, char* str1, char* str2);
00093 static int  w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2);
00094 static int  w_prefix2domain_2(struct sip_msg* msg, char* mode, char* sd_en);
00095 static int  mod_init(void);
00096 static void mod_destroy(void);
00097 static int  child_init(void);
00098 static int  mod_child_init(int r);
00099 static int prefix2domain(struct sip_msg*, int mode, int sd_en);
00100 
00101 static struct mi_root* pdt_mi_reload(struct mi_root*, void* param);
00102 static struct mi_root* pdt_mi_add(struct mi_root*, void* param);
00103 static struct mi_root* pdt_mi_delete(struct mi_root*, void* param);
00104 static struct mi_root* pdt_mi_list(struct mi_root*, void* param);
00105 
00106 static int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode);
00107 static int pdt_load_db();
00108 
00109 static cmd_export_t cmds[]={
00110    {"prefix2domain", (cmd_function)w_prefix2domain,   0, 0,
00111       0, REQUEST_ROUTE|FAILURE_ROUTE},
00112    {"prefix2domain", (cmd_function)w_prefix2domain_1, 1, fixup_igp_null,
00113       0, REQUEST_ROUTE|FAILURE_ROUTE},
00114    {"prefix2domain", (cmd_function)w_prefix2domain_2, 2, fixup_igp_igp,
00115       0, REQUEST_ROUTE|FAILURE_ROUTE},
00116    {0, 0, 0, 0, 0, 0}
00117 };
00118 
00119 static param_export_t params[]={
00120    {"db_url",         STR_PARAM, &db_url.s},
00121    {"db_table",       STR_PARAM, &db_table.s},
00122    {"sdomain_column", STR_PARAM, &sdomain_column.s},
00123    {"prefix_column",  STR_PARAM, &prefix_column.s},
00124    {"domain_column",  STR_PARAM, &domain_column.s},
00125    {"prefix",         STR_PARAM, &prefix.s},
00126    {"char_list",      STR_PARAM, &pdt_char_list.s},
00127    {"fetch_rows",     INT_PARAM, &pdt_fetch_rows},
00128    {"check_domain",   INT_PARAM, &pdt_check_domain},
00129    {0, 0, 0}
00130 };
00131 
00132 static mi_export_t mi_cmds[] = {
00133    { "pdt_add",     pdt_mi_add,     0,  0,  child_init },
00134    { "pdt_reload",  pdt_mi_reload,  0,  0,  0 },
00135    { "pdt_delete",  pdt_mi_delete,  0,  0,  0 },
00136    { "pdt_list",    pdt_mi_list,    0,  0,  0 },
00137    { 0, 0, 0, 0, 0}
00138 };
00139 
00140 
00141 struct module_exports exports = {
00142    "pdt",
00143    DEFAULT_DLFLAGS, /* dlopen flags */
00144    cmds,
00145    params,
00146    0,
00147    mi_cmds,        /* exported MI functions */
00148    0,              /* exported pseudo-variables */
00149    0,              /* extra processes */
00150    mod_init,       /* module initialization function */
00151    0,              /* response function */
00152    mod_destroy,    /* destroy function */
00153    mod_child_init  /* per child init function */
00154 };
00155 
00156 
00157 
00158 /**
00159  * init module function
00160  */
00161 static int mod_init(void)
00162 {
00163    db_url.len = strlen(db_url.s);
00164    db_table.len = strlen(db_table.s);
00165    sdomain_column.len = strlen(sdomain_column.s);
00166    prefix_column.len = strlen(prefix_column.s);
00167    domain_column.len = strlen(domain_column.s);
00168    prefix.len = strlen(prefix.s);
00169 
00170    if(pdt_fetch_rows<=0)
00171       pdt_fetch_rows = 1000;
00172 
00173    pdt_char_list.len = strlen(pdt_char_list.s);
00174    if(pdt_char_list.len<=0)
00175    {
00176       LM_ERR("invalid pdt char list\n");
00177       return -1;
00178    }
00179    LM_INFO("pdt_char_list=%s \n",pdt_char_list.s);
00180 
00181    /* binding to mysql module */
00182    if(db_bind_mod(&db_url, &pdt_dbf))
00183    {
00184       LM_ERR("database module not found\n");
00185       return -1;
00186    }
00187 
00188    if (!DB_CAPABILITY(pdt_dbf, DB_CAP_ALL))
00189    {
00190       LM_ERR("database module does not "
00191           "implement all functions needed by the module\n");
00192       return -1;
00193    }
00194 
00195    /* open a connection with the database */
00196    db_con = pdt_dbf.init(&db_url);
00197    if(db_con==NULL)
00198    {
00199       LM_ERR("failed to connect to the database\n");        
00200       return -1;
00201    }
00202    
00203    if (pdt_dbf.use_table(db_con, &db_table) < 0)
00204    {
00205       LM_ERR("failed to use_table\n");
00206       goto error1;
00207    }
00208    LM_DBG("database connection opened successfully\n");
00209    
00210    if ( (pdt_lock=lock_alloc())==0) {
00211       LM_CRIT("failed to alloc lock\n");
00212       goto error1;
00213    }
00214    if (lock_init(pdt_lock)==0 ) {
00215       LM_CRIT("failed to init lock\n");
00216       goto error1;
00217    }
00218    
00219    /* tree pointer in shm */
00220    _ptree = (pdt_tree_t**)shm_malloc( sizeof(pdt_tree_t*) );
00221    if (_ptree==0) {
00222       LM_ERR("out of shm mem for pdtree\n");
00223       goto error1;
00224    }
00225    *_ptree=0;
00226 
00227    /* loading all information from database */
00228    if(pdt_load_db()!=0)
00229    {
00230       LM_ERR("cannot load info from database\n");  
00231       goto error1;
00232    }
00233       
00234    pdt_dbf.close(db_con);
00235    db_con = 0;
00236 
00237 #if 0
00238    pdt_print_tree(*_ptree);
00239 #endif
00240 
00241    /* success code */
00242    return 0;
00243 
00244 error1:
00245    if (pdt_lock)
00246    {
00247       lock_destroy( pdt_lock );
00248       lock_dealloc( pdt_lock );
00249       pdt_lock = 0;
00250    }
00251    if(_ptree!=0)
00252       shm_free(_ptree);
00253 
00254    if(db_con!=NULL)
00255    {
00256       pdt_dbf.close(db_con);
00257       db_con = 0;
00258    }
00259    return -1;
00260 }
00261 
00262 
00263 static int child_init(void)
00264 {
00265    db_con = pdt_dbf.init(&db_url);
00266    if(db_con==NULL)
00267    {
00268       LM_ERR("failed to connect to database\n");
00269       return -1;
00270    }
00271 
00272    if (pdt_dbf.use_table(db_con, &db_table) < 0)
00273    {
00274       LM_ERR("use_table failed\n");
00275       return -1;
00276    }
00277    return 0;
00278 }
00279 
00280 
00281 /* each child get a new connection to the database */
00282 static int mod_child_init(int r)
00283 {
00284    if ( child_init()!=0 )
00285       return -1;
00286 
00287    LM_DBG("#%d: database connection opened successfully\n",r);
00288 
00289    return 0;
00290 }
00291 
00292 
00293 static void mod_destroy(void)
00294 {
00295    LM_DBG("cleaning up\n");
00296    if (_ptree!=NULL)
00297    {
00298       if (*_ptree!=NULL)
00299          pdt_free_tree(*_ptree);
00300       shm_free(_ptree);
00301    }
00302    if (db_con!=NULL && pdt_dbf.close!=NULL)
00303       pdt_dbf.close(db_con);
00304       /* destroy lock */
00305    if (pdt_lock)
00306    {
00307       lock_destroy( pdt_lock );
00308       lock_dealloc( pdt_lock );
00309       pdt_lock = 0;
00310    }
00311 
00312 }
00313 
00314 
00315 static int w_prefix2domain(struct sip_msg* msg, char* str1, char* str2)
00316 {
00317    return prefix2domain(msg, 0, 0);
00318 }
00319 
00320 static int w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2)
00321 {
00322    int m;
00323 
00324    if(fixup_get_ivalue(msg, (gparam_p)mode, &m)!=0)
00325    {
00326       LM_ERR("no mode value\n");
00327       return -1;
00328    }
00329 
00330    if(m!=1 && m!=2)
00331       m = 0;
00332 
00333    return prefix2domain(msg, m, 0);
00334 }
00335 
00336 static int w_prefix2domain_2(struct sip_msg* msg, char* mode, char* sdm)
00337 {
00338    int m, s;
00339 
00340    if(fixup_get_ivalue(msg, (gparam_p)mode, &m)!=0)
00341    {
00342       LM_ERR("no mode value\n");
00343       return -1;
00344    }
00345 
00346    if(m!=1 && m!=2)
00347       m = 0;
00348 
00349    if(fixup_get_ivalue(msg, (gparam_p)sdm, &s)!=0)
00350    {
00351       LM_ERR("no multi-domain mode value\n");
00352       return -1;
00353    }
00354 
00355    if(s!=1 && s!=2)
00356       s = 0;
00357 
00358    return prefix2domain(msg, m, s);
00359 }
00360 
00361 /* change the r-uri if it is a PSTN format */
00362 static int prefix2domain(struct sip_msg* msg, int mode, int sd_en)
00363 {
00364    str *d, p, all={"*",1};
00365    int plen;
00366    struct sip_uri uri;
00367    
00368    if(msg==NULL)
00369    {
00370       LM_ERR("received null msg\n");
00371       return -1;
00372    }
00373    
00374    /* parse the uri, if not yet */
00375    if(msg->parsed_uri_ok==0)
00376       if(parse_sip_msg_uri(msg)<0)
00377       {
00378          LM_ERR("failed to parse the R-URI\n");
00379          return -1;
00380       }
00381 
00382     /* if the user part begin with the prefix for PSTN users, extract the code*/
00383    if (msg->parsed_uri.user.len<=0)
00384    {
00385       LM_DBG("user part of the message is empty\n");
00386       return -1;
00387    }   
00388     
00389    if(prefix.len>0)
00390    {
00391       if (msg->parsed_uri.user.len<=prefix.len)
00392       {
00393          LM_DBG("user part is less than prefix\n");
00394          return -1;
00395       }   
00396       if(strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0)
00397       {
00398          LM_DBG("PSTN prefix did not matched\n");
00399          return -1;
00400       }
00401    }   
00402    
00403    if(prefix.len>0 && prefix.len < msg->parsed_uri.user.len
00404          && strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0)
00405    {
00406       LM_DBG("PSTN prefix did not matched\n");
00407       return -1;
00408          
00409    }
00410 
00411    p.s   = msg->parsed_uri.user.s + prefix.len;
00412    p.len = msg->parsed_uri.user.len - prefix.len;
00413 
00414 again:
00415    lock_get( pdt_lock );
00416    if (pdt_reload_flag) {
00417       lock_release( pdt_lock );
00418       sleep_us(5);
00419       goto again;
00420    }
00421    pdt_tree_refcnt++;
00422    lock_release( pdt_lock );
00423 
00424    if(sd_en==2)
00425    {  
00426       /* take the domain from  FROM uri as sdomain */
00427       if(parse_from_header(msg)<0 ||  msg->from == NULL 
00428             || get_from(msg)==NULL)
00429       {
00430          LM_ERR("cannot parse FROM header\n");
00431          goto error;
00432       }  
00433       
00434       memset(&uri, 0, sizeof(struct sip_uri));
00435       if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0)
00436       {
00437          LM_ERR("failed to parse From uri\n");
00438          goto error;
00439       }
00440    
00441       /* find the domain that corresponds to this prefix */
00442       plen = 0;
00443       if((d=pdt_get_domain(*_ptree, &uri.host, &p, &plen))==NULL)
00444       {
00445          plen = 0;
00446          if((d=pdt_get_domain(*_ptree, &all, &p, &plen))==NULL)
00447          {
00448             LM_INFO("no prefix found in [%.*s]\n", p.len, p.s);
00449             goto error;
00450          }
00451       }
00452    } else if(sd_en==1) {   
00453       /* take the domain from  FROM uri as sdomain */
00454       if(parse_from_header(msg)<0 ||  msg->from == NULL
00455             || get_from(msg)==NULL)
00456       {
00457          LM_ERR("ERROR cannot parse FROM header\n");
00458          goto error;
00459       }  
00460       
00461       memset(&uri, 0, sizeof(struct sip_uri));
00462       if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0)
00463       {
00464          LM_ERR("failed to parse From uri\n");
00465          goto error;
00466       }
00467    
00468       /* find the domain that corresponds to this prefix */
00469       plen = 0;
00470       if((d=pdt_get_domain(*_ptree, &uri.host, &p, &plen))==NULL)
00471       {
00472          LM_INFO("no prefix found in [%.*s]\n", p.len, p.s);
00473          goto error;
00474       }
00475    } else {
00476       /* find the domain that corresponds to this prefix */
00477       plen = 0;
00478       if((d=pdt_get_domain(*_ptree, &all, &p, &plen))==NULL)
00479       {
00480          LM_INFO("no prefix found in [%.*s]\n", p.len, p.s);
00481          goto error;
00482       }
00483    }
00484    
00485    /* update the new uri */
00486    if(update_new_uri(msg, plen, d, mode)<0)
00487    {
00488       LM_ERR("new_uri cannot be updated\n");
00489       goto error;
00490    }
00491 
00492    lock_get( pdt_lock );
00493    pdt_tree_refcnt--;
00494    lock_release( pdt_lock );
00495    return 1;
00496 
00497 error:
00498    lock_get( pdt_lock );
00499    pdt_tree_refcnt--;
00500    lock_release( pdt_lock );
00501    return -1;
00502 }
00503 
00504 /* change the uri according to translation of the prefix */
00505 static int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode)
00506 {
00507    struct action act;
00508    if(msg==NULL || d==NULL)
00509    {
00510       LM_ERR("bad parameters\n");
00511       return -1;
00512    }
00513    
00514    if(mode==0 || (mode==1 && prefix.len>0))
00515    {
00516       act.type = STRIP_T;
00517       act.elem[0].type = NUMBER_ST;
00518       if(mode==0)
00519          act.elem[0].u.number = plen + prefix.len;
00520       else
00521          act.elem[0].u.number = prefix.len;
00522       act.next = 0;
00523 
00524       if (do_action(&act, msg) < 0)
00525       {
00526          LM_ERR("failed to remove prefix\n");
00527          return -1;
00528       }
00529    }
00530    
00531    act.type = SET_HOSTPORT_T;
00532    act.elem[0].type = STRING_ST;
00533    act.elem[0].u.string = d->s;
00534    act.next = 0;
00535 
00536    if (do_action(&act, msg) < 0)
00537    {
00538       LM_ERR("failed to change domain\n");
00539       return -1;
00540    }
00541 
00542    LM_DBG("len=%d uri=%.*s\n", msg->new_uri.len, 
00543          msg->new_uri.len, msg->new_uri.s);
00544    
00545    return 0;
00546 }
00547 
00548 static int pdt_load_db(void)
00549 {
00550    db_key_t db_cols[3] = {&sdomain_column, &prefix_column, &domain_column};
00551    str p, d, sdomain;
00552    db_res_t* db_res = NULL;
00553    int i, ret;
00554    pdt_tree_t *_ptree_new = NULL; 
00555    pdt_tree_t *old_tree = NULL; 
00556 
00557    if(db_con==NULL)
00558    {
00559       LM_ERR("no db connection\n");
00560       return -1;
00561    }
00562       
00563    if (pdt_dbf.use_table(db_con, &db_table) < 0)
00564    {
00565       LM_ERR("failed to use_table\n");
00566       return -1;
00567    }
00568 
00569    if (DB_CAPABILITY(pdt_dbf, DB_CAP_FETCH)) {
00570       if(pdt_dbf.query(db_con,0,0,0,db_cols,0,3,&sdomain_column,0) < 0)
00571       {
00572          LM_ERR("Error while querying db\n");
00573          return -1;
00574       }
00575       if(pdt_dbf.fetch_result(db_con, &db_res, pdt_fetch_rows)<0)
00576       {
00577          LM_ERR("Error while fetching result\n");
00578          if (db_res)
00579             pdt_dbf.free_result(db_con, db_res);
00580          goto error;
00581       } else {
00582          if(RES_ROW_N(db_res)==0)
00583          {
00584             return 0;
00585          }
00586       }
00587    } else {
00588       if((ret=pdt_dbf.query(db_con, NULL, NULL, NULL, db_cols,
00589             0, 3, &sdomain_column, &db_res))!=0
00590          || RES_ROW_N(db_res)<=0 )
00591       {
00592          pdt_dbf.free_result(db_con, db_res);
00593          if( ret==0)
00594          {
00595             return 0;
00596          } else {
00597             goto error;
00598          }
00599       }
00600    }
00601 
00602    do {
00603       for(i=0; i<RES_ROW_N(db_res); i++)
00604       {
00605          /* check for NULL values ?!?! */
00606          sdomain.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
00607          sdomain.len = strlen(sdomain.s);
00608 
00609          p.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val);
00610          p.len = strlen(p.s);
00611          
00612          d.s = (char*)(RES_ROWS(db_res)[i].values[2].val.string_val);
00613          d.len = strlen(d.s);
00614 
00615          if(p.s==NULL || d.s==NULL || sdomain.s==NULL ||
00616                p.len<=0 || d.len<=0 || sdomain.len<=0)
00617          {
00618             LM_ERR("Error - bad values in db\n");
00619             continue;
00620          }
00621       
00622          if(pdt_check_domain!=0 && _ptree_new!=NULL
00623                && pdt_check_pd(_ptree_new, &sdomain, &p, &d)==1)
00624          {
00625             LM_ERR("sdomain [%.*s]: prefix [%.*s] or domain <%.*s> "
00626                "duplicated\n", sdomain.len, sdomain.s, p.len, p.s,
00627                d.len, d.s);
00628             continue;
00629          }
00630 
00631          if(pdt_add_to_tree(&_ptree_new, &sdomain, &p, &d)<0)
00632          {
00633             LM_ERR("Error adding info to tree\n");
00634             goto error;
00635          }
00636       }
00637       if (DB_CAPABILITY(pdt_dbf, DB_CAP_FETCH)) {
00638          if(pdt_dbf.fetch_result(db_con, &db_res, pdt_fetch_rows)<0) {
00639             LM_ERR("Error while fetching!\n");
00640             if (db_res)
00641                pdt_dbf.free_result(db_con, db_res);
00642             goto error;
00643          }
00644       } else {
00645          break;
00646       }
00647    }  while(RES_ROW_N(db_res)>0);
00648    pdt_dbf.free_result(db_con, db_res);
00649 
00650 
00651    /* block all readers */
00652    lock_get( pdt_lock );
00653    pdt_reload_flag = 1;
00654    lock_release( pdt_lock );
00655 
00656    while (pdt_tree_refcnt) {
00657       sleep_us(10);
00658    }
00659 
00660    old_tree = *_ptree;
00661    *_ptree = _ptree_new;
00662 
00663    pdt_reload_flag = 0;
00664 
00665    /* free old data */
00666    if (old_tree!=NULL)
00667       pdt_free_tree(old_tree);
00668 
00669    return 0;
00670 
00671 error:
00672    pdt_dbf.free_result(db_con, db_res);
00673    if (_ptree_new!=NULL)
00674       pdt_free_tree(_ptree_new);
00675    return -1;
00676 }
00677 
00678 /**************************** MI ***************************/
00679 
00680 /**
00681  * "pdt_reload" syntax :
00682  * \n
00683  */
00684 static struct mi_root* pdt_mi_reload(struct mi_root *cmd_tree, void *param)
00685 {
00686    /* re-loading all information from database */
00687    if(pdt_load_db()!=0)
00688    {
00689       LM_ERR("cannot re-load info from database\n");  
00690       goto error;
00691    }
00692    
00693    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00694 
00695 error:
00696    return init_mi_tree( 500, "Failed to reload",16);
00697 }
00698 
00699 
00700 
00701 /**
00702  * "pdt_add" syntax :
00703  *   sdomain
00704  *   prefix
00705  *   domain
00706  */
00707 struct mi_root* pdt_mi_add(struct mi_root* cmd_tree, void* param)
00708 {
00709    db_key_t db_keys[NR_KEYS] = {&sdomain_column, &prefix_column, &domain_column};
00710    db_val_t db_vals[NR_KEYS];
00711    db_op_t  db_ops[NR_KEYS] = {OP_EQ, OP_EQ};
00712    int i= 0;
00713    str sd, sp, sdomain;
00714    struct mi_node* node= NULL;
00715 
00716    if(_ptree==NULL)
00717    {
00718       LM_ERR("strange situation\n");
00719       return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
00720    }
00721 
00722    /* read sdomain */
00723    node = cmd_tree->node.kids;
00724    if(node == NULL)
00725       goto error1;
00726 
00727    sdomain = node->value;
00728    if(sdomain.s == NULL || sdomain.len== 0)
00729       return init_mi_tree( 404, "domain not found", 16);
00730 
00731    if(*sdomain.s=='.' )
00732        return init_mi_tree( 400, "empty param",11);
00733 
00734    /* read prefix */
00735    node = node->next;
00736    if(node == NULL)
00737       goto error1;
00738 
00739    sp= node->value;
00740    if(sp.s== NULL || sp.len==0)
00741    {
00742       LM_ERR("could not read prefix\n");
00743       return init_mi_tree( 404, "prefix not found", 16);
00744    }
00745 
00746    if(*sp.s=='.')
00747        return init_mi_tree(400, "empty param", 11);
00748 
00749    while(i< sp.len)
00750    {
00751       if(strpos(pdt_char_list.s,sp.s[i]) < 0) 
00752          return init_mi_tree(400, "bad prefix", 10);
00753       i++;
00754    }
00755 
00756    /* read domain */
00757    node= node->next;
00758    if(node == NULL || node->next!=NULL)
00759       goto error1;
00760 
00761    sd= node->value;
00762    if(sd.s== NULL || sd.len==0)
00763    {
00764       LM_ERR("could not read domain\n");
00765       return init_mi_tree( 400, "domain not found", 16);
00766    }
00767 
00768    if(*sd.s=='.')
00769        return init_mi_tree(400, "empty param", 11);
00770 
00771    
00772    if(pdt_check_domain!=0 && *_ptree!=NULL
00773          && pdt_check_pd(*_ptree, &sdomain, &sp, &sd)==1)
00774    {
00775       LM_ERR("(sdomain,prefix,domain) exists\n");
00776       return init_mi_tree(400,
00777             "(sdomain,prefix,domain) exists already", 38);
00778    }
00779    db_vals[0].type = DB_STR;
00780    db_vals[0].nul = 0;
00781    db_vals[0].val.str_val.s = sdomain.s;
00782    db_vals[0].val.str_val.len = sdomain.len;
00783 
00784    db_vals[1].type = DB_STR;
00785    db_vals[1].nul = 0;
00786    db_vals[1].val.str_val.s = sp.s;
00787    db_vals[1].val.str_val.len = sp.len;
00788 
00789    db_vals[2].type = DB_STR;
00790    db_vals[2].nul = 0;
00791    db_vals[2].val.str_val.s = sd.s;
00792    db_vals[2].val.str_val.len = sd.len;
00793    
00794    /* insert a new domain into database */
00795    if(pdt_dbf.insert(db_con, db_keys, db_vals, NR_KEYS)<0)
00796    {
00797       LM_ERR("failed to store new prefix/domain\n");
00798       return init_mi_tree( 500,"Cannot store prefix/domain", 26);
00799    }
00800 
00801    /* re-loading all information from database */
00802    if(pdt_load_db()!=0)
00803    {
00804       LM_ERR("cannot re-load info from database\n");  
00805       goto error;
00806    }
00807    
00808    LM_DBG("new prefix added %.*s-%.*s => %.*s\n",
00809          sdomain.len, sdomain.s, sp.len, sp.s, sd.len, sd.s);
00810    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00811 
00812    
00813 error:
00814    if(pdt_dbf.delete(db_con, db_keys, db_ops, db_vals, NR_KEYS)<0)
00815       LM_ERR("database/cache are inconsistent\n");
00816    return init_mi_tree( 500, "could not add to cache", 23 );
00817 
00818 error1:
00819    return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00820 
00821 }
00822 
00823 /**
00824  * "pdt_delete" syntax:
00825  *    sdomain
00826  *    domain
00827  */
00828 struct mi_root* pdt_mi_delete(struct mi_root* cmd_tree, void* param)
00829 {
00830    str sd, sdomain;
00831    struct mi_node* node= NULL;
00832    db_key_t db_keys[2] = {&sdomain_column, &domain_column};
00833    db_val_t db_vals[2];
00834    db_op_t  db_ops[2] = {OP_EQ, OP_EQ};
00835 
00836    /* read sdomain */
00837    node = cmd_tree->node.kids;
00838    if(node == NULL)
00839       goto error;
00840 
00841    sdomain = node->value;
00842    if(sdomain.s == NULL || sdomain.len== 0)
00843       return init_mi_tree( 404, "domain not found", 16);
00844 
00845    if( *sdomain.s=='.' )
00846        return init_mi_tree( 400, "400 empty param",11);
00847 
00848    /* read domain */
00849    node= node->next;
00850    if(node == NULL || node->next!=NULL)
00851       goto error;
00852 
00853    sd= node->value;
00854    if(sd.s== NULL || sd.len==0)
00855    {
00856       LM_ERR("could not read domain\n");
00857       return init_mi_tree(404, "domain not found", 16);
00858    }
00859 
00860    if(*sd.s=='.')
00861        return init_mi_tree( 400, "empty param", 11);
00862 
00863 
00864    db_vals[0].type = DB_STR;
00865    db_vals[0].nul = 0;
00866    db_vals[0].val.str_val.s = sdomain.s;
00867    db_vals[0].val.str_val.len = sdomain.len;
00868    
00869    db_vals[1].type = DB_STR;
00870    db_vals[1].nul = 0;
00871    db_vals[1].val.str_val.s = sd.s;
00872    db_vals[1].val.str_val.len = sd.len;
00873 
00874    if(pdt_dbf.delete(db_con, db_keys, db_ops, db_vals, 2)<0)
00875    {
00876       LM_ERR("database/cache are inconsistent\n");
00877       return init_mi_tree( 500, "database/cache are inconsistent", 31 );
00878    } 
00879    /* re-loading all information from database */
00880    if(pdt_load_db()!=0)
00881    {
00882       LM_ERR("cannot re-load info from database\n");  
00883       return init_mi_tree( 500, "cannot reload", 13 );
00884    }
00885 
00886    LM_DBG("prefix for sdomain [%.*s] domain [%.*s] "
00887          "removed\n", sdomain.len, sdomain.s, sd.len, sd.s);
00888    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00889 error:
00890    return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00891 }
00892 
00893 
00894 int pdt_print_mi_node(pdt_node_t *pt, struct mi_node* rpl, char *code,
00895       int len, str *sdomain, str *sd, str *sp)
00896 {
00897    int i;
00898    struct mi_node* node = NULL;
00899    struct mi_attr* attr= NULL;
00900 
00901    if(pt==NULL || len>=PDT_MAX_DEPTH)
00902       return 0;
00903    
00904    for(i=0; i<PDT_NODE_SIZE; i++)
00905    {
00906       code[len]=pdt_char_list.s[i];
00907       if(pt[i].domain.s!=NULL)
00908       {
00909          if((sp->s==NULL && sd->s==NULL)
00910             || (sp->s==NULL && (sd->s!=NULL && pt[i].domain.len==sd->len
00911                   && strncasecmp(pt[i].domain.s, sd->s, sd->len)==0)) 
00912             || (sd->s==NULL && (len+1>=sp->len
00913                   && strncmp(code, sp->s, sp->len)==0))
00914             || ((sp->s!=NULL && len+1>=sp->len
00915                   && strncmp(code, sp->s, sp->len)==0)
00916                   && (sd->s!=NULL && pt[i].domain.len>=sd->len
00917                   && strncasecmp(pt[i].domain.s, sd->s, sd->len)==0)))
00918          {
00919             node = add_mi_node_child(rpl, 0, "PDT", 3, 0, 0);
00920             if(node == NULL)
00921                goto error;
00922 
00923             attr = add_mi_attr(node, MI_DUP_VALUE, "SDOMAIN", 7,
00924                   sdomain->s, sdomain->len);
00925             if(attr == NULL)
00926                goto error;
00927             attr = add_mi_attr(node, MI_DUP_VALUE, "PREFIX", 6,
00928                      code, len+1);
00929             if(attr == NULL)
00930                goto error;
00931                   
00932             attr = add_mi_attr(node, MI_DUP_VALUE,"DOMAIN", 6,
00933                      pt[i].domain.s, pt[i].domain.len);
00934             if(attr == NULL)
00935                goto error;
00936          }
00937       }
00938       if(pdt_print_mi_node(pt[i].child, rpl, code, len+1, sdomain, sd, sp)<0)
00939          goto error;
00940    }
00941    return 0;
00942 error:
00943    return -1;
00944 }
00945 
00946 /**
00947  * "pdt_list" syntax :
00948  *    sdomain
00949  *    prefix
00950  *    domain
00951  *
00952  *    - '.' (dot) means NULL value and will match anything
00953  *    - the comparison operation is 'START WITH' -- if domain is 'a' then
00954  *      all domains starting with 'a' are listed
00955  *
00956  *      Examples
00957  *      pdt_list o 2 .    - lists the entries where sdomain is starting with 'o', 
00958  *                          prefix is starting with '2' and domain is anything
00959  *      
00960  *      pdt_list . 2 open - lists the entries where sdomain is anything, prefix 
00961  *                          starts with '2' and domain starts with 'open'
00962  */
00963 
00964 struct mi_root* pdt_mi_list(struct mi_root* cmd_tree, void* param)
00965 {
00966    str sd, sp, sdomain;
00967    pdt_tree_t *pt;
00968    struct mi_node* node = NULL;
00969    unsigned int i= 0;
00970    struct mi_root* rpl_tree = NULL;
00971    struct mi_node* rpl = NULL;
00972    static char code_buf[PDT_MAX_DEPTH+1];
00973    int len;
00974 
00975    if(_ptree==NULL)
00976    {
00977       LM_ERR("empty domain list\n");
00978       return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
00979    }
00980 
00981    /* read sdomain */
00982    sdomain.s = 0;
00983    sdomain.len = 0;
00984    sp.s = 0;
00985    sp.len = 0;
00986    sd.s = 0;
00987    sd.len = 0;
00988    node = cmd_tree->node.kids;
00989    if(node != NULL)
00990    {
00991       sdomain = node->value;
00992       if(sdomain.s == NULL || sdomain.len== 0)
00993          return init_mi_tree( 404, "domain not found", 16);
00994 
00995       if(*sdomain.s=='.')
00996          sdomain.s = 0;
00997 
00998       /* read prefix */
00999       node = node->next;
01000       if(node != NULL)
01001       {
01002          sp= node->value;
01003          if(sp.s== NULL || sp.len==0 || *sp.s=='.')
01004             sp.s = NULL;
01005          else {
01006             while(sp.s!=NULL && i!=sp.len)
01007             {
01008                if(strpos(pdt_char_list.s,sp.s[i]) < 0)
01009                {
01010                   LM_ERR("bad prefix [%.*s]\n", sp.len, sp.s);
01011                   return init_mi_tree( 400, "bad prefix", 10);
01012                }
01013                i++;
01014             }
01015          }
01016 
01017          /* read domain */
01018          node= node->next;
01019          if(node != NULL)
01020          {
01021             sd= node->value;
01022             if(sd.s== NULL || sd.len==0 || *sd.s=='.')
01023                sd.s = NULL;
01024          }
01025       }
01026    }
01027 
01028    rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
01029    if(rpl_tree == NULL)
01030       return 0;
01031    rpl = &rpl_tree->node;
01032 
01033    if(*_ptree==0)
01034       return rpl_tree;
01035 
01036    pt = *_ptree;
01037    
01038    while(pt!=NULL)
01039    {
01040       if(sdomain.s==NULL || 
01041          (sdomain.s!=NULL && pt->sdomain.len>=sdomain.len && 
01042           strncmp(pt->sdomain.s, sdomain.s, sdomain.len)==0))
01043       {
01044          len = 0;
01045          if(pdt_print_mi_node(pt->head, rpl, code_buf, len, &pt->sdomain,
01046                   &sd, &sp)<0)
01047             goto error;
01048       }
01049       pt = pt->next;
01050    }
01051    
01052    return rpl_tree;
01053 
01054 error:
01055    free_mi_tree(rpl_tree);
01056    return 0;
01057 }
01058 

Generated on Thu May 24 02:00:29 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6