00001
00027 #include <stdio.h>
00028 #include <unistd.h>
00029 #include <stdlib.h>
00030 #include <ctype.h>
00031
00032 #include "../../sr_module.h"
00033 #include "../../mem/mem.h"
00034 #include "../../dprint.h"
00035 #include "../../mod_fix.h"
00036 #include "../../trim.h"
00037
00038 #include "redis_client.h"
00039
00040 MODULE_VERSION
00041
00044 int redis_srv_param(modparam_t type, void *val);
00045 static int w_redis_cmd3(struct sip_msg* msg, char* ssrv, char* scmd,
00046 char* sres);
00047 static int w_redis_cmd4(struct sip_msg* msg, char* ssrv, char* scmd,
00048 char *sargv1, char* sres);
00049 static int w_redis_cmd5(struct sip_msg* msg, char* ssrv, char* scmd,
00050 char *sargv1, char *sargv2, char* sres);
00051 static int w_redis_cmd6(struct sip_msg* msg, char* ssrv, char* scmd,
00052 char *sargv1, char *sargv2, char *sargv3, char* sres);
00053 static int fixup_redis_cmd6(void** param, int param_no);
00054
00055 static int mod_init(void);
00056 static void mod_destroy(void);
00057 static int child_init(int rank);
00058
00059 static int pv_get_redisc(struct sip_msg *msg, pv_param_t *param,
00060 pv_value_t *res);
00061 static int pv_parse_redisc_name(pv_spec_p sp, str *in);
00062
00063 static pv_export_t mod_pvs[] = {
00064 { {"redis", sizeof("redis")-1}, PVT_OTHER, pv_get_redisc, 0,
00065 pv_parse_redisc_name, 0, 0, 0 },
00066 { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00067 };
00068
00069
00070 static cmd_export_t cmds[]={
00071 {"redis_cmd", (cmd_function)w_redis_cmd3, 3, fixup_redis_cmd6,
00072 0, ANY_ROUTE},
00073 {"redis_cmd", (cmd_function)w_redis_cmd4, 4, fixup_redis_cmd6,
00074 0, ANY_ROUTE},
00075 {"redis_cmd", (cmd_function)w_redis_cmd5, 5, fixup_redis_cmd6,
00076 0, ANY_ROUTE},
00077 {"redis_cmd", (cmd_function)w_redis_cmd6, 6, fixup_redis_cmd6,
00078 0, ANY_ROUTE},
00079 {0, 0, 0, 0, 0, 0}
00080 };
00081
00082 static param_export_t params[]={
00083 {"server", STR_PARAM|USE_FUNC_PARAM, (void*)redis_srv_param},
00084 {0, 0, 0}
00085 };
00086
00087 struct module_exports exports = {
00088 "ndb_redis",
00089 DEFAULT_DLFLAGS,
00090 cmds,
00091 params,
00092 0,
00093 0,
00094 mod_pvs,
00095 0,
00096 mod_init,
00097 0,
00098 mod_destroy,
00099 child_init
00100 };
00101
00102
00103
00107 static int mod_init(void)
00108 {
00109
00110 return 0;
00111 }
00112
00113
00114 static int child_init(int rank)
00115 {
00116
00117 if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00118 return 0;
00119
00120 if(redisc_init()<0)
00121 {
00122 LM_ERR("failed to initialize redis connections\n");
00123 return -1;
00124 }
00125 return 0;
00126 }
00127
00131 static void mod_destroy(void)
00132 {
00133 LM_DBG("cleaning up\n");
00134 redisc_destroy();
00135 }
00136
00140 static int w_redis_cmd3(struct sip_msg* msg, char* ssrv, char* scmd, char* sres)
00141 {
00142 str s[3];
00143
00144 if(fixup_get_svalue(msg, (gparam_t*)ssrv, &s[0])!=0)
00145 {
00146 LM_ERR("no redis server name\n");
00147 return -1;
00148 }
00149 if(fixup_get_svalue(msg, (gparam_t*)scmd, &s[1])!=0)
00150 {
00151 LM_ERR("no redis command\n");
00152 return -1;
00153 }
00154 if(fixup_get_svalue(msg, (gparam_t*)sres, &s[2])!=0)
00155 {
00156 LM_ERR("no redis reply name\n");
00157 return -1;
00158 }
00159
00160 if(redisc_exec(&s[0], &s[1], NULL, NULL, NULL, &s[2])<0)
00161 return -1;
00162 return 1;
00163 }
00164
00168 static int w_redis_cmd4(struct sip_msg* msg, char* ssrv, char* scmd,
00169 char *sargv1, char* sres)
00170 {
00171 str s[4];
00172
00173 if(fixup_get_svalue(msg, (gparam_t*)ssrv, &s[0])!=0)
00174 {
00175 LM_ERR("no redis server name\n");
00176 return -1;
00177 }
00178 if(fixup_get_svalue(msg, (gparam_t*)scmd, &s[1])!=0)
00179 {
00180 LM_ERR("no redis command\n");
00181 return -1;
00182 }
00183 if(fixup_get_svalue(msg, (gparam_t*)sargv1, &s[2])!=0)
00184 {
00185 LM_ERR("no argument 1\n");
00186 return -1;
00187 }
00188 if(fixup_get_svalue(msg, (gparam_t*)sres, &s[3])!=0)
00189 {
00190 LM_ERR("no redis reply name\n");
00191 return -1;
00192 }
00193
00194 if(redisc_exec(&s[0], &s[1], &s[2], NULL, NULL, &s[3])<0)
00195 return -1;
00196 return 1;
00197 }
00198
00202 static int w_redis_cmd5(struct sip_msg* msg, char* ssrv, char* scmd,
00203 char *sargv1, char *sargv2, char* sres)
00204 {
00205 str s[5];
00206
00207 if(fixup_get_svalue(msg, (gparam_t*)ssrv, &s[0])!=0)
00208 {
00209 LM_ERR("no redis server name\n");
00210 return -1;
00211 }
00212 if(fixup_get_svalue(msg, (gparam_t*)scmd, &s[1])!=0)
00213 {
00214 LM_ERR("no redis command\n");
00215 return -1;
00216 }
00217 if(fixup_get_svalue(msg, (gparam_t*)sargv1, &s[2])!=0)
00218 {
00219 LM_ERR("no argument 1\n");
00220 return -1;
00221 }
00222 if(fixup_get_svalue(msg, (gparam_t*)sargv2, &s[3])!=0)
00223 {
00224 LM_ERR("no argument 2\n");
00225 return -1;
00226 }
00227 if(fixup_get_svalue(msg, (gparam_t*)sres, &s[4])!=0)
00228 {
00229 LM_ERR("no redis reply name\n");
00230 return -1;
00231 }
00232
00233 if(redisc_exec(&s[0], &s[1], &s[2], &s[3], NULL, &s[4])<0)
00234 return -1;
00235 return 1;
00236 }
00237
00241 static int w_redis_cmd6(struct sip_msg* msg, char* ssrv, char* scmd,
00242 char *sargv1, char *sargv2, char *sargv3, char* sres)
00243 {
00244 str s[6];
00245
00246 if(fixup_get_svalue(msg, (gparam_t*)ssrv, &s[0])!=0)
00247 {
00248 LM_ERR("no redis server name\n");
00249 return -1;
00250 }
00251 if(fixup_get_svalue(msg, (gparam_t*)scmd, &s[1])!=0)
00252 {
00253 LM_ERR("no redis command\n");
00254 return -1;
00255 }
00256 if(fixup_get_svalue(msg, (gparam_t*)sargv1, &s[2])!=0)
00257 {
00258 LM_ERR("no argument 1\n");
00259 return -1;
00260 }
00261 if(fixup_get_svalue(msg, (gparam_t*)sargv2, &s[3])!=0)
00262 {
00263 LM_ERR("no argument 2\n");
00264 return -1;
00265 }
00266 if(fixup_get_svalue(msg, (gparam_t*)sargv3, &s[4])!=0)
00267 {
00268 LM_ERR("no argument 3\n");
00269 return -1;
00270 }
00271 if(fixup_get_svalue(msg, (gparam_t*)sres, &s[5])!=0)
00272 {
00273 LM_ERR("no redis reply name\n");
00274 return -1;
00275 }
00276
00277 if(redisc_exec(&s[0], &s[1], &s[2], &s[3], &s[4], &s[5])<0)
00278 return -1;
00279 return 1;
00280 }
00281
00285 static int fixup_redis_cmd6(void** param, int param_no)
00286 {
00287 return fixup_spve_null(param, 1);
00288 }
00289
00290
00294 int redis_srv_param(modparam_t type, void *val)
00295 {
00296 return redisc_add_server((char*)val);
00297 }
00298
00299
00303 int redis_parse_index(str *in, gparam_t *gp)
00304 {
00305 if(in->s[0]==PV_MARKER)
00306 {
00307 gp->type = GPARAM_TYPE_PVS;
00308 gp->v.pvs = (pv_spec_t*)pkg_malloc(sizeof(pv_spec_t));
00309 if (gp->v.pvs == NULL)
00310 {
00311 LM_ERR("no pkg memory left for pv_spec_t\n");
00312 pkg_free(gp);
00313 return -1;
00314 }
00315
00316 if(pv_parse_spec(in, gp->v.pvs)==NULL)
00317 {
00318 LM_ERR("invalid PV identifier\n");
00319 pkg_free(gp->v.pvs);
00320 pkg_free(gp);
00321 return -1;
00322 }
00323 } else {
00324 gp->type = GPARAM_TYPE_INT;
00325 if(str2sint(in, &gp->v.i) != 0)
00326 {
00327 LM_ERR("bad number <%.*s>\n", in->len, in->s);
00328 return -1;
00329 }
00330 }
00331 return 0;
00332 }
00333
00334
00338 int redis_parse_token(str *in, gparam_t *gp, int i)
00339 {
00340 str tok;
00341
00342 while(i<in->len && isspace(in->s[i]))
00343 i++;
00344
00345 if(i>=in->len-2)
00346 return -1;
00347
00348 if(in->s[i++]!='[')
00349 return -1;
00350
00351 while(i<in->len-1 && isspace(in->s[i]))
00352 i++;
00353 if(i==in->len-1 || in->s[i]==']')
00354 return -1;
00355 tok.s = &(in->s[i]);
00356
00357 while(i<in->len && !isspace(in->s[i]) && in->s[i]!=']')
00358 i++;
00359 if(i==in->len)
00360 return -1;
00361 tok.len = &(in->s[i]) - tok.s;
00362 if(redis_parse_index(&tok, gp)!=0)
00363 return -1;
00364
00365 while(i<in->len && isspace(in->s[i]))
00366 i++;
00367 if(i==in->len || in->s[i]!=']')
00368 return -1;
00369
00370 return 0;
00371 }
00372
00376 static int pv_parse_redisc_name(pv_spec_p sp, str *in)
00377 {
00378 redisc_pv_t *rpv=NULL;
00379 str pvs;
00380 int i;
00381
00382 if(in->s==NULL || in->len<=0)
00383 return -1;
00384
00385 rpv = (redisc_pv_t*)pkg_malloc(sizeof(redisc_pv_t));
00386 if(rpv==NULL)
00387 return -1;
00388
00389 memset(rpv, 0, sizeof(redisc_pv_t));
00390
00391 pvs = *in;
00392 trim(&pvs);
00393
00394 rpv->rname.s = pvs.s;
00395 for(i=0; i<pvs.len-2; i++)
00396 {
00397 if(isspace(pvs.s[i]) || pvs.s[i]=='=') {
00398 rpv->rname.len = i;
00399 break;
00400 }
00401 }
00402 rpv->rname.len = i;
00403
00404 if(rpv->rname.len==0)
00405 goto error_var;
00406
00407 while(i<pvs.len-2 && isspace(pvs.s[i]))
00408 i++;
00409
00410 if(pvs.s[i]!='=')
00411 goto error_var;
00412
00413 if(pvs.s[i+1]!='>')
00414 goto error_var;
00415
00416 i += 2;
00417 while(i<pvs.len && isspace(pvs.s[i]))
00418 i++;
00419
00420 if(i>=pvs.len)
00421 goto error_key;
00422
00423 rpv->rkey.s = pvs.s + i;
00424 rpv->rkey.len = pvs.len - i;
00425
00426
00427 rpv->pos.type = GPARAM_TYPE_INT;
00428 rpv->pos.v.i = -1;
00429
00430 if(rpv->rkey.len>=5 && strncmp(rpv->rkey.s, "value", 5)==0) {
00431 rpv->rkeyid = 1;
00432 if(rpv->rkey.len>5)
00433 {
00434 i+=5;
00435 if(redis_parse_token(&pvs, &(rpv->pos), i)!=0)
00436 goto error_key;
00437 }
00438 } else if(rpv->rkey.len>=4 && strncmp(rpv->rkey.s, "type", 4)==0) {
00439 rpv->rkeyid = 0;
00440 if(rpv->rkey.len>4)
00441 {
00442 i+=4;
00443 if(redis_parse_token(&pvs, &(rpv->pos), i)!=0)
00444 goto error_key;
00445 }
00446 } else if(rpv->rkey.len==4 && strncmp(rpv->rkey.s, "info", 4)==0) {
00447 rpv->rkeyid = 2;
00448 } else if(rpv->rkey.len==4 && strncmp(rpv->rkey.s, "size", 4)==0) {
00449 rpv->rkeyid = 3;
00450 } else {
00451 goto error_key;
00452 }
00453
00454 sp->pvp.pvn.u.dname = (void*)rpv;
00455 sp->pvp.pvn.type = PV_NAME_OTHER;
00456 return 0;
00457
00458 error_var:
00459 LM_ERR("invalid var spec [%.*s]\n", in->len, in->s);
00460 pkg_free(rpv);
00461 return -1;
00462
00463 error_key:
00464 LM_ERR("invalid key spec in [%.*s]\n", in->len, in->s);
00465 pkg_free(rpv);
00466 return -1;
00467 }
00468
00472 static int pv_get_redisc(struct sip_msg *msg, pv_param_t *param,
00473 pv_value_t *res)
00474 {
00475 redisc_pv_t *rpv;
00476 str s;
00477 int pos;
00478
00479 rpv = (redisc_pv_t*)param->pvn.u.dname;
00480 if(rpv->reply==NULL)
00481 {
00482 rpv->reply = redisc_get_reply(&rpv->rname);
00483 if(rpv->reply==NULL)
00484 return pv_get_null(msg, param, res);
00485 }
00486
00487 if(rpv->reply->rplRedis==NULL)
00488 return pv_get_null(msg, param, res);
00489
00490
00491 if(fixup_get_ivalue(msg, &rpv->pos, &pos)!=0)
00492 return pv_get_null(msg, param, res);
00493
00494 switch(rpv->rkeyid) {
00495 case 1:
00496
00497 switch(rpv->reply->rplRedis->type) {
00498 case REDIS_REPLY_STRING:
00499 if(pos!=-1)
00500 return pv_get_null(msg, param, res);
00501 s.len = rpv->reply->rplRedis->len;
00502 s.s = rpv->reply->rplRedis->str;
00503 return pv_get_strval(msg, param, res, &s);
00504 case REDIS_REPLY_INTEGER:
00505 if(pos!=-1)
00506 return pv_get_null(msg, param, res);
00507 return pv_get_sintval(msg, param, res,
00508 (int)rpv->reply->rplRedis->integer);
00509 case REDIS_REPLY_ARRAY:
00510 if(pos<0 || pos>=(int)rpv->reply->rplRedis->elements)
00511 return pv_get_null(msg, param, res);
00512 if(rpv->reply->rplRedis->element[pos]==NULL)
00513 return pv_get_null(msg, param, res);
00514 switch(rpv->reply->rplRedis->element[pos]->type) {
00515 case REDIS_REPLY_STRING:
00516 s.len = rpv->reply->rplRedis->element[pos]->len;
00517 s.s = rpv->reply->rplRedis->element[pos]->str;
00518 return pv_get_strval(msg, param, res, &s);
00519 case REDIS_REPLY_INTEGER:
00520 return pv_get_sintval(msg, param, res,
00521 (int)rpv->reply->rplRedis->element[pos]->integer);
00522 default:
00523 return pv_get_null(msg, param, res);
00524 }
00525 default:
00526 return pv_get_null(msg, param, res);
00527 }
00528 case 2:
00529
00530 if(rpv->reply->rplRedis->str==NULL)
00531 return pv_get_null(msg, param, res);
00532 s.len = rpv->reply->rplRedis->len;
00533 s.s = rpv->reply->rplRedis->str;
00534 return pv_get_strval(msg, param, res, &s);
00535 case 3:
00536
00537 if(rpv->reply->rplRedis->type == REDIS_REPLY_ARRAY) {
00538 return pv_get_uintval(msg, param, res, (unsigned int)rpv->reply->rplRedis->elements);
00539 } else {
00540 return pv_get_null(msg, param, res);
00541 }
00542 case 0:
00543
00544 if(pos==-1)
00545 return pv_get_sintval(msg, param, res,
00546 rpv->reply->rplRedis->type);
00547 if(rpv->reply->rplRedis->type != REDIS_REPLY_ARRAY)
00548 return pv_get_null(msg, param, res);
00549 if(pos<0 || pos>=(int)rpv->reply->rplRedis->elements)
00550 return pv_get_null(msg, param, res);
00551 if(rpv->reply->rplRedis->element[pos]==NULL)
00552 return pv_get_null(msg, param, res);
00553 return pv_get_sintval(msg, param, res, rpv->reply->rplRedis->element[pos]->type);
00554 default:
00555
00556 return pv_get_null(msg, param, res);
00557 }
00558 }