modules_s/pdt/pdt.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2001-2003 FhG FOKUS
00005  * Copyright (C) 2008 iptelorg GmbH
00006  *
00007  * This file is part of ser, a free SIP server.
00008  *
00009  * ser is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * For a license to use the ser software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact iptel.org by e-mail at the following addresses:
00017  *    info@iptel.org
00018  *
00019  * ser is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027  *
00028  * History:
00029  * -------
00030  * 2003-04-07: a structure for both hashes introduced (ramona)
00031  * 2003-04-06: db connection closed in mod_init (janakj)
00032  * 2004-06-07: updated to the new DB api (andrei)
00033  * 2005-01-26: removed terminating code (ramona)
00034  *             prefix hash replaced with tree (ramona)
00035  *             FIFO commands to add/list/delete prefix domains (ramona)
00036  *             pdt cache per process for fast translation (ramona)
00037  */
00038 
00039 /*
00040  * Prefix-Domains Translation - ser module
00041  * Ramona Modroiu
00042  */
00043 
00044 #include <stdio.h>
00045 #include <unistd.h>
00046 #include <stdlib.h>
00047 
00048 #include "../../sr_module.h"
00049 #include "../../lib/srdb2/db.h"
00050 #include "../../mem/shm_mem.h"
00051 #include "../../mem/mem.h"
00052 #include "../../dprint.h"
00053 #include "../../parser/parse_uri.h"
00054 #include "../../timer.h"
00055 #include "../../ut.h"
00056 #include "../../rpc.h"
00057 #include "../../action.h"
00058 
00059 #include "domains.h"
00060 #include "pdtree.h"
00061 
00062 MODULE_VERSION
00063 
00064 
00065 #define NR_KEYS                 2
00066 
00067 int hs_two_pow = 2;
00068 
00070 pdt_hash_t *_dhash = NULL;
00071 pdt_tree_t *_ptree = NULL;
00072 
00073 time_t last_sync;
00074 
00076 static db_ctx_t* ctx = NULL;
00077 static db_cmd_t* db_load = NULL;
00078 static db_cmd_t* db_insert = NULL;
00079 static db_cmd_t* db_delete = NULL;
00080 static db_cmd_t* db_del_domain = NULL;
00081 
00082 
00084 static char *db_url = DEFAULT_DB_URL;
00085 char *db_table = "pdt";
00086 char *prefix_column = "prefix";
00087 char *domain_column = "domain";
00088 
00090 str prefix = STR_STATIC_INIT("");
00091 int sync_time = 600;
00092 int clean_time = 900;
00093 
00094 static int w_prefix2domain(struct sip_msg* msg, char* str1, char* str2);
00095 static int w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2);
00096 static int mod_init(void);
00097 static void mod_destroy(void);
00098 static int  child_init(int r);
00099 
00100 static int prefix2domain(struct sip_msg*, int mode);
00101 
00102 int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode);
00103 int pdt_load_db();
00104 int pdt_sync_cache();
00105 void pdt_clean_cache(unsigned int ticks, void *param);
00106 
00107 static rpc_export_t pdt_rpc[];
00108 
00109 static cmd_export_t cmds[]={
00110         {"prefix2domain", w_prefix2domain,   0, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00111         {"prefix2domain", w_prefix2domain_1, 1, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00112         {0, 0, 0, 0, 0}
00113 };
00114 
00115 static param_export_t params[]={
00116         {"db_url",        PARAM_STRING, &db_url},
00117         {"db_table",      PARAM_STRING, &db_table},
00118         {"prefix_column", PARAM_STRING, &prefix_column},
00119         {"domain_column", PARAM_STRING, &domain_column},
00120         {"prefix",        PARAM_STR,    &prefix},
00121         {"hsize_2pow",    PARAM_INT,    &hs_two_pow},
00122         {"sync_time",     PARAM_INT,    &sync_time},
00123         {"clean_time",    PARAM_INT,    &clean_time},
00124         {0, 0, 0}
00125 };
00126 
00127 struct module_exports exports = {
00128         "pdt",
00129         cmds,
00130         pdt_rpc,         /* RPC methods */
00131         params,
00132 
00133         mod_init,               /* module initialization function */
00134         0,                              /* response function */
00135         mod_destroy,    /* destroy function */
00136         0,                              /* oncancel function */
00137         child_init              /* per child init function */
00138 };
00139 
00140 
00141 static void pdt_db_close(void)
00142 {
00143         if (db_load) db_cmd_free(db_load);
00144         db_load = NULL;
00145 
00146         if (db_insert) db_cmd_free(db_insert);
00147         db_insert = NULL;
00148 
00149         if (db_delete) db_cmd_free(db_delete);
00150         db_delete = NULL;
00151 
00152         if (db_del_domain) db_cmd_free(db_del_domain);
00153         db_del_domain = NULL;
00154 
00155         if (ctx) {
00156                 db_disconnect(ctx);
00157                 db_ctx_free(ctx);
00158                 ctx = NULL;
00159         }
00160 }
00161 
00162 
00163 static int pdt_db_init(void)
00164 {
00165         db_fld_t fields[] = {
00166                 {.name = prefix_column, .type = DB_STR},
00167                 {.name = domain_column, .type = DB_STR},
00168                 {.name = 0}
00169         };
00170         
00171         db_fld_t del_dom_param[] = {
00172                 {.name = domain_column, .type = DB_STR},
00173                 {.name = 0}
00174         };
00175 
00176         ctx = db_ctx("pdt");
00177         if (!ctx) goto error;
00178         if (db_add_db(ctx, db_url) < 0) goto error;
00179         if (db_connect(ctx) < 0) goto error;
00180 
00181         db_load = db_cmd(DB_GET, ctx, db_table, fields, NULL, NULL);
00182         if (!db_load) goto error;
00183 
00184         db_insert = db_cmd(DB_PUT, ctx, db_table, NULL, NULL, fields);
00185         if (!db_insert) goto error;
00186 
00187         db_delete = db_cmd(DB_DEL, ctx, db_table, NULL, fields, NULL);
00188         if (!db_delete) goto error;
00189 
00190         db_del_domain = db_cmd(DB_DEL, ctx, db_table, NULL, del_dom_param, NULL);
00191         if (!db_del_domain) goto error;
00192 
00193     return 0;
00194 
00195 error:
00196         pdt_db_close();
00197         ERR("pdt: Error while initializing database layer\n");
00198         return -1;
00199 }
00200 
00201 
00202 
00203 /*
00204  * init module function
00205  */
00206 static int mod_init(void)
00207 {
00208         DBG("PDT: initializing...\n");
00209 
00210         if(hs_two_pow<0)
00211         {
00212                 LOG(L_ERR, "PDT:mod_init: hash_size_two_pow must be"
00213                                         " positive and less than %d\n", MAX_HSIZE_TWO_POW);
00214                 return -1;
00215         }
00216 
00217         prefix.len = strlen(prefix.s);
00218 
00219 
00220         if (pdt_db_init() < 0) return -1;
00221 
00222         /* init the hash and tree in share memory */
00223         if( (_dhash = pdt_init_hash(hs_two_pow)) == NULL)
00224         {
00225                 LOG(L_ERR, "PDT:mod_init: domain hash could not be allocated\n");
00226                 goto error1;
00227         }
00228 
00229         if( (_ptree = pdt_init_tree()) == NULL)
00230         {
00231                 LOG(L_ERR, "PDT:mod_init: prefix tree could not be allocated\n");
00232                 goto error2;
00233         }
00234 
00235         /* loading all information from database */
00236         if(pdt_load_db()!=0)
00237         {
00238                 LOG(L_ERR, "PDT:mod_init: cannot load info from database\n");
00239                 goto error3;
00240         }
00241 
00242         pdt_db_close();
00243 
00244         pdt_print_tree(_ptree);
00245         DBG("PDT:mod_init: -------------------\n");
00246         pdt_print_hash(_dhash);
00247 
00248         last_sync = time(NULL);
00249 
00250         register_timer(pdt_clean_cache, 0, clean_time);
00251 
00252         /* success code */
00253         return 0;
00254 
00255  error3:
00256         if(_ptree!=NULL)
00257         {
00258                 pdt_free_tree(_ptree);
00259                 _ptree = 0;
00260         }
00261  error2:
00262         if(_dhash!=NULL)
00263         {
00264                 pdt_free_hash(_dhash);
00265                 _dhash = 0;
00266         }
00267  error1:
00268         pdt_db_close();
00269         return -1;
00270 }
00271 
00272 /* each child get a new connection to the database */
00273 static int child_init(int rank)
00274 {
00275         DBG("PDT:child_init #%d / pid <%d>\n", rank, getpid());
00276 
00277         if(rank>0)
00278         {
00279                 if(_dhash==NULL)
00280                 {
00281                         LOG(L_ERR,"PDT:child_init #%d: ERROR no domain hash\n", rank);
00282                         return -1;
00283                 }
00284 
00285                 lock_get(&_dhash->diff_lock);
00286                 _dhash->workers++;
00287                 lock_release(&_dhash->diff_lock);
00288         } else {
00289                 if(_ptree!=NULL)
00290                 {
00291                         pdt_free_tree(_ptree);
00292                         _ptree = 0;
00293                 }
00294         }
00295 
00296         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00297                 return 0; /* do nothing for the main or tcp_main processes */
00298 
00299         if (pdt_db_init() < 0) return -1;
00300 
00301         if(sync_time<=0)
00302                 sync_time = 300;
00303         sync_time += rank%60;
00304 
00305         DBG("PDT:child_init #%d: Database connection opened successfully\n",rank);
00306 
00307         return 0;
00308 }
00309 
00310 static void mod_destroy(void)
00311 {
00312         DBG("PDT: mod_destroy : Cleaning up\n");
00313         if (_dhash!=NULL)
00314                 pdt_free_hash(_dhash);
00315         if (_ptree!=NULL)
00316                 pdt_free_tree(_ptree);
00317 
00318         pdt_db_close();
00319 }
00320 
00321 
00322 static int w_prefix2domain(struct sip_msg* msg, char* str1, char* str2)
00323 {
00324         return prefix2domain(msg, 0);
00325 }
00326 
00327 static int w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2)
00328 {
00329         if(mode!=NULL && *mode=='1')
00330                 return prefix2domain(msg, 1);
00331         else if(mode!=NULL && *mode=='2')
00332                         return prefix2domain(msg, 2);
00333         else return prefix2domain(msg, 0);
00334 }
00335 
00336 /* change the r-uri if it is a PSTN format */
00337 static int prefix2domain(struct sip_msg* msg, int mode)
00338 {
00339         str p;
00340         str *d;
00341         time_t crt_time;
00342         int plen;
00343 
00344         if(msg==NULL)
00345         {
00346                 LOG(L_ERR,"PDT:prefix2domain: weird error\n");
00347                 return -1;
00348         }
00349 
00350         /* parse the uri, if not yet */
00351         if(msg->parsed_uri_ok==0)
00352                 if(parse_sip_msg_uri(msg)<0)
00353                 {
00354                         LOG(L_ERR,"PDT:prefix2domain: ERROR while parsing the R-URI\n");
00355                         return -1;
00356                 }
00357 
00358         /* if the user part begin with the prefix for PSTN users, extract the code*/
00359         if (msg->parsed_uri.user.len<=0)
00360         {
00361                 DBG("PDT:prefix2domain: user part of the message is empty\n");
00362                 return 1;
00363         }
00364 
00365         if(prefix.len>0 && prefix.len < msg->parsed_uri.user.len
00366                         && strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0)
00367         {
00368                 DBG("PDT:prefix2domain: PSTN prefix did not matched\n");
00369                 return 1;
00370 
00371         }
00372 
00373         p.s   = msg->parsed_uri.user.s + prefix.len;
00374         p.len = msg->parsed_uri.user.len - prefix.len;
00375 
00376         /* check if need for sync */
00377         crt_time = time(NULL);
00378         if(last_sync + sync_time < crt_time)
00379         {
00380                 last_sync = crt_time;
00381                 if(pdt_sync_cache())
00382                 {
00383                         LOG(L_ERR, "PDT:prefix2domain: cannot update the cache\n");
00384                         return -1;
00385                 }
00386         }
00387 
00388         /* find the domain that corresponds to this prefix */
00389         plen = 0;
00390         if((d=pdt_get_domain(_ptree, &p, &plen))==NULL)
00391         {
00392                 LOG(L_INFO, "PDT:prefix2domain: no prefix found in [%.*s]\n",
00393                                 p.len, p.s);
00394                 return -1;
00395         }
00396 
00397         /* update the new uri */
00398         if(update_new_uri(msg, plen, d, mode)<0)
00399         {
00400                 LOG(L_ERR, "PDT:prefix2domain: new_uri cannot be updated\n");
00401                 return -1;
00402         }
00403         return 1;
00404 }
00405 
00406 /* change the uri according to translation of the prefix */
00407 int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode)
00408 {
00409         struct action act;
00410         struct run_act_ctx ra_ctx;
00411         if(msg==NULL || d==NULL)
00412         {
00413                 LOG(L_ERR, "PDT:update_new_uri: bad parameters\n");
00414                 return -1;
00415         }
00416 
00417         memset(&act, 0, sizeof(act));
00418         if(mode==0 || (mode==1 && prefix.len>0))
00419         {
00420                 act.type = STRIP_T;
00421                 act.val[0].type = NUMBER_ST;
00422                 if(mode==0)
00423                         act.val[0].u.number = plen + prefix.len;
00424                 else
00425                         act.val[0].u.number = prefix.len;
00426                 act.next = 0;
00427 
00428         init_run_actions_ctx(&ra_ctx);
00429                 if (do_action(&ra_ctx, &act, msg) < 0)
00430                 {
00431                         LOG(L_ERR, "PDT:update_new_uri:Error removing prefix\n");
00432                         return -1;
00433                 }
00434         }
00435 
00436         act.type = SET_HOSTPORT_T;
00437         act.val[0].type = STRING_ST;
00438         act.val[0].u.string = d->s;
00439         act.next = 0;
00440 
00441         init_run_actions_ctx(&ra_ctx);
00442         if (do_action(&ra_ctx, &act, msg) < 0)
00443         {
00444                 LOG(L_ERR, "PDT:update_new_uri:Error changing domain\n");
00445                 return -1;
00446         }
00447 
00448         DBG("PDT: update_new_uri: len=%d uri=%.*s\n", msg->new_uri.len,
00449                         msg->new_uri.len, msg->new_uri.s);
00450 
00451         return 0;
00452 }
00453 
00454 int pdt_load_db()
00455 {
00456         db_res_t* res = NULL;
00457         db_rec_t* rec;
00458 
00459         if (db_exec(&res, db_load) < 0) {
00460                 ERR("pdt: Error while loading data from database\n");
00461                 return -1;
00462         }
00463         if (res == NULL) return 0;
00464 
00465         for(rec = db_first(res); rec; rec = db_next(res)) {
00466                 if (rec->fld[0].flags & DB_NULL ||
00467                         rec->fld[1].flags & DB_NULL) {
00468                         INFO("pdt: Record with NULL value(s) found in database, skipping\n");
00469                         continue;
00470                 }
00471 
00472                 if (pdt_check_pd(_dhash, &rec->fld[0].v.lstr, 
00473                                                  &rec->fld[1].v.lstr) != 0) {
00474                         ERR("pdt: Prefix [%.*s] or domain <%.*s> duplicated\n",
00475                                 STR_FMT(&rec->fld[0].v.lstr), 
00476                                 STR_FMT(&rec->fld[1].v.lstr));
00477                         goto error;
00478                 }
00479                 
00480                 if (pdt_add_to_tree(_ptree, &rec->fld[0].v.lstr, 
00481                                                         &rec->fld[1].v.lstr) != 0) {
00482                         ERR("pdt: Error adding info in tree\n");
00483                         goto error;
00484                 }
00485                 
00486                 if(pdt_add_to_hash(_dhash, &rec->fld[0].v.lstr, 
00487                                                    &rec->fld[1].v.lstr) != 0) {
00488                         ERR("pdt: Error adding info in hash\n");
00489                         goto error;
00490                 }
00491         }
00492 
00493         db_res_free(res);
00494         return 0;
00495 
00496 error:
00497         if (res) db_res_free(res);
00498         return -1;
00499 }
00500 
00501 
00502 int pdt_sync_cache()
00503 {
00504         pd_op_t *ito;
00505 
00506         DBG("PDT:pdt_sync_cache: ...\n");
00507 
00508         if(_dhash==NULL || _ptree==NULL)
00509         {
00510                 LOG(L_ERR, "PDT:pdt_sync_cache: strange situation\n");
00511                 return -1;
00512         }
00513 
00514         lock_get(&_dhash->diff_lock);
00515 
00516         if(_ptree->idsync >= _dhash->max_id)
00517                 goto done;
00518 
00519         ito = _dhash->diff;
00520 
00521         while(ito!=NULL && _ptree->idsync >= ito->id)
00522                 ito = ito->n;
00523 
00524         while(ito!=NULL)
00525         {
00526                 DBG("PDT:pdt_sync_cache: sync op[%d]=%d...\n",
00527                                 ito->id, ito->op);
00528                 switch(ito->op)
00529                 {
00530                         case PDT_ADD:
00531                                 if(pdt_add_to_tree(_ptree, &ito->cell->prefix,
00532                                                         &ito->cell->domain)!=0)
00533                                 {
00534                                         LOG(L_ERR, "PDT:pdt_sync_cache: Error to insert in tree\n");
00535                                         goto error;
00536                                 }
00537                                 break;
00538                         case PDT_DELETE:
00539                                 if(pdt_remove_from_tree(_ptree, &ito->cell->prefix)!=0)
00540                                 {
00541                                         LOG(L_ERR,
00542                                                 "PDT:pdt_sync_cache: Error to remove from tree\n");
00543                                         goto error;
00544                                 }
00545                                 break;
00546                         default:
00547                                 LOG(L_ERR, "PDT:pdt_sync_cache: unknown operation\n");
00548                 }
00549                 _ptree->idsync = ito->id;
00550                 ito->count++;
00551                 ito = ito->n;
00552         }
00553 
00554 done:
00555         lock_release(&_dhash->diff_lock);
00556         return 0;
00557 error:
00558         lock_release(&_dhash->diff_lock);
00559         return -1;
00560 }
00561 
00562 void pdt_clean_cache(unsigned int ticks, void *param)
00563 {
00564         pd_op_t *ito, *tmp;
00565 
00566         /* DBG("PDT:pdt_clean_cache: ...\n"); */
00567 
00568         if(_dhash==NULL)
00569         {
00570                 LOG(L_ERR, "PDT:pdt_clean_cache: strange situation\n");
00571                 return;
00572         }
00573 
00574         lock_get(&_dhash->diff_lock);
00575 
00576         ito = _dhash->diff;
00577 
00578         while(ito!=NULL)
00579         {
00580                 if(ito->count >= _dhash->workers)
00581                 {
00582                         DBG("PDT:pdt_clean_cache: cleaning op[%d]=%d...\n",
00583                                         ito->id, ito->op);
00584                         free_cell(ito->cell);
00585                         if(ito->p!=NULL)
00586                                 (ito->p)->n = ito->n;
00587                         else
00588                                 _dhash->diff = ito->n;
00589                         if(ito->n!=NULL)
00590                                 (ito->n)->p = ito->p;
00591                         tmp = ito;
00592                         ito = ito->n;
00593                         shm_free(tmp);
00594                 } else
00595                         ito = ito->n;
00596         }
00597 
00598         lock_release(&_dhash->diff_lock);
00599         return;
00600 }
00601 
00602 
00603 
00604 static const char* rpc_add_doc[2] = {
00605         "Add new prefix/domain translation rule.",
00606         0
00607 };
00608 
00609 static void rpc_add(rpc_t* rpc, void* c)
00610 {
00611         pd_t* cell;
00612         pd_op_t *ito, *tmp;
00613         str sd, sp;
00614         char* t;
00615 
00616         if(_dhash==NULL) {
00617                 LOG(L_ERR, "PDT:pdt_fifo_add: strange situation\n");
00618                 rpc->fault(c, 500, "Server Error");
00619                 return;
00620         }
00621 
00622              /* Use 's' to make sure strings are zero terminated */
00623         if (rpc->scan(c, "ss", &sp.s, &sd.s) < 2) {
00624                 rpc->fault(c, 400, "Invalid Parameter Value");
00625                 return;
00626         }
00627         sp.len = strlen(sp.s);
00628         sd.len = strlen(sd.s);
00629 
00630         t = sp.s;
00631         while(t!=NULL && *t!='\0') {
00632                 if(*t < '0' || *t > '9') {
00633                         LOG(L_ERR, "PDT:pdt_fifo_add: bad prefix [%s]\n", sp.s);
00634                         rpc->fault(c, 400, "Bad Prefix");
00635                         return;
00636                 }
00637                 t++;
00638         }
00639 
00640         if(pdt_check_pd(_dhash, &sp, &sd)!=0) {
00641                 LOG(L_ERR, "PDT:pdt_fifo_add: prefix or domain exists\n");
00642                 rpc->fault(c, 400, "Prefix Or Domain Exists");
00643                 return;
00644         }
00645 
00646         db_insert->vals[0].v.lstr = sp;
00647         db_insert->vals[1].v.lstr = sd;
00648 
00649         DBG("PDT:pdt_fifo_add: [%.*s] <%.*s>\n", STR_FMT(&sp), STR_FMT(&sd));
00650 
00651              /* insert a new domain into database */
00652         if (db_exec(NULL, db_insert) < 0) {
00653                 LOG(L_ERR, "PDT:pdt_fifo_add: error storing new prefix/domain\n");
00654                 rpc->fault(c, 430, "Cannot Store Prefix/domain");
00655                 return;
00656         }
00657         
00658              /* insert the new domain into hashtables, too */
00659         cell = new_cell(&sp, &sd);
00660         if(cell==NULL) {
00661                 LOG(L_ERR, "PDT:pdt_fifo_add: no more shm\n");
00662                 rpc->fault(c, 431, "Out Of Shared Memory");
00663                 goto error1;
00664         }
00665         tmp = new_pd_op(cell, 0, PDT_ADD);
00666         if(tmp==NULL) {
00667                 LOG(L_ERR, "PDT:pdt_fifo_add: no more shm!\n");
00668                 rpc->fault(c, 431, "Out Of Shared Memory");
00669                 goto error2;
00670         }
00671 
00672         lock_get(&_dhash->diff_lock);
00673 
00674         if(pdt_add_to_hash(_dhash, &sp, &sd)!=0) {
00675                 LOG(L_ERR, "PDT:pdt_fifo_add: could not add to cache\n");
00676                 rpc->fault(c, 431, "Could Not Add To Cache");
00677                 goto error3;
00678         }
00679 
00680         _dhash->max_id++;
00681         tmp->id = _dhash->max_id;
00682         if(_dhash->diff==NULL) {
00683                 _dhash->diff = tmp;
00684                 goto done;
00685         }
00686         ito = _dhash->diff;
00687         while(ito->n!=NULL)
00688                 ito = ito->n;
00689 
00690         ito->n = tmp;
00691         tmp->p = ito;
00692 
00693  done:
00694         DBG("PDT:pdt_fifo_add: op[%d]=%d...\n", tmp->id, tmp->op);
00695         lock_release(&_dhash->diff_lock);
00696         return;
00697 
00698  error3:
00699         lock_release(&_dhash->diff_lock);
00700         free_pd_op(tmp);
00701  error2:
00702         free_cell(cell);
00703  error1:
00704 
00705         db_delete->vals[0].v.lstr = sp;
00706         db_delete->vals[1].v.lstr = sd;
00707         if (db_exec(NULL, db_delete) < 0) {
00708                 LOG(L_ERR,"PDT:pdt_fifo_add: database/cache are inconsistent\n");
00709         }
00710 }
00711 
00712 
00713 
00714 static const char* rpc_delete_doc[2] = {
00715         "Delete prefix/domain translation rule.",
00716         0
00717 };
00718 
00719 static void rpc_delete(rpc_t* rpc, void* c)
00720 {
00721         str sd;
00722         unsigned int dhash;
00723         int hash_entry;
00724         pd_t *it;
00725         pd_op_t *ito, *tmp;
00726 
00727         if(_dhash==NULL) {
00728                 LOG(L_ERR, "PDT:pdt_fifo_delete: strange situation\n");
00729                 rpc->fault(c, 500, "Server Error");
00730                 return;
00731         }
00732 
00733              /* Use s to make sure the string is zero terminated */
00734         if (rpc->scan(c, "s", &sd.s) < 1) {
00735                 rpc->fault(c, 400, "Parameter Missing");
00736                 return;
00737         }
00738         sd.len = strlen(sd.s);
00739 
00740         if(*sd.s=='\0') {
00741                 LOG(L_INFO, "PDT:pdt_fifo_delete: empty domain\n");
00742                 rpc->fault(c, 400, "Empty Parameter");
00743                 return;
00744         }
00745 
00746         dhash = pdt_compute_hash(sd.s);
00747         hash_entry = get_hash_entry(dhash, _dhash->hash_size);
00748 
00749         lock_get(&_dhash->diff_lock);
00750 
00751         lock_get(&_dhash->dhash[hash_entry].lock);
00752 
00753         it = _dhash->dhash[hash_entry].e;
00754         while(it!=NULL && it->dhash<=dhash) {
00755                 if(it->dhash==dhash && it->domain.len==sd.len
00756                    && strncasecmp(it->domain.s, sd.s, sd.len)==0)
00757                         break;
00758                 it = it->n;
00759         }
00760 
00761         if(it!=NULL) {
00762                 if(it->p!=NULL)
00763                         (it->p)->n = it->n;
00764                 else
00765                         _dhash->dhash[hash_entry].e = it->n;
00766                 if(it->n)
00767                         (it->n)->p = it->p;
00768         }
00769         lock_release(&_dhash->dhash[hash_entry].lock);
00770 
00771         if(it!=NULL) {
00772                 tmp = new_pd_op(it, 0, PDT_DELETE);
00773                 if(tmp==NULL) {
00774                         LOG(L_ERR, "PDT:pdt_fifo_delete: no more shm!\n");
00775                         rpc->fault(c, 431, "No Shared Memory Left");
00776                         lock_release(&_dhash->diff_lock);
00777                         return;
00778                 }
00779 
00780                 _dhash->max_id++;
00781                 tmp->id = _dhash->max_id;
00782                 if(_dhash->diff==NULL) {
00783                         _dhash->diff = tmp;
00784                         DBG("PDT:pdt_fifo_delete: op[%d]=%d...\n", tmp->id, tmp->op);
00785                         goto done;
00786                 }
00787                 ito = _dhash->diff;
00788                 while(ito->n!=NULL)
00789                         ito = ito->n;
00790 
00791                 ito->n = tmp;
00792                 tmp->p = ito;
00793                 DBG("PDT:pdt_fifo_delete: op[%d]=%d...\n", tmp->id, tmp->op);
00794                 dhash = 1;
00795         } else {
00796                 dhash = 0;
00797         }
00798 
00799  done:
00800         lock_release(&_dhash->diff_lock);
00801         if(dhash==0) {
00802                 DBG("PDT:pdt_fifo_delete: prefix for domain [%s] not found\n", sd.s);
00803                 rpc->fault(c, 404, "Domain Not Found");
00804         } else {
00805                 db_del_domain->match[0].v.lstr = sd;
00806                 if (db_exec(NULL, db_del_domain) < 0) {
00807                         LOG(L_ERR,"PDT:pdt_fifo_delete: database/cache are inconsistent\n");
00808                         rpc->fault(c, 502, "Database And Cache Are Inconsistent");
00809                 }
00810         }
00811 }
00812 
00813 
00814 
00815 static const char* rpc_list_doc[2] = {
00816         "List existin prefix/domain translation rules",
00817         0
00818 };
00819 
00835 static void rpc_list(rpc_t* rpc, void* c)
00836 {
00837         str sd, sp;
00838         pd_t *it;
00839         int i;
00840         char* buf1, *buf2, *t;
00841 
00842         if(_dhash==NULL) {
00843                 LOG(L_ERR, "PDT:pdt_fifo_list: strange situation\n");
00844                 rpc->fault(c, 500, "Server Error");
00845                 return;
00846         }
00847 
00848         if (rpc->scan(c, "ss", &sp.s, &sd.s) < 2) {
00849                 rpc->fault(c, 400, "Invalid parameter value");
00850                 return;
00851         }
00852         sp.len = strlen(sp.s);
00853         sd.len = strlen(sd.s);
00854 
00855         t = sp.s;
00856         if(*t!='\0' && *t!='.') {
00857                 while(t!=NULL && *t!='\0') {
00858                         if(*t < '0' || *t > '9') {
00859                                 LOG(L_ERR, "PDT:pdt_fifo_add: bad prefix [%s]\n", sp.s);
00860                                 rpc->fault(c, 400, "Bad Prefix");
00861                                 return;
00862                         }
00863                         t++;
00864                 }
00865         } else {
00866                 sp.s   = NULL;
00867                 sp.len = 0;
00868         }
00869 
00870         if(*sd.s=='\0' || *sd.s=='.') {
00871                 sd.s   = NULL;
00872                 sd.len = 0;
00873         }
00874 
00875         lock_get(&_dhash->diff_lock);
00876 
00877         for(i=0; i<_dhash->hash_size; i++) {
00878                 lock_get(&_dhash->dhash[i].lock);
00879 
00880                 it = _dhash->dhash[i].e;
00881                 for (it = _dhash->dhash[i].e; it; it = it->n) {
00882                         if((sp.s==NULL && sd.s==NULL)
00883                            || (sp.s!=NULL && it->prefix.len>=sp.len &&
00884                                strncmp(it->prefix.s, sp.s, sp.len)==0)
00885                            || (sd.s!=NULL && it->domain.len>=sd.len &&
00886                                strncasecmp(it->domain.s, sd.s, sd.len)==0)) {
00887 
00888                                 buf1 = pkg_malloc(it->prefix.len + 1);
00889                                 if (!buf1) continue;
00890                                 memcpy(buf1, it->prefix.s, it->prefix.len);
00891                                 buf1[it->prefix.len] = '\0';
00892 
00893                                 buf2 = pkg_malloc(it->domain.len + 1);
00894                                 if (!buf2) {
00895                                         pkg_free(buf1);
00896                                         continue;
00897                                 }
00898                                 memcpy(buf2, it->domain.s, it->domain.len);
00899                                 buf2[it->domain.len] = '\0';
00900 
00901                                 rpc->add(c, "ss", buf1, buf2);
00902                                 pkg_free(buf1);
00903                                 pkg_free(buf2);
00904                         }
00905                 }
00906 
00907                 lock_release(&_dhash->dhash[i].lock);
00908         }
00909 
00910         lock_release(&_dhash->diff_lock);
00911 }
00912 
00913 
00914 static rpc_export_t pdt_rpc[] = {
00915         {"pdt.add",    rpc_add,    rpc_add_doc,    0},
00916         {"pdt.delete", rpc_delete, rpc_delete_doc, 0},
00917         {"pdt.list",   rpc_list,   rpc_list_doc,   RET_ARRAY},
00918         {0, 0, 0, 0}
00919 };