ndb_redis_mod.c

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, /* dlopen flags */
00090         cmds,
00091         params,
00092         0,
00093         0,              /* exported MI functions */
00094         mod_pvs,        /* exported pseudo-variables */
00095         0,              /* extra processes */
00096         mod_init,       /* module initialization function */
00097         0,              /* response function */
00098         mod_destroy,    /* destroy function */
00099         child_init      /* per child init function */
00100 };
00101 
00102 
00103 
00107 static int mod_init(void)
00108 {
00109         /* success code */
00110         return 0;
00111 }
00112 
00113 /* each child get a new connection to the database */
00114 static int child_init(int rank)
00115 {
00116         /* skip child init for non-worker process ranks */
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         /* Default pos param initialization. */
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                         /* value */
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                         /* info */
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                         /* size */
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                         /* type */
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                         /* We do nothing. */
00556                         return pv_get_null(msg, param, res);
00557         }
00558 }