00001
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include <sys/types.h>
00027 #include <sys/ipc.h>
00028 #include <unistd.h>
00029 #include <fcntl.h>
00030
00031 #include "../../sr_module.h"
00032 #include "../../timer.h"
00033 #include "../../route.h"
00034 #include "../../dprint.h"
00035 #include "../../ut.h"
00036 #include "../../rpc.h"
00037 #include "../../rpc_lookup.h"
00038 #include "../../lib/kmi/mi.h"
00039 #include "../../lib/kcore/faked_msg.h"
00040
00041 #include "../../pvar.h"
00042 #include "ht_api.h"
00043 #include "ht_db.h"
00044 #include "ht_var.h"
00045 #include "api.h"
00046
00047
00048 MODULE_VERSION
00049
00050 int ht_timer_interval = 20;
00051 int ht_db_expires_flag = 0;
00052
00053 static int htable_init_rpc(void);
00054
00056 static int ht_print(struct sip_msg*, char*, char*);
00057 static int mod_init(void);
00058 static int child_init(int rank);
00059 static void destroy(void);
00060
00061 static int fixup_ht_rm(void** param, int param_no);
00062 static int ht_rm_name_re(struct sip_msg* msg, char* key, char* foo);
00063 static int ht_rm_value_re(struct sip_msg* msg, char* key, char* foo);
00064
00065 int ht_param(modparam_t type, void* val);
00066
00067 static struct mi_root* ht_mi_reload(struct mi_root* cmd_tree, void* param);
00068 static struct mi_root* ht_mi_dump(struct mi_root* cmd_tree, void* param);
00069 static struct mi_root* ht_mi_delete(struct mi_root* cmd_tree, void* param);
00070
00071 static pv_export_t mod_pvs[] = {
00072 { {"sht", sizeof("sht")-1}, PVT_OTHER, pv_get_ht_cell, pv_set_ht_cell,
00073 pv_parse_ht_name, 0, 0, 0 },
00074 { {"shtex", sizeof("shtex")-1}, PVT_OTHER, pv_get_ht_cell_expire,
00075 pv_set_ht_cell_expire,
00076 pv_parse_ht_name, 0, 0, 0 },
00077 { {"shtcn", sizeof("shtcn")-1}, PVT_OTHER, pv_get_ht_cn, 0,
00078 pv_parse_ht_name, 0, 0, 0 },
00079 { {"shtcv", sizeof("shtcv")-1}, PVT_OTHER, pv_get_ht_cv, 0,
00080 pv_parse_ht_name, 0, 0, 0 },
00081 { {"shtinc", sizeof("shtinc")-1}, PVT_OTHER, pv_get_ht_inc, 0,
00082 pv_parse_ht_name, 0, 0, 0 },
00083 { {"shtdec", sizeof("shtdec")-1}, PVT_OTHER, pv_get_ht_dec, 0,
00084 pv_parse_ht_name, 0, 0, 0 },
00085 { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00086 };
00087
00088 static mi_export_t mi_cmds[] = {
00089 { "sht_reload", ht_mi_reload, 0, 0, 0},
00090 { "sht_dump", ht_mi_dump, 0, 0, 0},
00091 { "sht_delete", ht_mi_delete, 0, 0, 0},
00092 { 0, 0, 0, 0, 0}
00093 };
00094
00095
00096 static cmd_export_t cmds[]={
00097 {"sht_print", (cmd_function)ht_print, 0, 0, 0,
00098 ANY_ROUTE},
00099 {"sht_rm_name_re", (cmd_function)ht_rm_name_re, 1, fixup_ht_rm, 0,
00100 ANY_ROUTE},
00101 {"sht_rm_value_re", (cmd_function)ht_rm_value_re, 1, fixup_ht_rm, 0,
00102 ANY_ROUTE},
00103 {"bind_htable", (cmd_function)bind_htable, 0, 0, 0,
00104 ANY_ROUTE},
00105 {0,0,0,0,0,0}
00106 };
00107
00108 static param_export_t params[]={
00109 {"htable", STR_PARAM|USE_FUNC_PARAM, (void*)ht_param},
00110 {"db_url", STR_PARAM, &ht_db_url.s},
00111 {"key_name_column", STR_PARAM, &ht_db_name_column.s},
00112 {"key_type_column", STR_PARAM, &ht_db_ktype_column.s},
00113 {"value_type_column", STR_PARAM, &ht_db_vtype_column.s},
00114 {"key_value_column", STR_PARAM, &ht_db_value_column.s},
00115 {"expires_column", STR_PARAM, &ht_db_expires_column.s},
00116 {"array_size_suffix", STR_PARAM, &ht_array_size_suffix.s},
00117 {"fetch_rows", INT_PARAM, &ht_fetch_rows},
00118 {"timer_interval", INT_PARAM, &ht_timer_interval},
00119 {"db_expires", INT_PARAM, &ht_db_expires_flag},
00120 {0,0,0}
00121 };
00122
00123
00125 struct module_exports exports= {
00126 "htable",
00127 DEFAULT_DLFLAGS,
00128 cmds,
00129 params,
00130 0,
00131 mi_cmds,
00132 mod_pvs,
00133 0,
00134 mod_init,
00135 0,
00136 (destroy_function) destroy,
00137 child_init
00138 };
00139
00143 static int mod_init(void)
00144 {
00145 if(register_mi_mod(exports.name, mi_cmds)!=0)
00146 {
00147 LM_ERR("failed to register MI commands\n");
00148 return -1;
00149 }
00150 if(htable_init_rpc()!=0)
00151 {
00152 LM_ERR("failed to register RPC commands\n");
00153 return -1;
00154 }
00155
00156 if(ht_init_tables()!=0)
00157 return -1;
00158 ht_db_init_params();
00159
00160 if(ht_db_url.len>0)
00161 {
00162 if(ht_db_init_con()!=0)
00163 return -1;
00164 if(ht_db_open_con()!=0)
00165 return -1;
00166 if(ht_db_load_tables()!=0)
00167 {
00168 ht_db_close_con();
00169 return -1;
00170 }
00171 ht_db_close_con();
00172 }
00173 if(ht_has_autoexpire())
00174 {
00175 LM_DBG("starting auto-expire timer\n");
00176 if(ht_timer_interval<=0)
00177 ht_timer_interval = 20;
00178 if(register_timer(ht_timer, 0, ht_timer_interval)<0)
00179 {
00180 LM_ERR("failed to register timer function\n");
00181 return -1;
00182 }
00183 }
00184 return 0;
00185 }
00186
00187
00188 static int child_init(int rank)
00189 {
00190 struct sip_msg *fmsg;
00191 struct run_act_ctx ctx;
00192 int rtb, rt;
00193
00194 LM_DBG("rank is (%d)\n", rank);
00195 if (rank!=PROC_INIT)
00196 return 0;
00197
00198 rt = route_get(&event_rt, "htable:mod-init");
00199 if(rt>=0 && event_rt.rlist[rt]!=NULL) {
00200 LM_DBG("executing event_route[htable:mod-init] (%d)\n", rt);
00201 if(faked_msg_init()<0)
00202 return -1;
00203 fmsg = faked_msg_next();
00204 rtb = get_route_type();
00205 set_route_type(REQUEST_ROUTE);
00206 init_run_actions_ctx(&ctx);
00207 run_top_route(event_rt.rlist[rt], fmsg, &ctx);
00208 if(ctx.run_flags&DROP_R_F)
00209 {
00210 LM_ERR("exit due to 'drop' in event route\n");
00211 return -1;
00212 }
00213 set_route_type(rtb);
00214 }
00215
00216 return 0;
00217 }
00218
00222 static void destroy(void)
00223 {
00224
00225 if(ht_db_url.len>0)
00226 {
00227 if(ht_db_init_con()==0)
00228 {
00229 if(ht_db_open_con()==0)
00230 {
00231 ht_db_sync_tables();
00232 ht_db_close_con();
00233 }
00234 }
00235 }
00236 ht_destroy();
00237 }
00238
00242 static int ht_print(struct sip_msg *msg, char *s1, char *s2)
00243 {
00244 ht_dbg();
00245 return 1;
00246 }
00247
00248 static int fixup_ht_rm(void** param, int param_no)
00249 {
00250 pv_spec_t *sp;
00251 str s;
00252
00253 sp = (pv_spec_t*)pkg_malloc(sizeof(pv_spec_t));
00254 if(param_no != 1)
00255 {
00256 LM_ERR("invalid parameter number %d\n", param_no);
00257 return -1;
00258 }
00259 if (sp == 0)
00260 {
00261 LM_ERR("no pkg memory left\n");
00262 return -1;
00263 }
00264 memset(sp, 0, sizeof(pv_spec_t));
00265 s.s = (char*)*param; s.len = strlen(s.s);
00266 if(pv_parse_ht_name(sp, &s)<0)
00267 {
00268 pkg_free(sp);
00269 LM_ERR("invalid parameter %d\n", param_no);
00270 return -1;
00271 }
00272 *param = (void*)sp;
00273 return 0;
00274 }
00275
00276 static int ht_rm_name_re(struct sip_msg* msg, char* key, char* foo)
00277 {
00278 ht_pv_t *hpv;
00279 str sre;
00280 pv_spec_t *sp;
00281 sp = (pv_spec_t*)key;
00282
00283 hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
00284
00285 if(hpv->ht==NULL)
00286 {
00287 hpv->ht = ht_get_table(&hpv->htname);
00288 if(hpv->ht==NULL)
00289 return 1;
00290 }
00291 if(pv_printf_s(msg, hpv->pve, &sre)!=0)
00292 {
00293 LM_ERR("cannot get $ht expression\n");
00294 return -1;
00295 }
00296 if(ht_rm_cell_re(&sre, hpv->ht, 0)<0)
00297 return -1;
00298 return 1;
00299 }
00300
00301 static int ht_rm_value_re(struct sip_msg* msg, char* key, char* foo)
00302 {
00303 ht_pv_t *hpv;
00304 str sre;
00305 pv_spec_t *sp;
00306 sp = (pv_spec_t*)key;
00307
00308 hpv = (ht_pv_t*)sp->pvp.pvn.u.dname;
00309
00310 if(hpv->ht==NULL)
00311 {
00312 hpv->ht = ht_get_table(&hpv->htname);
00313 if(hpv->ht==NULL)
00314 return 1;
00315 }
00316 if(pv_printf_s(msg, hpv->pve, &sre)!=0)
00317 {
00318 LM_ERR("cannot get $ht expression\n");
00319 return -1;
00320 }
00321
00322 if(ht_rm_cell_re(&sre, hpv->ht, 1)<0)
00323 return -1;
00324 return 1;
00325 }
00326
00327
00328 int ht_param(modparam_t type, void *val)
00329 {
00330 if(val==NULL)
00331 goto error;
00332
00333 return ht_table_spec((char*)val);
00334 error:
00335 return -1;
00336
00337 }
00338
00339 #define MI_ERR_RELOAD "ERROR Reloading data"
00340 #define MI_ERR_RELOAD_LEN (sizeof(MI_ERR_RELOAD)-1)
00341 static struct mi_root* ht_mi_reload(struct mi_root* cmd_tree, void* param)
00342 {
00343 struct mi_node* node;
00344 str htname;
00345 ht_t *ht;
00346 ht_t nht;
00347 ht_cell_t *first;
00348 ht_cell_t *it;
00349 int i;
00350
00351 if(ht_db_url.len<=0)
00352 return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
00353
00354 if(ht_db_init_con()!=0)
00355 return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
00356 if(ht_db_open_con()!=0)
00357 return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
00358
00359 node = cmd_tree->node.kids;
00360 if(node == NULL)
00361 {
00362 ht_db_close_con();
00363 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00364 }
00365 htname = node->value;
00366 if(htname.len<=0 || htname.s==NULL)
00367 {
00368 LM_ERR("bad hash table name\n");
00369 ht_db_close_con();
00370 return init_mi_tree( 500, "bad hash table name", 19);
00371 }
00372 ht = ht_get_table(&htname);
00373 if(ht==NULL || ht->dbtable.len<=0)
00374 {
00375 LM_ERR("bad hash table name\n");
00376 ht_db_close_con();
00377 return init_mi_tree( 500, "no such hash table", 18);
00378 }
00379 memcpy(&nht, ht, sizeof(ht_t));
00380 nht.entries = (ht_entry_t*)shm_malloc(nht.htsize*sizeof(ht_entry_t));
00381 if(nht.entries == NULL)
00382 {
00383 ht_db_close_con();
00384 return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
00385 }
00386 memset(nht.entries, 0, nht.htsize*sizeof(ht_entry_t));
00387
00388 if(ht_db_load_table(&nht, &ht->dbtable, 0)<0)
00389 {
00390 ht_db_close_con();
00391 return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
00392 }
00393
00394
00395 for(i=0; i<nht.htsize; i++)
00396 {
00397 lock_get(&ht->entries[i].lock);
00398 first = ht->entries[i].first;
00399 ht->entries[i].first = nht.entries[i].first;
00400 ht->entries[i].esize = nht.entries[i].esize;
00401 lock_release(&ht->entries[i].lock);
00402 nht.entries[i].first = first;
00403 }
00404
00405 for(i=0; i<nht.htsize; i++)
00406 {
00407 first = nht.entries[i].first;
00408 while(first)
00409 {
00410 it = first;
00411 first = first->next;
00412 ht_cell_free(it);
00413 }
00414 }
00415 ht_db_close_con();
00416 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00417 }
00418
00419 static struct mi_root* ht_mi_delete(struct mi_root* cmd_tree, void* param) {
00420 struct mi_node *node;
00421 str *htname, *key;
00422 ht_t *ht;
00423
00424 node = cmd_tree->node.kids;
00425 if (!node)
00426 goto param_err;
00427
00428 htname = &node->value;
00429 if (!htname->len)
00430 goto param_err;
00431
00432 node = node->next;
00433 if (!node)
00434 goto param_err;
00435
00436 key = &node->value;
00437 if (!key->len)
00438 goto param_err;
00439
00440 ht = ht_get_table(htname);
00441 if (!ht)
00442 return init_mi_tree(404, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00443
00444 ht_del_cell(ht, key);
00445
00446 return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00447
00448 param_err:
00449 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00450 }
00451
00452 static struct mi_root* ht_mi_dump(struct mi_root* cmd_tree, void* param)
00453 {
00454 struct mi_node* node;
00455 struct mi_node* node2;
00456 struct mi_root *rpl_tree;
00457 struct mi_node *rpl;
00458 str htname;
00459 ht_t *ht;
00460 ht_cell_t *it;
00461 int i;
00462 int len;
00463 char *p;
00464
00465 node = cmd_tree->node.kids;
00466 if(node == NULL)
00467 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00468 htname = node->value;
00469 if(htname.len<=0 || htname.s==NULL)
00470 {
00471 LM_ERR("bad hash table name\n");
00472 return init_mi_tree( 500, "bad hash table name", 19);
00473 }
00474 ht = ht_get_table(&htname);
00475 if(ht==NULL)
00476 {
00477 LM_ERR("bad hash table name\n");
00478 return init_mi_tree( 500, "no such hash table", 18);
00479 }
00480
00481 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00482 if (rpl_tree==NULL)
00483 return 0;
00484 rpl = &rpl_tree->node;
00485
00486 for(i=0; i<ht->htsize; i++)
00487 {
00488 lock_get(&ht->entries[i].lock);
00489 it = ht->entries[i].first;
00490 if(it)
00491 {
00492
00493 p = int2str((unsigned long)i, &len);
00494 node = add_mi_node_child(rpl, MI_DUP_VALUE, "Entry", 5, p, len);
00495 if (node==0)
00496 goto error;
00497 while(it)
00498 {
00499 if(it->flags&AVP_VAL_STR) {
00500 node2 = add_mi_node_child(node, MI_DUP_VALUE, it->name.s, it->name.len,
00501 it->value.s.s, it->value.s.len);
00502 } else {
00503 p = sint2str((long)it->value.n, &len);
00504 node2 = add_mi_node_child(node, MI_DUP_VALUE, it->name.s, it->name.len,
00505 p, len);
00506 }
00507 if (node2==0)
00508 goto error;
00509 it = it->next;
00510 }
00511 }
00512 lock_release(&ht->entries[i].lock);
00513 }
00514
00515 return rpl_tree;
00516 error:
00517 free_mi_tree(rpl_tree);
00518 return 0;
00519 }
00520
00521 static const char* htable_dump_doc[2] = {
00522 "Dump the contents of hash table.",
00523 0
00524 };
00525 static const char* htable_delete_doc[2] = {
00526 "Delete one key from a hash table.",
00527 0
00528 };
00529
00530 static void htable_rpc_delete(rpc_t* rpc, void* c) {
00531 str htname, keyname;
00532 ht_t *ht;
00533
00534 if (rpc->scan(c, "SS", &htname, &keyname) < 2) {
00535 rpc->fault(c, 500, "Not enough parameters (htable name & key name");
00536 return;
00537 }
00538 ht = ht_get_table(&htname);
00539 if (!ht) {
00540 rpc->fault(c, 500, "No such htable");
00541 return;
00542 }
00543
00544 ht_del_cell(ht, &keyname);
00545 }
00546
00547 static void htable_rpc_dump(rpc_t* rpc, void* c)
00548 {
00549 str htname;
00550 ht_t *ht;
00551 ht_cell_t *it;
00552 int i;
00553 void* th;
00554 void* ih;
00555 void* vh;
00556
00557 if (rpc->scan(c, "S", &htname) < 1)
00558 {
00559 rpc->fault(c, 500, "No htable name given");
00560 return;
00561 }
00562 ht = ht_get_table(&htname);
00563 if(ht==NULL)
00564 {
00565 rpc->fault(c, 500, "No such htable");
00566 return;
00567 }
00568 for(i=0; i<ht->htsize; i++)
00569 {
00570 lock_get(&ht->entries[i].lock);
00571 it = ht->entries[i].first;
00572 if(it)
00573 {
00574
00575 if (rpc->add(c, "{", &th) < 0)
00576 {
00577 rpc->fault(c, 500, "Internal error creating rpc");
00578 goto error;
00579 }
00580 if(rpc->struct_add(th, "dd{",
00581 "entry", i,
00582 "size", (int)ht->entries[i].esize,
00583 "slot", &ih)<0)
00584 {
00585 rpc->fault(c, 500, "Internal error creating rpc");
00586 goto error;
00587 }
00588 while(it)
00589 {
00590 if(rpc->struct_add(ih, "{",
00591 "item", &vh)<0)
00592 {
00593 rpc->fault(c, 500, "Internal error creating rpc");
00594 goto error;
00595 }
00596 if(it->flags&AVP_VAL_STR) {
00597 if(rpc->struct_add(vh, "SS",
00598 "name", &it->name.s,
00599 "value", &it->value.s)<0)
00600 {
00601 rpc->fault(c, 500, "Internal error adding item");
00602 goto error;
00603 }
00604 } else {
00605 if(rpc->struct_add(vh, "Sd",
00606 "name", &it->name.s,
00607 "value", (int)it->value.n))
00608 {
00609 rpc->fault(c, 500, "Internal error adding item");
00610 goto error;
00611 }
00612 }
00613 it = it->next;
00614 }
00615 }
00616 lock_release(&ht->entries[i].lock);
00617 }
00618
00619 return;
00620
00621 error:
00622 lock_release(&ht->entries[i].lock);
00623 }
00624
00625 rpc_export_t htable_rpc[] = {
00626 {"htable.dump", htable_rpc_dump, htable_dump_doc, 0},
00627 {"htable.delete", htable_rpc_delete, htable_delete_doc, 0},
00628 {0, 0, 0, 0}
00629 };
00630
00631 static int htable_init_rpc(void)
00632 {
00633 if (rpc_register_array(htable_rpc)!=0)
00634 {
00635 LM_ERR("failed to register RPC commands\n");
00636 return -1;
00637 }
00638 return 0;
00639 }